2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.server.location;
19 import com.android.internal.app.IAppOpsService;
20 import com.android.internal.app.IBatteryStats;
21 import com.android.internal.location.GpsNetInitiatedHandler;
22 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
23 import com.android.internal.location.ProviderProperties;
24 import com.android.internal.location.ProviderRequest;
26 import android.app.AlarmManager;
27 import android.app.AppOpsManager;
28 import android.app.PendingIntent;
29 import android.content.BroadcastReceiver;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.database.Cursor;
34 import android.hardware.location.GeofenceHardware;
35 import android.hardware.location.GeofenceHardwareImpl;
36 import android.location.Criteria;
37 import android.location.FusedBatchOptions;
38 import android.location.GnssStatus;
39 import android.location.IGnssStatusListener;
40 import android.location.IGnssStatusProvider;
41 import android.location.GnssMeasurementsEvent;
42 import android.location.GnssNavigationMessage;
43 import android.location.IGpsGeofenceHardware;
44 import android.location.ILocationManager;
45 import android.location.INetInitiatedListener;
46 import android.location.Location;
47 import android.location.LocationListener;
48 import android.location.LocationManager;
49 import android.location.LocationProvider;
50 import android.location.LocationRequest;
51 import android.net.ConnectivityManager;
52 import android.net.Network;
53 import android.net.NetworkCapabilities;
54 import android.net.NetworkInfo;
55 import android.net.NetworkRequest;
56 import android.net.Uri;
57 import android.os.AsyncTask;
58 import android.os.BatteryStats;
59 import android.os.Binder;
60 import android.os.Bundle;
61 import android.os.Handler;
62 import android.os.Looper;
63 import android.os.Message;
64 import android.os.PowerManager;
65 import android.os.RemoteException;
66 import android.os.ServiceManager;
67 import android.os.SystemClock;
68 import android.os.SystemProperties;
69 import android.os.UserHandle;
70 import android.os.WorkSource;
71 import android.provider.Settings;
72 import android.provider.Telephony.Carriers;
73 import android.provider.Telephony.Sms.Intents;
74 import android.telephony.SmsMessage;
75 import android.telephony.SubscriptionManager;
76 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
77 import android.telephony.TelephonyManager;
78 import android.telephony.gsm.GsmCellLocation;
79 import android.text.TextUtils;
80 import android.util.Log;
81 import android.util.NtpTrustedTime;
83 import java.io.ByteArrayOutputStream;
85 import java.io.FileDescriptor;
86 import java.io.FileInputStream;
87 import java.io.IOException;
88 import java.io.PrintWriter;
89 import java.io.StringReader;
90 import java.net.InetAddress;
91 import java.net.UnknownHostException;
92 import java.util.Arrays;
93 import java.util.Date;
94 import java.util.Map.Entry;
95 import java.util.Properties;
97 import libcore.io.IoUtils;
100 * A GPS implementation of LocationProvider used by LocationManager.
104 public class GnssLocationProvider implements LocationProviderInterface {
106 private static final String TAG = "GnssLocationProvider";
108 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
109 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
111 private static final ProviderProperties PROPERTIES = new ProviderProperties(
112 true, true, false, false, true, true, true,
113 Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
115 // these need to match GpsPositionMode enum in gps.h
116 private static final int GPS_POSITION_MODE_STANDALONE = 0;
117 private static final int GPS_POSITION_MODE_MS_BASED = 1;
118 private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
120 // these need to match GpsPositionRecurrence enum in gps.h
121 private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
122 private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
124 // these need to match GpsStatusValue defines in gps.h
125 private static final int GPS_STATUS_NONE = 0;
126 private static final int GPS_STATUS_SESSION_BEGIN = 1;
127 private static final int GPS_STATUS_SESSION_END = 2;
128 private static final int GPS_STATUS_ENGINE_ON = 3;
129 private static final int GPS_STATUS_ENGINE_OFF = 4;
131 // these need to match GpsApgsStatusValue defines in gps.h
132 /** AGPS status event values. */
133 private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
134 private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
135 private static final int GPS_AGPS_DATA_CONNECTED = 3;
136 private static final int GPS_AGPS_DATA_CONN_DONE = 4;
137 private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
139 // these need to match GpsLocationFlags enum in gps.h
140 private static final int LOCATION_INVALID = 0;
141 private static final int LOCATION_HAS_LAT_LONG = 1;
142 private static final int LOCATION_HAS_ALTITUDE = 2;
143 private static final int LOCATION_HAS_SPEED = 4;
144 private static final int LOCATION_HAS_BEARING = 8;
145 private static final int LOCATION_HAS_ACCURACY = 16;
147 // IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h
148 private static final int GPS_DELETE_EPHEMERIS = 0x0001;
149 private static final int GPS_DELETE_ALMANAC = 0x0002;
150 private static final int GPS_DELETE_POSITION = 0x0004;
151 private static final int GPS_DELETE_TIME = 0x0008;
152 private static final int GPS_DELETE_IONO = 0x0010;
153 private static final int GPS_DELETE_UTC = 0x0020;
154 private static final int GPS_DELETE_HEALTH = 0x0040;
155 private static final int GPS_DELETE_SVDIR = 0x0080;
156 private static final int GPS_DELETE_SVSTEER = 0x0100;
157 private static final int GPS_DELETE_SADATA = 0x0200;
158 private static final int GPS_DELETE_RTI = 0x0400;
159 private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
160 private static final int GPS_DELETE_ALL = 0xFFFF;
162 // The GPS_CAPABILITY_* flags must match the values in gps.h
163 private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
164 private static final int GPS_CAPABILITY_MSB = 0x0000002;
165 private static final int GPS_CAPABILITY_MSA = 0x0000004;
166 private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
167 private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
168 private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
169 private static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
170 private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
172 // The AGPS SUPL mode
173 private static final int AGPS_SUPL_MODE_MSA = 0x02;
174 private static final int AGPS_SUPL_MODE_MSB = 0x01;
176 // these need to match AGpsType enum in gps.h
177 private static final int AGPS_TYPE_SUPL = 1;
178 private static final int AGPS_TYPE_C2K = 2;
180 // these must match the definitions in gps.h
181 private static final int APN_INVALID = 0;
182 private static final int APN_IPV4 = 1;
183 private static final int APN_IPV6 = 2;
184 private static final int APN_IPV4V6 = 3;
186 // for mAGpsDataConnectionState
187 private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
188 private static final int AGPS_DATA_CONNECTION_OPENING = 1;
189 private static final int AGPS_DATA_CONNECTION_OPEN = 2;
192 private static final int CHECK_LOCATION = 1;
193 private static final int ENABLE = 2;
194 private static final int SET_REQUEST = 3;
195 private static final int UPDATE_NETWORK_STATE = 4;
196 private static final int INJECT_NTP_TIME = 5;
197 private static final int DOWNLOAD_XTRA_DATA = 6;
198 private static final int UPDATE_LOCATION = 7;
199 private static final int ADD_LISTENER = 8;
200 private static final int REMOVE_LISTENER = 9;
201 private static final int INJECT_NTP_TIME_FINISHED = 10;
202 private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
203 private static final int SUBSCRIPTION_OR_SIM_CHANGED = 12;
204 private static final int INITIALIZE_HANDLER = 13;
205 private static final int REQUEST_SUPL_CONNECTION = 14;
206 private static final int RELEASE_SUPL_CONNECTION = 15;
209 private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
210 private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
212 // Request ref location
213 private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1;
214 private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2;
216 // ref. location info
217 private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
218 private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
219 private static final int AGPS_REG_LOCATION_TYPE_MAC = 3;
222 private static final int AGPS_SETID_TYPE_NONE = 0;
223 private static final int AGPS_SETID_TYPE_IMSI = 1;
224 private static final int AGPS_SETID_TYPE_MSISDN = 2;
226 private static final String PROPERTIES_FILE_PREFIX = "/etc/gps";
227 private static final String PROPERTIES_FILE_SUFFIX = ".conf";
228 private static final String DEFAULT_PROPERTIES_FILE = PROPERTIES_FILE_PREFIX + PROPERTIES_FILE_SUFFIX;
230 private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
231 private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
233 // GPS Geofence errors. Should match gps.h constants.
234 private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
235 private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
236 private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101;
237 private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
238 private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
239 private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
242 // Valid TCP/UDP port range is (0, 65535].
243 private static final int TCP_MIN_PORT = 0;
244 private static final int TCP_MAX_PORT = 0xffff;
246 // Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode.
247 private static final int BATTERY_SAVER_MODE_NO_CHANGE = 0;
248 // Value of batterySaverGpsMode such that GPS is disabled when battery saver mode
249 // is enabled and the screen is off.
250 private static final int BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF = 1;
251 // Secure setting for GPS behavior when battery saver mode is on.
252 private static final String BATTERY_SAVER_GPS_MODE = "batterySaverGpsMode";
254 /** simpler wrapper for ProviderRequest + Worksource */
255 private static class GpsRequest {
256 public ProviderRequest request;
257 public WorkSource source;
258 public GpsRequest(ProviderRequest request, WorkSource source) {
259 this.request = request;
260 this.source = source;
264 private Object mLock = new Object();
266 private int mLocationFlags = LOCATION_INVALID;
269 private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
271 // time for last status update
272 private long mStatusUpdateTime = SystemClock.elapsedRealtime();
274 // turn off GPS fix icon if we haven't received a fix in 10 seconds
275 private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
277 // stop trying if we do not receive a fix within 60 seconds
278 private static final int NO_FIX_TIMEOUT = 60 * 1000;
280 // if the fix interval is below this we leave GPS on,
281 // if above then we cycle the GPS driver.
282 // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane.
283 private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000;
285 // how often to request NTP time, in milliseconds
286 // current setting 24 hours
287 private static final long NTP_INTERVAL = 24*60*60*1000;
288 // how long to wait if we have a network error in NTP or XTRA downloading
289 // the initial value of the exponential backoff
290 // current setting - 5 minutes
291 private static final long RETRY_INTERVAL = 5*60*1000;
292 // how long to wait if we have a network error in NTP or XTRA downloading
293 // the max value of the exponential backoff
294 // current setting - 4 hours
295 private static final long MAX_RETRY_INTERVAL = 4*60*60*1000;
297 private BackOff mNtpBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
298 private BackOff mXtraBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
300 // true if we are enabled, protected by this
301 private boolean mEnabled;
303 // states for injecting ntp and downloading xtra data
304 private static final int STATE_PENDING_NETWORK = 0;
305 private static final int STATE_DOWNLOADING = 1;
306 private static final int STATE_IDLE = 2;
308 // flags to trigger NTP or XTRA data download when network becomes available
309 // initialized to true so we do NTP and XTRA when the network comes up after booting
310 private int mInjectNtpTimePending = STATE_PENDING_NETWORK;
311 private int mDownloadXtraDataPending = STATE_PENDING_NETWORK;
313 // set to true if the GPS engine requested on-demand NTP time requests
314 private boolean mOnDemandTimeInjection;
316 // true if GPS is navigating
317 private boolean mNavigating;
319 // true if GPS engine is on
320 private boolean mEngineOn;
322 // requested frequency of fixes, in milliseconds
323 private int mFixInterval = 1000;
325 // true if we started navigation
326 private boolean mStarted;
328 // true if single shot request is in progress
329 private boolean mSingleShot;
331 // capabilities of the GPS engine
332 private int mEngineCapabilities;
334 // true if XTRA is supported
335 private boolean mSupportsXtra;
337 // for calculating time to first fix
338 private long mFixRequestTime = 0;
339 // time to first fix for most recent session
340 private int mTimeToFirstFix = 0;
341 // time we received our last fix
342 private long mLastFixTime;
344 private int mPositionMode;
346 // Current request from underlying location clients.
347 private ProviderRequest mProviderRequest = null;
348 // Current list of underlying location clients.
349 private WorkSource mWorkSource = null;
350 // True if gps should be disabled (used to support battery saver mode in settings).
351 private boolean mDisableGps = false;
354 * Properties loaded from PROPERTIES_FILE.
355 * It must be accessed only inside {@link #mHandler}.
357 private Properties mProperties;
359 private String mSuplServerHost;
360 private int mSuplServerPort = TCP_MIN_PORT;
361 private String mC2KServerHost;
362 private int mC2KServerPort;
363 private boolean mSuplEsEnabled = false;
365 private final Context mContext;
366 private final NtpTrustedTime mNtpTime;
367 private final ILocationManager mILocationManager;
368 private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
369 private Bundle mLocationExtras = new Bundle();
370 private final GnssStatusListenerHelper mListenerHelper;
371 private final GnssMeasurementsProvider mGnssMeasurementsProvider;
372 private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
374 // Handler for processing events
375 private Handler mHandler;
377 /** It must be accessed only inside {@link #mHandler}. */
378 private int mAGpsDataConnectionState;
379 /** It must be accessed only inside {@link #mHandler}. */
380 private InetAddress mAGpsDataConnectionIpAddr;
382 private final ConnectivityManager mConnMgr;
383 private final GpsNetInitiatedHandler mNIHandler;
386 private final static String WAKELOCK_KEY = "GnssLocationProvider";
387 private final PowerManager.WakeLock mWakeLock;
390 private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
391 private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
394 private final static String SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
396 // Persist property for LPP_PROFILE
397 private final static String LPP_PROFILE = "persist.sys.gps.lpp";
400 private static final String[] VzwMccMncList = {"311480", "310004", "20404"};
401 // corresponding GID1 value, empty string means ignore gid1 match.
402 private static final String[] VzwGid1List = {"", "", "BAE0000000000000"};
405 private final PowerManager mPowerManager;
406 private final AlarmManager mAlarmManager;
407 private final PendingIntent mWakeupIntent;
408 private final PendingIntent mTimeoutIntent;
410 private final IAppOpsService mAppOpsService;
411 private final IBatteryStats mBatteryStats;
413 // only modified on handler thread
414 private WorkSource mClientSource = new WorkSource();
416 private GeofenceHardwareImpl mGeofenceHardwareImpl;
418 private int mYearOfHardware = 0;
420 private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() {
422 public void registerGnssStatusCallback(IGnssStatusListener callback) {
423 mListenerHelper.addListener(callback);
427 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
428 mListenerHelper.removeListener(callback);
432 public IGnssStatusProvider getGnssStatusProvider() {
433 return mGnssStatusProvider;
436 public IGpsGeofenceHardware getGpsGeofenceProxy() {
437 return mGpsGeofenceBinder;
440 public GnssMeasurementsProvider getGnssMeasurementsProvider() {
441 return mGnssMeasurementsProvider;
444 public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
445 return mGnssNavigationMessageProvider;
449 * Callback used to listen for data connectivity changes.
451 private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback =
452 new ConnectivityManager.NetworkCallback() {
454 public void onAvailable(Network network) {
455 if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
458 if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
459 xtraDownloadRequest();
465 * Callback used to listen for availability of a requested SUPL connection.
466 * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to
467 * manage the registration/un-registration lifetimes separate.
469 private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback =
470 new ConnectivityManager.NetworkCallback() {
472 public void onAvailable(Network network) {
473 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
477 public void onLost(Network network) {
478 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
482 public void onUnavailable() {
483 // timeout, it was not possible to establish the required connection
484 releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
488 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
489 @Override public void onReceive(Context context, Intent intent) {
490 String action = intent.getAction();
491 if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
492 if (action == null) {
496 if (action.equals(ALARM_WAKEUP)) {
497 startNavigating(false);
498 } else if (action.equals(ALARM_TIMEOUT)) {
500 } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
501 checkSmsSuplInit(intent);
502 } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
503 checkWapSuplInit(intent);
504 } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
505 || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
506 || Intent.ACTION_SCREEN_OFF.equals(action)
507 || Intent.ACTION_SCREEN_ON.equals(action)) {
508 updateLowPowerMode();
509 } else if (action.equals(SIM_STATE_CHANGED)) {
510 subscriptionOrSimChanged(context);
515 private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
516 new OnSubscriptionsChangedListener() {
518 public void onSubscriptionsChanged() {
519 sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
523 private final boolean isVerizon(String mccMnc, String imsi, String groupId) {
524 if (DEBUG) Log.d(TAG, "simOperator: " + mccMnc);
525 if (!TextUtils.isEmpty(mccMnc) || !TextUtils.isEmpty(imsi)) {
526 for (int i = 0; i < VzwMccMncList.length; i++) {
527 if ((!TextUtils.isEmpty(mccMnc) && mccMnc.equals(VzwMccMncList[i])) ||
528 (!TextUtils.isEmpty(imsi) && imsi.startsWith(VzwMccMncList[i]))) {
529 // check gid too if needed
530 if (TextUtils.isEmpty(VzwGid1List[i]) || VzwGid1List[i].equals(groupId)) {
531 if (DEBUG) Log.d(TAG, "Verizon UICC");
540 private void subscriptionOrSimChanged(Context context) {
541 if (DEBUG) Log.d(TAG, "received SIM related action: ");
542 TelephonyManager phone = (TelephonyManager)
543 mContext.getSystemService(Context.TELEPHONY_SERVICE);
544 String mccMnc = phone.getSimOperator();
545 String imsi = phone.getSubscriberId();
546 String groupId = phone.getGroupIdLevel1();
547 if (!TextUtils.isEmpty(mccMnc)) {
548 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
549 synchronized (mLock) {
550 if (isVerizon(mccMnc, imsi, groupId)) {
551 // load current properties for carrier VZW
552 loadPropertiesFromResource(context, mProperties);
553 String lpp_profile = mProperties.getProperty("LPP_PROFILE");
554 // set the persist property LPP_PROFILE for VZW
555 SystemProperties.set(LPP_PROFILE, lpp_profile);
557 // reset the persist property for Non VZW
558 SystemProperties.set(LPP_PROFILE, "");
560 reloadGpsProperties(context, mProperties);
561 mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
564 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available");
568 private void checkSmsSuplInit(Intent intent) {
569 SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
570 if (messages == null) {
571 Log.e(TAG, "Message does not exist in the intent.");
575 for (SmsMessage message : messages) {
576 if (message != null && message.mWrappedSmsMessage != null) {
577 byte[] suplInit = message.getUserData();
578 if (suplInit != null) {
579 native_agps_ni_message(suplInit, suplInit.length);
585 private void checkWapSuplInit(Intent intent) {
586 byte[] suplInit = intent.getByteArrayExtra("data");
587 if (suplInit == null) {
590 native_agps_ni_message(suplInit,suplInit.length);
593 private void updateLowPowerMode() {
594 // Disable GPS if we are in device idle mode.
595 boolean disableGps = mPowerManager.isDeviceIdleMode();
596 switch (Settings.Secure.getInt(mContext.getContentResolver(), BATTERY_SAVER_GPS_MODE,
597 BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF)) {
598 case BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF:
599 // If we are in battery saver mode and the screen is off, disable GPS.
600 disableGps |= mPowerManager.isPowerSaveMode() && !mPowerManager.isInteractive();
603 if (disableGps != mDisableGps) {
604 mDisableGps = disableGps;
605 updateRequirements();
609 public static boolean isSupported() {
610 return native_is_supported();
613 private void reloadGpsProperties(Context context, Properties properties) {
614 if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
615 loadPropertiesFromResource(context, properties);
617 boolean isPropertiesLoadedFromFile = false;
618 final String gpsHardware = SystemProperties.get("ro.hardware.gps");
620 if (!TextUtils.isEmpty(gpsHardware)) {
621 final String propFilename =
622 PROPERTIES_FILE_PREFIX + "." + gpsHardware + PROPERTIES_FILE_SUFFIX;
623 isPropertiesLoadedFromFile =
624 loadPropertiesFromFile(propFilename, properties);
626 if (!isPropertiesLoadedFromFile) {
627 loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties);
629 if (DEBUG) Log.d(TAG, "GPS properties reloaded, size = " + properties.size());
630 String lpp_prof = SystemProperties.get(LPP_PROFILE);
631 if (!TextUtils.isEmpty(lpp_prof)) {
632 // override default value of this if lpp_prof is not empty
633 properties.setProperty("LPP_PROFILE", lpp_prof);
635 // TODO: we should get rid of C2K specific setting.
636 setSuplHostPort(properties.getProperty("SUPL_HOST"),
637 properties.getProperty("SUPL_PORT"));
638 mC2KServerHost = properties.getProperty("C2K_HOST");
639 String portString = properties.getProperty("C2K_PORT");
640 if (mC2KServerHost != null && portString != null) {
642 mC2KServerPort = Integer.parseInt(portString);
643 } catch (NumberFormatException e) {
644 Log.e(TAG, "unable to parse C2K_PORT: " + portString);
648 if (native_is_gnss_configuration_supported()) {
650 // Convert properties to string contents and send it to HAL.
651 ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
652 properties.store(baos, null);
653 native_configuration_update(baos.toString());
654 if (DEBUG) Log.d(TAG, "final config = " + baos.toString());
655 } catch (IOException ex) {
656 Log.e(TAG, "failed to dump properties contents");
659 Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
663 // SUPL_ES configuration.
664 String suplESProperty = mProperties.getProperty("SUPL_ES");
665 if (suplESProperty != null) {
667 mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1);
668 } catch (NumberFormatException e) {
669 Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty);
674 private void loadPropertiesFromResource(Context context,
675 Properties properties) {
676 String[] configValues = context.getResources().getStringArray(
677 com.android.internal.R.array.config_gpsParameters);
678 for (String item : configValues) {
679 if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item);
680 // We need to support "KEY =", but not "=VALUE".
681 String[] split = item.split("=");
682 if (split.length == 2) {
683 properties.setProperty(split[0].trim().toUpperCase(), split[1]);
685 Log.w(TAG, "malformed contents: " + item);
690 private boolean loadPropertiesFromFile(String filename,
691 Properties properties) {
693 File file = new File(filename);
694 FileInputStream stream = null;
696 stream = new FileInputStream(file);
697 properties.load(stream);
699 IoUtils.closeQuietly(stream);
702 } catch (IOException e) {
703 Log.w(TAG, "Could not open GPS configuration file " + filename);
709 public GnssLocationProvider(Context context, ILocationManager ilocationManager,
712 mNtpTime = NtpTrustedTime.getInstance(context);
713 mILocationManager = ilocationManager;
715 mLocation.setExtras(mLocationExtras);
717 // Create a wake lock
718 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
719 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
720 mWakeLock.setReferenceCounted(true);
722 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
723 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
724 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
726 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
728 // App ops service to keep track of who is accessing the GPS
729 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
730 Context.APP_OPS_SERVICE));
732 // Battery statistics service to be notified when GPS turns on or off
733 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
734 BatteryStats.SERVICE_NAME));
736 // Construct internal handler
737 mHandler = new ProviderHandler(looper);
739 // Load GPS configuration and register listeners in the background:
740 // some operations, such as opening files and registering broadcast receivers, can take a
741 // relative long time, so the ctor() is kept to create objects needed by this instance,
742 // while IO initialization and registration is delegated to our internal handler
743 // this approach is just fine because events are posted to our handler anyway
744 mProperties = new Properties();
745 sendMessage(INITIALIZE_HANDLER, 0, null);
747 // Create a GPS net-initiated handler.
748 mNIHandler = new GpsNetInitiatedHandler(context,
749 mNetInitiatedListener,
752 mListenerHelper = new GnssStatusListenerHelper(mHandler) {
754 protected boolean isAvailableInPlatform() {
755 return isSupported();
759 protected boolean isGpsEnabled() {
764 mGnssMeasurementsProvider = new GnssMeasurementsProvider(mHandler) {
766 public boolean isAvailableInPlatform() {
767 return native_is_measurement_supported();
771 protected boolean registerWithService() {
772 return native_start_measurement_collection();
776 protected void unregisterFromService() {
777 native_stop_measurement_collection();
781 protected boolean isGpsEnabled() {
786 mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) {
788 protected boolean isAvailableInPlatform() {
789 return native_is_navigation_message_supported();
793 protected boolean registerWithService() {
794 return native_start_navigation_message_collection();
798 protected void unregisterFromService() {
799 native_stop_navigation_message_collection();
803 protected boolean isGpsEnabled() {
810 * Returns the name of this provider.
813 public String getName() {
814 return LocationManager.GPS_PROVIDER;
818 public ProviderProperties getProperties() {
822 private void handleUpdateNetworkState(Network network) {
823 // retrieve NetworkInfo for this UID
824 NetworkInfo info = mConnMgr.getNetworkInfo(network);
829 boolean isConnected = info.isConnected();
831 String message = String.format(
832 "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
833 agpsDataConnStateAsString(),
836 mConnMgr.getNetworkCapabilities(network));
840 if (native_is_agps_ril_supported()) {
841 boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled();
842 boolean networkAvailable = info.isAvailable() && dataEnabled;
843 String defaultApn = getSelectedApn();
844 if (defaultApn == null) {
845 defaultApn = "dummy-apn";
848 native_update_network_state(
856 Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported");
859 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
861 String apnName = info.getExtraInfo();
862 if (apnName == null) {
863 // assign a dummy value in the case of C2K as otherwise we will have a runtime
864 // exception in the following call to native_agps_data_conn_open
865 apnName = "dummy-apn";
867 int apnIpType = getApnIpType(apnName);
870 String message = String.format(
871 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
876 native_agps_data_conn_open(apnName, apnIpType);
877 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
879 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
884 private void handleRequestSuplConnection(InetAddress address) {
886 String message = String.format(
887 "requestSuplConnection, state=%s, address=%s",
888 agpsDataConnStateAsString(),
893 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
896 mAGpsDataConnectionIpAddr = address;
897 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
899 NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
900 requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
901 requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
902 NetworkRequest request = requestBuilder.build();
903 mConnMgr.requestNetwork(
905 mSuplConnectivityCallback,
906 ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS);
909 private void handleReleaseSuplConnection(int agpsDataConnStatus) {
911 String message = String.format(
912 "releaseSuplConnection, state=%s, status=%s",
913 agpsDataConnStateAsString(),
914 agpsDataConnStatusAsString(agpsDataConnStatus));
918 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
921 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
923 mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
924 switch (agpsDataConnStatus) {
925 case GPS_AGPS_DATA_CONN_FAILED:
926 native_agps_data_conn_failed();
928 case GPS_RELEASE_AGPS_DATA_CONN:
929 native_agps_data_conn_closed();
932 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
936 private void handleInjectNtpTime() {
937 if (mInjectNtpTimePending == STATE_DOWNLOADING) {
938 // already downloading data
941 if (!isDataNetworkConnected()) {
942 // try again when network is up
943 mInjectNtpTimePending = STATE_PENDING_NETWORK;
946 mInjectNtpTimePending = STATE_DOWNLOADING;
948 // hold wake lock while task runs
950 Log.i(TAG, "WakeLock acquired by handleInjectNtpTime()");
951 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
956 // force refresh NTP cache when outdated
957 boolean refreshSuccess = true;
958 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
959 refreshSuccess = mNtpTime.forceRefresh();
962 // only update when NTP time is fresh
963 if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
964 long time = mNtpTime.getCachedNtpTime();
965 long timeReference = mNtpTime.getCachedNtpTimeReference();
966 long certainty = mNtpTime.getCacheCertainty();
967 long now = System.currentTimeMillis();
970 Log.d(TAG, "NTP server returned: "
971 + time + " (" + new Date(time)
972 + ") reference: " + timeReference
973 + " certainty: " + certainty
974 + " system time offset: " + (time - now));
977 native_inject_time(time, timeReference, (int) certainty);
978 delay = NTP_INTERVAL;
981 Log.e(TAG, "requestTime failed");
982 delay = mNtpBackOff.nextBackoffMillis();
985 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
988 String message = String.format(
989 "onDemandTimeInjection=%s, refreshSuccess=%s, delay=%s",
990 mOnDemandTimeInjection,
995 if (mOnDemandTimeInjection || !refreshSuccess) {
996 // send delayed message for next NTP injection
997 // since this is delayed and not urgent we do not hold a wake lock here
998 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
1001 // release wake lock held by task
1002 mWakeLock.release();
1003 Log.i(TAG, "WakeLock released by handleInjectNtpTime()");
1008 private void handleDownloadXtraData() {
1009 if (!mSupportsXtra) {
1010 // native code reports xtra not supported, don't try
1011 Log.d(TAG, "handleDownloadXtraData() called when Xtra not supported");
1014 if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
1015 // already downloading data
1018 if (!isDataNetworkConnected()) {
1019 // try again when network is up
1020 mDownloadXtraDataPending = STATE_PENDING_NETWORK;
1023 mDownloadXtraDataPending = STATE_DOWNLOADING;
1025 // hold wake lock while task runs
1026 mWakeLock.acquire();
1027 Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
1028 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
1031 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
1032 byte[] data = xtraDownloader.downloadXtraData();
1034 if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
1035 native_inject_xtra_data(data, data.length);
1036 mXtraBackOff.reset();
1039 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
1043 // since this is delayed and not urgent we do not hold a wake lock here
1044 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
1045 mXtraBackOff.nextBackoffMillis());
1048 // release wake lock held by task
1049 mWakeLock.release();
1050 Log.i(TAG, "WakeLock released by handleDownloadXtraData()");
1055 private void handleUpdateLocation(Location location) {
1056 if (location.hasAccuracy()) {
1057 native_inject_location(location.getLatitude(), location.getLongitude(),
1058 location.getAccuracy());
1063 * Enables this provider. When enabled, calls to getStatus()
1064 * must be handled. Hardware may be started up
1065 * when the provider is enabled.
1068 public void enable() {
1069 synchronized (mLock) {
1070 if (mEnabled) return;
1074 sendMessage(ENABLE, 1, null);
1077 private void setSuplHostPort(String hostString, String portString) {
1078 if (hostString != null) {
1079 mSuplServerHost = hostString;
1081 if (portString != null) {
1083 mSuplServerPort = Integer.parseInt(portString);
1084 } catch (NumberFormatException e) {
1085 Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
1088 if (mSuplServerHost != null
1089 && mSuplServerPort > TCP_MIN_PORT
1090 && mSuplServerPort <= TCP_MAX_PORT) {
1091 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1096 * Checks what SUPL mode to use, according to the AGPS mode as well as the
1097 * allowed mode from properties.
1099 * @param properties GPS properties
1100 * @param agpsEnabled whether AGPS is enabled by settings value
1101 * @param singleShot whether "singleshot" is needed
1102 * @return SUPL mode (MSA vs MSB vs STANDALONE)
1104 private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
1106 String modeString = properties.getProperty("SUPL_MODE");
1108 if (!TextUtils.isEmpty(modeString)) {
1110 suplMode = Integer.parseInt(modeString);
1111 } catch (NumberFormatException e) {
1112 Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
1113 return GPS_POSITION_MODE_STANDALONE;
1116 // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
1117 // such mode when it is available
1118 if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
1119 return GPS_POSITION_MODE_MS_BASED;
1121 // for now, just as the legacy code did, we fallback to MS-Assisted if it is available,
1122 // do fallback only for single-shot requests, because it is too expensive to do for
1123 // periodic requests as well
1125 && hasCapability(GPS_CAPABILITY_MSA)
1126 && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
1127 return GPS_POSITION_MODE_MS_ASSISTED;
1130 return GPS_POSITION_MODE_STANDALONE;
1133 private void handleEnable() {
1134 if (DEBUG) Log.d(TAG, "handleEnable");
1136 boolean enabled = native_init();
1139 mSupportsXtra = native_supports_xtra();
1141 // TODO: remove the following native calls if we can make sure they are redundant.
1142 if (mSuplServerHost != null) {
1143 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1145 if (mC2KServerHost != null) {
1146 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
1149 mGnssMeasurementsProvider.onGpsEnabledChanged();
1150 mGnssNavigationMessageProvider.onGpsEnabledChanged();
1152 synchronized (mLock) {
1155 Log.w(TAG, "Failed to enable location provider");
1160 * Disables this provider. When disabled, calls to getStatus()
1161 * need not be handled. Hardware may be shut
1162 * down while the provider is disabled.
1165 public void disable() {
1166 synchronized (mLock) {
1167 if (!mEnabled) return;
1171 sendMessage(ENABLE, 0, null);
1174 private void handleDisable() {
1175 if (DEBUG) Log.d(TAG, "handleDisable");
1177 updateClientUids(new WorkSource());
1179 mAlarmManager.cancel(mWakeupIntent);
1180 mAlarmManager.cancel(mTimeoutIntent);
1182 // do this before releasing wakelock
1185 mGnssMeasurementsProvider.onGpsEnabledChanged();
1186 mGnssNavigationMessageProvider.onGpsEnabledChanged();
1190 public boolean isEnabled() {
1191 synchronized (mLock) {
1197 public int getStatus(Bundle extras) {
1198 if (extras != null) {
1199 extras.putInt("satellites", mSvCount);
1204 private void updateStatus(int status, int svCount) {
1205 if (status != mStatus || svCount != mSvCount) {
1208 mLocationExtras.putInt("satellites", svCount);
1209 mStatusUpdateTime = SystemClock.elapsedRealtime();
1214 public long getStatusUpdateTime() {
1215 return mStatusUpdateTime;
1219 public void setRequest(ProviderRequest request, WorkSource source) {
1220 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
1223 private void handleSetRequest(ProviderRequest request, WorkSource source) {
1224 mProviderRequest = request;
1225 mWorkSource = source;
1226 updateRequirements();
1229 // Called when the requirements for GPS may have changed
1230 private void updateRequirements() {
1231 if (mProviderRequest == null || mWorkSource == null) {
1235 boolean singleShot = false;
1237 // see if the request is for a single update
1238 if (mProviderRequest.locationRequests != null
1239 && mProviderRequest.locationRequests.size() > 0) {
1240 // if any request has zero or more than one updates
1241 // requested, then this is not single-shot mode
1244 for (LocationRequest lr : mProviderRequest.locationRequests) {
1245 if (lr.getNumUpdates() != 1) {
1251 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
1252 if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
1253 // update client uids
1254 updateClientUids(mWorkSource);
1256 mFixInterval = (int) mProviderRequest.interval;
1258 // check for overflow
1259 if (mFixInterval != mProviderRequest.interval) {
1260 Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
1261 mFixInterval = Integer.MAX_VALUE;
1264 // apply request to GPS engine
1265 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1267 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1268 mFixInterval, 0, 0)) {
1269 Log.e(TAG, "set_position_mode failed in setMinTime()");
1271 } else if (!mStarted) {
1273 startNavigating(singleShot);
1276 updateClientUids(new WorkSource());
1279 mAlarmManager.cancel(mWakeupIntent);
1280 mAlarmManager.cancel(mTimeoutIntent);
1284 private void updateClientUids(WorkSource source) {
1285 // Update work source.
1286 WorkSource[] changes = mClientSource.setReturningDiffs(source);
1287 if (changes == null) {
1290 WorkSource newWork = changes[0];
1291 WorkSource goneWork = changes[1];
1293 // Update sources that were not previously tracked.
1294 if (newWork != null) {
1296 for (int i=0; i<newWork.size(); i++) {
1298 int uid = newWork.get(i);
1299 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
1300 AppOpsManager.OP_GPS, uid, newWork.getName(i));
1301 if (uid != lastuid) {
1303 mBatteryStats.noteStartGps(uid);
1305 } catch (RemoteException e) {
1306 Log.w(TAG, "RemoteException", e);
1311 // Update sources that are no longer tracked.
1312 if (goneWork != null) {
1314 for (int i=0; i<goneWork.size(); i++) {
1316 int uid = goneWork.get(i);
1317 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
1318 AppOpsManager.OP_GPS, uid, goneWork.getName(i));
1319 if (uid != lastuid) {
1321 mBatteryStats.noteStopGps(uid);
1323 } catch (RemoteException e) {
1324 Log.w(TAG, "RemoteException", e);
1331 public boolean sendExtraCommand(String command, Bundle extras) {
1333 long identity = Binder.clearCallingIdentity();
1334 boolean result = false;
1336 if ("delete_aiding_data".equals(command)) {
1337 result = deleteAidingData(extras);
1338 } else if ("force_time_injection".equals(command)) {
1341 } else if ("force_xtra_injection".equals(command)) {
1342 if (mSupportsXtra) {
1343 xtraDownloadRequest();
1347 Log.w(TAG, "sendExtraCommand: unknown command " + command);
1350 Binder.restoreCallingIdentity(identity);
1354 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
1355 public boolean isHardwareGeofenceSupported() {
1356 return native_is_geofence_supported();
1359 public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
1360 double longitude, double radius, int lastTransition, int monitorTransitions,
1361 int notificationResponsiveness, int unknownTimer) {
1362 return native_add_geofence(geofenceId, latitude, longitude, radius,
1363 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
1366 public boolean removeHardwareGeofence(int geofenceId) {
1367 return native_remove_geofence(geofenceId);
1370 public boolean pauseHardwareGeofence(int geofenceId) {
1371 return native_pause_geofence(geofenceId);
1374 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
1375 return native_resume_geofence(geofenceId, monitorTransition);
1379 private boolean deleteAidingData(Bundle extras) {
1382 if (extras == null) {
1383 flags = GPS_DELETE_ALL;
1386 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
1387 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
1388 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
1389 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
1390 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
1391 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
1392 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
1393 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
1394 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
1395 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
1396 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
1397 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
1398 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
1402 native_delete_aiding_data(flags);
1409 private void startNavigating(boolean singleShot) {
1411 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
1412 mTimeToFirstFix = 0;
1415 mSingleShot = singleShot;
1416 mPositionMode = GPS_POSITION_MODE_STANDALONE;
1418 boolean agpsEnabled =
1419 (Settings.Global.getInt(mContext.getContentResolver(),
1420 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
1421 mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
1426 switch(mPositionMode) {
1427 case GPS_POSITION_MODE_STANDALONE:
1428 mode = "standalone";
1430 case GPS_POSITION_MODE_MS_ASSISTED:
1431 mode = "MS_ASSISTED";
1433 case GPS_POSITION_MODE_MS_BASED:
1440 Log.d(TAG, "setting position_mode to " + mode);
1443 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1444 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1447 Log.e(TAG, "set_position_mode failed in startNavigating()");
1450 if (!native_start()) {
1452 Log.e(TAG, "native_start failed in startNavigating()");
1456 // reset SV count to zero
1457 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1458 mFixRequestTime = System.currentTimeMillis();
1459 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1460 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1461 // and our fix interval is not short
1462 if (mFixInterval >= NO_FIX_TIMEOUT) {
1463 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1464 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1470 private void stopNavigating() {
1471 if (DEBUG) Log.d(TAG, "stopNavigating");
1474 mSingleShot = false;
1476 mTimeToFirstFix = 0;
1478 mLocationFlags = LOCATION_INVALID;
1480 // reset SV count to zero
1481 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1485 private void hibernate() {
1486 // stop GPS until our next fix interval arrives
1488 mAlarmManager.cancel(mTimeoutIntent);
1489 mAlarmManager.cancel(mWakeupIntent);
1490 long now = SystemClock.elapsedRealtime();
1491 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
1494 private boolean hasCapability(int capability) {
1495 return ((mEngineCapabilities & capability) != 0);
1500 * called from native code to update our position.
1502 private void reportLocation(int flags, double latitude, double longitude, double altitude,
1503 float speed, float bearing, float accuracy, long timestamp) {
1504 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
1505 " timestamp: " + timestamp);
1507 synchronized (mLocation) {
1508 mLocationFlags = flags;
1509 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1510 mLocation.setLatitude(latitude);
1511 mLocation.setLongitude(longitude);
1512 mLocation.setTime(timestamp);
1513 // It would be nice to push the elapsed real-time timestamp
1514 // further down the stack, but this is still useful
1515 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1517 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1518 mLocation.setAltitude(altitude);
1520 mLocation.removeAltitude();
1522 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1523 mLocation.setSpeed(speed);
1525 mLocation.removeSpeed();
1527 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1528 mLocation.setBearing(bearing);
1530 mLocation.removeBearing();
1532 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1533 mLocation.setAccuracy(accuracy);
1535 mLocation.removeAccuracy();
1537 mLocation.setExtras(mLocationExtras);
1540 mILocationManager.reportLocation(mLocation, false);
1541 } catch (RemoteException e) {
1542 Log.e(TAG, "RemoteException calling reportLocation");
1546 mLastFixTime = System.currentTimeMillis();
1547 // report time to first fix
1548 if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1549 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
1550 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
1552 // notify status listeners
1553 mListenerHelper.onFirstFix(mTimeToFirstFix);
1560 if (mStarted && mStatus != LocationProvider.AVAILABLE) {
1561 // we want to time out if we do not receive a fix
1562 // within the time out and we are requesting infrequent fixes
1563 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
1564 mAlarmManager.cancel(mTimeoutIntent);
1567 // send an intent to notify that the GPS is receiving fixes.
1568 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1569 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
1570 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1571 updateStatus(LocationProvider.AVAILABLE, mSvCount);
1574 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1575 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
1576 if (DEBUG) Log.d(TAG, "got fix, hibernating");
1582 * called from native code to update our status
1584 private void reportStatus(int status) {
1585 if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
1587 boolean wasNavigating = mNavigating;
1589 case GPS_STATUS_SESSION_BEGIN:
1593 case GPS_STATUS_SESSION_END:
1594 mNavigating = false;
1596 case GPS_STATUS_ENGINE_ON:
1599 case GPS_STATUS_ENGINE_OFF:
1601 mNavigating = false;
1605 if (wasNavigating != mNavigating) {
1606 mListenerHelper.onStatusChanged(mNavigating);
1608 // send an intent to notify that the GPS has been enabled or disabled
1609 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1610 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
1611 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1616 * called from native code to update SV info
1618 private void reportSvStatus() {
1619 int svCount = native_read_sv_status(mSvidWithFlags, mCn0s, mSvElevations, mSvAzimuths);
1620 mListenerHelper.onSvStatusChanged(
1628 Log.v(TAG, "SV count: " + svCount);
1630 // Calculate number of sets used in fix.
1631 int usedInFixCount = 0;
1632 for (int i = 0; i < svCount; i++) {
1633 if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
1637 Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
1638 " cn0: " + mCn0s[i]/10 +
1639 " elev: " + mSvElevations[i] +
1640 " azimuth: " + mSvAzimuths[i] +
1641 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
1643 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
1645 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
1649 // return number of sets used in fix instead of total
1650 updateStatus(mStatus, usedInFixCount);
1652 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
1653 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
1654 // send an intent to notify that the GPS is no longer receiving fixes.
1655 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1656 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
1657 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1658 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
1663 * called from native code to update AGPS status
1665 private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
1667 case GPS_REQUEST_AGPS_DATA_CONN:
1668 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
1669 Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
1670 InetAddress connectionIpAddress = null;
1671 if (ipaddr != null) {
1673 connectionIpAddress = InetAddress.getByAddress(ipaddr);
1674 if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
1675 } catch (UnknownHostException e) {
1676 Log.e(TAG, "Bad IP Address: " + ipaddr, e);
1679 sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress);
1681 case GPS_RELEASE_AGPS_DATA_CONN:
1682 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
1683 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
1685 case GPS_AGPS_DATA_CONNECTED:
1686 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
1688 case GPS_AGPS_DATA_CONN_DONE:
1689 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
1691 case GPS_AGPS_DATA_CONN_FAILED:
1692 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
1695 if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
1699 private void releaseSuplConnection(int connStatus) {
1700 sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/);
1704 * called from native code to report NMEA data received
1706 private void reportNmea(long timestamp) {
1707 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
1708 String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
1709 mListenerHelper.onNmeaReceived(timestamp, nmea);
1713 * called from native code - Gps measurements callback
1715 private void reportMeasurementData(GnssMeasurementsEvent event) {
1716 mGnssMeasurementsProvider.onMeasurementsAvailable(event);
1720 * called from native code - GPS navigation message callback
1722 private void reportNavigationMessage(GnssNavigationMessage event) {
1723 mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
1727 * called from native code to inform us what the GPS engine capabilities are
1729 private void setEngineCapabilities(int capabilities) {
1730 mEngineCapabilities = capabilities;
1732 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
1733 mOnDemandTimeInjection = true;
1737 mGnssMeasurementsProvider.onCapabilitiesUpdated(
1738 (capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS);
1739 mGnssNavigationMessageProvider.onCapabilitiesUpdated(
1740 (capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES);
1744 * Called from native code to inform us the hardware information.
1746 private void setGnssYearOfHardware(int yearOfHardware) {
1747 if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
1748 mYearOfHardware = yearOfHardware;
1751 public interface GnssSystemInfoProvider {
1753 * Returns the year of GPS hardware.
1755 int getGnssYearOfHardware();
1761 public GnssSystemInfoProvider getGnssSystemInfoProvider() {
1762 return new GnssSystemInfoProvider() {
1764 public int getGnssYearOfHardware() {
1765 return mYearOfHardware;
1771 * called from native code to request XTRA data
1773 private void xtraDownloadRequest() {
1774 if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
1775 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
1779 * Helper method to construct a location object.
1781 private Location buildLocation(
1790 Location location = new Location(LocationManager.GPS_PROVIDER);
1791 if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1792 location.setLatitude(latitude);
1793 location.setLongitude(longitude);
1794 location.setTime(timestamp);
1795 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1797 if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1798 location.setAltitude(altitude);
1800 if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1801 location.setSpeed(speed);
1803 if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1804 location.setBearing(bearing);
1806 if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1807 location.setAccuracy(accuracy);
1813 * Converts the GPS HAL status to the internal Geofence Hardware status.
1815 private int getGeofenceStatus(int status) {
1817 case GPS_GEOFENCE_OPERATION_SUCCESS:
1818 return GeofenceHardware.GEOFENCE_SUCCESS;
1819 case GPS_GEOFENCE_ERROR_GENERIC:
1820 return GeofenceHardware.GEOFENCE_FAILURE;
1821 case GPS_GEOFENCE_ERROR_ID_EXISTS:
1822 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
1823 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
1824 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
1825 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
1826 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
1827 case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
1828 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
1835 * Called from native to report GPS Geofence transition
1836 * All geofence callbacks are called on the same thread
1838 private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
1839 double longitude, double altitude, float speed, float bearing, float accuracy,
1840 long timestamp, int transition, long transitionTimestamp) {
1841 if (mGeofenceHardwareImpl == null) {
1842 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1844 Location location = buildLocation(
1853 mGeofenceHardwareImpl.reportGeofenceTransition(
1857 transitionTimestamp,
1858 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1859 FusedBatchOptions.SourceTechnologies.GNSS);
1863 * called from native code to report GPS status change.
1865 private void reportGeofenceStatus(int status, int flags, double latitude,
1866 double longitude, double altitude, float speed, float bearing, float accuracy,
1868 if (mGeofenceHardwareImpl == null) {
1869 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1871 Location location = buildLocation(
1880 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
1881 if(status == GPS_GEOFENCE_AVAILABLE) {
1882 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
1884 mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
1885 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1888 FusedBatchOptions.SourceTechnologies.GNSS);
1892 * called from native code - Geofence Add callback
1894 private void reportGeofenceAddStatus(int geofenceId, int status) {
1895 if (mGeofenceHardwareImpl == null) {
1896 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1898 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
1902 * called from native code - Geofence Remove callback
1904 private void reportGeofenceRemoveStatus(int geofenceId, int status) {
1905 if (mGeofenceHardwareImpl == null) {
1906 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1908 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
1912 * called from native code - Geofence Pause callback
1914 private void reportGeofencePauseStatus(int geofenceId, int status) {
1915 if (mGeofenceHardwareImpl == null) {
1916 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1918 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
1922 * called from native code - Geofence Resume callback
1924 private void reportGeofenceResumeStatus(int geofenceId, int status) {
1925 if (mGeofenceHardwareImpl == null) {
1926 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1928 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
1931 //=============================================================
1932 // NI Client support
1933 //=============================================================
1934 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
1935 // Sends a response for an NI request to HAL.
1937 public boolean sendNiResponse(int notificationId, int userResponse)
1939 // TODO Add Permission check
1941 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
1942 ", response: " + userResponse);
1943 native_send_ni_response(notificationId, userResponse);
1948 public INetInitiatedListener getNetInitiatedListener() {
1949 return mNetInitiatedListener;
1952 // Called by JNI function to report an NI request.
1953 public void reportNiNotification(
1958 int defaultResponse,
1961 int requestorIdEncoding,
1963 String extras // Encoded extra data
1966 Log.i(TAG, "reportNiNotification: entered");
1967 Log.i(TAG, "notificationId: " + notificationId +
1968 ", niType: " + niType +
1969 ", notifyFlags: " + notifyFlags +
1970 ", timeout: " + timeout +
1971 ", defaultResponse: " + defaultResponse);
1973 Log.i(TAG, "requestorId: " + requestorId +
1975 ", requestorIdEncoding: " + requestorIdEncoding +
1976 ", textEncoding: " + textEncoding);
1978 GpsNiNotification notification = new GpsNiNotification();
1980 notification.notificationId = notificationId;
1981 notification.niType = niType;
1982 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
1983 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
1984 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
1985 notification.timeout = timeout;
1986 notification.defaultResponse = defaultResponse;
1987 notification.requestorId = requestorId;
1988 notification.text = text;
1989 notification.requestorIdEncoding = requestorIdEncoding;
1990 notification.textEncoding = textEncoding;
1992 // Process extras, assuming the format is
1993 // one of more lines of "key = value"
1994 Bundle bundle = new Bundle();
1996 if (extras == null) extras = "";
1997 Properties extraProp = new Properties();
2000 extraProp.load(new StringReader(extras));
2002 catch (IOException e)
2004 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
2007 for (Entry<Object, Object> ent : extraProp.entrySet())
2009 bundle.putString((String) ent.getKey(), (String) ent.getValue());
2012 notification.extras = bundle;
2014 mNIHandler.handleNiNotification(notification);
2018 * Called from native code to request set id info.
2019 * We should be careful about receiving null string from the TelephonyManager,
2020 * because sending null String to JNI function would cause a crash.
2023 private void requestSetID(int flags) {
2024 TelephonyManager phone = (TelephonyManager)
2025 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2026 int type = AGPS_SETID_TYPE_NONE;
2029 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
2030 String data_temp = phone.getSubscriberId();
2031 if (data_temp == null) {
2032 // This means the framework does not have the SIM card ready.
2034 // This means the framework has the SIM card.
2036 type = AGPS_SETID_TYPE_IMSI;
2039 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
2040 String data_temp = phone.getLine1Number();
2041 if (data_temp == null) {
2042 // This means the framework does not have the SIM card ready.
2044 // This means the framework has the SIM card.
2046 type = AGPS_SETID_TYPE_MSISDN;
2049 native_agps_set_id(type, data);
2053 * Called from native code to request utc time info
2055 private void requestUtcTime() {
2056 if (DEBUG) Log.d(TAG, "utcTimeRequest");
2057 sendMessage(INJECT_NTP_TIME, 0, null);
2061 * Called from native code to request reference location info
2064 private void requestRefLocation(int flags) {
2065 TelephonyManager phone = (TelephonyManager)
2066 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2067 final int phoneType = phone.getPhoneType();
2068 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
2069 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
2070 if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
2071 && (phone.getNetworkOperator().length() > 3)) {
2073 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
2074 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
2075 int networkType = phone.getNetworkType();
2076 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
2077 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
2078 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
2079 || networkType == TelephonyManager.NETWORK_TYPE_HSPA
2080 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
2081 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
2083 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
2085 native_agps_set_ref_location_cellid(type, mcc, mnc,
2086 gsm_cell.getLac(), gsm_cell.getCid());
2088 Log.e(TAG,"Error getting cell location info.");
2090 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
2091 Log.e(TAG, "CDMA not supported.");
2095 private void sendMessage(int message, int arg, Object obj) {
2096 // hold a wake lock until this message is delivered
2097 // note that this assumes the message will not be removed from the queue before
2098 // it is handled (otherwise the wake lock would be leaked).
2099 mWakeLock.acquire();
2100 Log.i(TAG, "WakeLock acquired by sendMessage(" + message + ", " + arg + ", " + obj + ")");
2101 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
2104 private final class ProviderHandler extends Handler {
2105 public ProviderHandler(Looper looper) {
2106 super(looper, null, true /*async*/);
2110 public void handleMessage(Message msg) {
2111 int message = msg.what;
2114 if (msg.arg1 == 1) {
2121 GpsRequest gpsRequest = (GpsRequest) msg.obj;
2122 handleSetRequest(gpsRequest.request, gpsRequest.source);
2124 case UPDATE_NETWORK_STATE:
2125 handleUpdateNetworkState((Network) msg.obj);
2127 case REQUEST_SUPL_CONNECTION:
2128 handleRequestSuplConnection((InetAddress) msg.obj);
2130 case RELEASE_SUPL_CONNECTION:
2131 handleReleaseSuplConnection(msg.arg1);
2133 case INJECT_NTP_TIME:
2134 handleInjectNtpTime();
2136 case DOWNLOAD_XTRA_DATA:
2137 handleDownloadXtraData();
2139 case INJECT_NTP_TIME_FINISHED:
2140 mInjectNtpTimePending = STATE_IDLE;
2142 case DOWNLOAD_XTRA_DATA_FINISHED:
2143 mDownloadXtraDataPending = STATE_IDLE;
2145 case UPDATE_LOCATION:
2146 handleUpdateLocation((Location) msg.obj);
2148 case SUBSCRIPTION_OR_SIM_CHANGED:
2149 subscriptionOrSimChanged(mContext);
2151 case INITIALIZE_HANDLER:
2155 if (msg.arg2 == 1) {
2156 // wakelock was taken for this message, release it
2157 mWakeLock.release();
2158 Log.i(TAG, "WakeLock released by handleMessage(" + message + ", " + msg.arg1 + ", "
2164 * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
2165 * It is in charge of loading properties and registering for events that will be posted to
2168 private void handleInitialize() {
2169 // load default GPS configuration
2170 // (this configuration might change in the future based on SIM changes)
2171 reloadGpsProperties(mContext, mProperties);
2173 // TODO: When this object "finishes" we should unregister by invoking
2174 // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
2175 // This is not strictly necessary because it will be unregistered if the
2176 // notification fails but it is good form.
2178 // Register for SubscriptionInfo list changes which is guaranteed
2179 // to invoke onSubscriptionsChanged the first time.
2180 SubscriptionManager.from(mContext)
2181 .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
2183 // listen for events
2184 IntentFilter intentFilter;
2185 if (native_is_agps_ril_supported()) {
2186 intentFilter = new IntentFilter();
2187 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
2188 intentFilter.addDataScheme("sms");
2189 intentFilter.addDataAuthority("localhost", "7275");
2190 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2192 intentFilter = new IntentFilter();
2193 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
2195 intentFilter.addDataType("application/vnd.omaloc-supl-init");
2196 } catch (IntentFilter.MalformedMimeTypeException e) {
2197 Log.w(TAG, "Malformed SUPL init mime type");
2199 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2201 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS"
2202 + " HAL is not supported");
2205 intentFilter = new IntentFilter();
2206 intentFilter.addAction(ALARM_WAKEUP);
2207 intentFilter.addAction(ALARM_TIMEOUT);
2208 intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
2209 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
2210 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
2211 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
2212 intentFilter.addAction(SIM_STATE_CHANGED);
2213 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2215 // register for connectivity change events, this is equivalent to the deprecated way of
2216 // registering for CONNECTIVITY_ACTION broadcasts
2217 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
2218 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
2219 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
2220 NetworkRequest networkRequest = networkRequestBuilder.build();
2221 mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
2223 // listen for PASSIVE_PROVIDER updates
2224 LocationManager locManager =
2225 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
2227 float minDistance = 0;
2228 boolean oneShot = false;
2229 LocationRequest request = LocationRequest.createFromDeprecatedProvider(
2230 LocationManager.PASSIVE_PROVIDER,
2234 // Don't keep track of this request since it's done on behalf of other clients
2235 // (which are kept track of separately).
2236 request.setHideFromAppOps(true);
2237 locManager.requestLocationUpdates(
2239 new NetworkLocationListener(),
2244 private final class NetworkLocationListener implements LocationListener {
2246 public void onLocationChanged(Location location) {
2247 // this callback happens on mHandler looper
2248 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
2249 handleUpdateLocation(location);
2253 public void onStatusChanged(String provider, int status, Bundle extras) { }
2255 public void onProviderEnabled(String provider) { }
2257 public void onProviderDisabled(String provider) { }
2260 private String getSelectedApn() {
2261 Uri uri = Uri.parse("content://telephony/carriers/preferapn");
2262 Cursor cursor = null;
2264 cursor = mContext.getContentResolver().query(
2266 new String[] { "apn" },
2267 null /* selection */,
2268 null /* selectionArgs */,
2269 Carriers.DEFAULT_SORT_ORDER);
2270 if (cursor != null && cursor.moveToFirst()) {
2271 return cursor.getString(0);
2273 Log.e(TAG, "No APN found to select.");
2275 } catch (Exception e) {
2276 Log.e(TAG, "Error encountered on selecting the APN.", e);
2278 if (cursor != null) {
2286 private int getApnIpType(String apn) {
2287 ensureInHandlerThread();
2292 String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
2293 Cursor cursor = null;
2295 cursor = mContext.getContentResolver().query(
2296 Carriers.CONTENT_URI,
2297 new String[] { Carriers.PROTOCOL },
2300 Carriers.DEFAULT_SORT_ORDER);
2302 if (null != cursor && cursor.moveToFirst()) {
2303 return translateToApnIpType(cursor.getString(0), apn);
2305 Log.e(TAG, "No entry found in query for APN: " + apn);
2307 } catch (Exception e) {
2308 Log.e(TAG, "Error encountered on APN query for: " + apn, e);
2310 if (cursor != null) {
2318 private int translateToApnIpType(String ipProtocol, String apn) {
2319 if ("IP".equals(ipProtocol)) {
2322 if ("IPV6".equals(ipProtocol)) {
2325 if ("IPV4V6".equals(ipProtocol)) {
2329 // we hit the default case so the ipProtocol is not recognized
2330 String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
2331 Log.e(TAG, message);
2335 private void setRouting() {
2336 if (mAGpsDataConnectionIpAddr == null) {
2340 // TODO: replace the use of this deprecated API
2341 boolean result = mConnMgr.requestRouteToHostAddress(
2342 ConnectivityManager.TYPE_MOBILE_SUPL,
2343 mAGpsDataConnectionIpAddr);
2346 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
2348 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
2353 * @return {@code true} if there is a data network available for outgoing connections,
2354 * {@code false} otherwise.
2356 private boolean isDataNetworkConnected() {
2357 NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
2358 return activeNetworkInfo != null && activeNetworkInfo.isConnected();
2362 * Ensures the calling function is running in the thread associated with {@link #mHandler}.
2364 private void ensureInHandlerThread() {
2365 if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
2368 throw new RuntimeException("This method must run on the Handler thread.");
2372 * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
2374 private String agpsDataConnStateAsString() {
2375 switch(mAGpsDataConnectionState) {
2376 case AGPS_DATA_CONNECTION_CLOSED:
2378 case AGPS_DATA_CONNECTION_OPEN:
2380 case AGPS_DATA_CONNECTION_OPENING:
2388 * @return A string representing the given GPS_AGPS_DATA status.
2390 private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
2391 switch (agpsDataConnStatus) {
2392 case GPS_AGPS_DATA_CONNECTED:
2394 case GPS_AGPS_DATA_CONN_DONE:
2396 case GPS_AGPS_DATA_CONN_FAILED:
2398 case GPS_RELEASE_AGPS_DATA_CONN:
2400 case GPS_REQUEST_AGPS_DATA_CONN:
2408 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2409 StringBuilder s = new StringBuilder();
2410 s.append(" mFixInterval=").append(mFixInterval).append('\n');
2411 s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
2412 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
2414 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
2415 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
2416 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
2417 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
2418 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
2419 if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
2420 if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
2421 if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
2424 s.append(native_get_internal_state());
2429 * A simple implementation of exponential backoff.
2431 private static final class BackOff {
2432 private static final int MULTIPLIER = 2;
2433 private final long mInitIntervalMillis;
2434 private final long mMaxIntervalMillis;
2435 private long mCurrentIntervalMillis;
2437 public BackOff(long initIntervalMillis, long maxIntervalMillis) {
2438 mInitIntervalMillis = initIntervalMillis;
2439 mMaxIntervalMillis = maxIntervalMillis;
2441 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2444 public long nextBackoffMillis() {
2445 if (mCurrentIntervalMillis > mMaxIntervalMillis) {
2446 return mMaxIntervalMillis;
2449 mCurrentIntervalMillis *= MULTIPLIER;
2450 return mCurrentIntervalMillis;
2453 public void reset() {
2454 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2458 // for GPS SV statistics
2459 private static final int MAX_SVS = 64;
2461 // preallocated arrays, to avoid memory allocation in reportStatus()
2462 private int mSvidWithFlags[] = new int[MAX_SVS];
2463 private float mCn0s[] = new float[MAX_SVS];
2464 private float mSvElevations[] = new float[MAX_SVS];
2465 private float mSvAzimuths[] = new float[MAX_SVS];
2466 private int mSvCount;
2467 // preallocated to avoid memory allocation in reportNmea()
2468 private byte[] mNmeaBuffer = new byte[120];
2470 static { class_init_native(); }
2471 private static native void class_init_native();
2472 private static native boolean native_is_supported();
2473 private static native boolean native_is_agps_ril_supported();
2474 private static native boolean native_is_gnss_configuration_supported();
2476 private native boolean native_init();
2477 private native void native_cleanup();
2478 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
2479 int preferred_accuracy, int preferred_time);
2480 private native boolean native_start();
2481 private native boolean native_stop();
2482 private native void native_delete_aiding_data(int flags);
2483 // returns number of SVs
2484 // mask[0] is ephemeris mask and mask[1] is almanac mask
2485 private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations,
2487 private native int native_read_nmea(byte[] buffer, int bufferSize);
2488 private native void native_inject_location(double latitude, double longitude, float accuracy);
2491 private native void native_inject_time(long time, long timeReference, int uncertainty);
2492 private native boolean native_supports_xtra();
2493 private native void native_inject_xtra_data(byte[] data, int length);
2496 private native String native_get_internal_state();
2499 private native void native_agps_data_conn_open(String apn, int apnIpType);
2500 private native void native_agps_data_conn_closed();
2501 private native void native_agps_data_conn_failed();
2502 private native void native_agps_ni_message(byte [] msg, int length);
2503 private native void native_set_agps_server(int type, String hostname, int port);
2505 // Network-initiated (NI) Support
2506 private native void native_send_ni_response(int notificationId, int userResponse);
2509 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
2511 private native void native_agps_set_id(int type, String setid);
2513 private native void native_update_network_state(boolean connected, int type,
2514 boolean roaming, boolean available, String extraInfo, String defaultAPN);
2516 // Hardware Geofence support.
2517 private static native boolean native_is_geofence_supported();
2518 private static native boolean native_add_geofence(int geofenceId, double latitude,
2519 double longitude, double radius, int lastTransition,int monitorTransitions,
2520 int notificationResponsivenes, int unknownTimer);
2521 private static native boolean native_remove_geofence(int geofenceId);
2522 private static native boolean native_resume_geofence(int geofenceId, int transitions);
2523 private static native boolean native_pause_geofence(int geofenceId);
2525 // Gps Hal measurements support.
2526 private static native boolean native_is_measurement_supported();
2527 private native boolean native_start_measurement_collection();
2528 private native boolean native_stop_measurement_collection();
2530 // Gps Navigation message support.
2531 private static native boolean native_is_navigation_message_supported();
2532 private native boolean native_start_navigation_message_collection();
2533 private native boolean native_stop_navigation_message_collection();
2535 // GNSS Configuration
2536 private static native void native_configuration_update(String configData);