1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17 package com.android.server.location; 18 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; 25 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; 82 83 import java.io.ByteArrayOutputStream; 84 import java.io.File; 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; 96 97 import libcore.io.IoUtils; 98 99 /** 100 * A GPS implementation of LocationProvider used by LocationManager. 101 * 102 * {@hide} 103 */ 104 public class GnssLocationProvider implements LocationProviderInterface { 105 106 private static final String TAG = "GnssLocationProvider"; 107 108 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 109 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 110 111 private static final ProviderProperties PROPERTIES = new ProviderProperties( 112 true, true, false, false, true, true, true, 113 Criteria.POWER_HIGH, Criteria.ACCURACY_FINE); 114 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; 119 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; 123 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; 130 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; 138 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; 146 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; 161 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; 171 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; 175 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; 179 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; 185 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; 190 191 // Handler messages 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; 207 208 // Request setid 209 private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1; 210 private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2; 211 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; 215 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; 220 221 // set id info 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; 225 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; 229 230 private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L; 231 private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L; 232 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; 240 241 // TCP/IP constants. 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; 245 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"; 253 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; 261 } 262 } 263 264 private Object mLock = new Object(); 265 266 private int mLocationFlags = LOCATION_INVALID; 267 268 // current status 269 private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE; 270 271 // time for last status update 272 private long mStatusUpdateTime = SystemClock.elapsedRealtime(); 273 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; 276 277 // stop trying if we do not receive a fix within 60 seconds 278 private static final int NO_FIX_TIMEOUT = 60 * 1000; 279 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; 284 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; 296 297 private BackOff mNtpBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL); 298 private BackOff mXtraBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL); 299 300 // true if we are enabled, protected by this 301 private boolean mEnabled; 302 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; 307 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; 312 313 // set to true if the GPS engine requested on-demand NTP time requests 314 private boolean mOnDemandTimeInjection; 315 316 // true if GPS is navigating 317 private boolean mNavigating; 318 319 // true if GPS engine is on 320 private boolean mEngineOn; 321 322 // requested frequency of fixes, in milliseconds 323 private int mFixInterval = 1000; 324 325 // true if we started navigation 326 private boolean mStarted; 327 328 // true if single shot request is in progress 329 private boolean mSingleShot; 330 331 // capabilities of the GPS engine 332 private int mEngineCapabilities; 333 334 // true if XTRA is supported 335 private boolean mSupportsXtra; 336 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; 343 344 private int mPositionMode; 345 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; 352 353 /** 354 * Properties loaded from PROPERTIES_FILE. 355 * It must be accessed only inside {@link #mHandler}. 356 */ 357 private Properties mProperties; 358 359 private String mSuplServerHost; 360 private int mSuplServerPort = TCP_MIN_PORT; 361 private String mC2KServerHost; 362 private int mC2KServerPort; 363 private boolean mSuplEsEnabled = false; 364 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; 373 374 // Handler for processing events 375 private Handler mHandler; 376 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; 381 382 private final ConnectivityManager mConnMgr; 383 private final GpsNetInitiatedHandler mNIHandler; 384 385 // Wakelocks 386 private final static String WAKELOCK_KEY = "GnssLocationProvider"; 387 private final PowerManager.WakeLock mWakeLock; 388 389 // Alarms 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"; 392 393 // SIM/Carrier info. 394 private final static String SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED"; 395 396 // Persist property for LPP_PROFILE 397 private final static String LPP_PROFILE = "persist.sys.gps.lpp"; 398 399 // VZW PLMN info 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"}; 403 404 405 private final PowerManager mPowerManager; 406 private final AlarmManager mAlarmManager; 407 private final PendingIntent mWakeupIntent; 408 private final PendingIntent mTimeoutIntent; 409 410 private final IAppOpsService mAppOpsService; 411 private final IBatteryStats mBatteryStats; 412 413 // only modified on handler thread 414 private WorkSource mClientSource = new WorkSource(); 415 416 private GeofenceHardwareImpl mGeofenceHardwareImpl; 417 418 private int mYearOfHardware = 0; 419 420 private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() { 421 @Override 422 public void registerGnssStatusCallback(IGnssStatusListener callback) { 423 mListenerHelper.addListener(callback); 424 } 425 426 @Override 427 public void unregisterGnssStatusCallback(IGnssStatusListener callback) { 428 mListenerHelper.removeListener(callback); 429 } 430 }; 431 432 public IGnssStatusProvider getGnssStatusProvider() { 433 return mGnssStatusProvider; 434 } 435 436 public IGpsGeofenceHardware getGpsGeofenceProxy() { 437 return mGpsGeofenceBinder; 438 } 439 440 public GnssMeasurementsProvider getGnssMeasurementsProvider() { 441 return mGnssMeasurementsProvider; 442 } 443 444 public GnssNavigationMessageProvider getGnssNavigationMessageProvider() { 445 return mGnssNavigationMessageProvider; 446 } 447 448 /** 449 * Callback used to listen for data connectivity changes. 450 */ 451 private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback = 452 new ConnectivityManager.NetworkCallback() { 453 @Override 454 public void onAvailable(Network network) { 455 if (mInjectNtpTimePending == STATE_PENDING_NETWORK) { 456 requestUtcTime(); 457 } 458 if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) { 459 xtraDownloadRequest(); 460 } 461 } 462 }; 463 464 /** 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. 468 */ 469 private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback = 470 new ConnectivityManager.NetworkCallback() { 471 @Override 472 public void onAvailable(Network network) { 473 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network); 474 } 475 476 @Override 477 public void onLost(Network network) { 478 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN); 479 } 480 481 @Override 482 public void onUnavailable() { 483 // timeout, it was not possible to establish the required connection 484 releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED); 485 } 486 }; 487 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) { 493 return; 494 } 495 496 if (action.equals(ALARM_WAKEUP)) { 497 startNavigating(false); 498 } else if (action.equals(ALARM_TIMEOUT)) { 499 hibernate(); 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); 511 } 512 } 513 }; 514 515 private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener = 516 new OnSubscriptionsChangedListener() { 517 @Override 518 public void onSubscriptionsChanged() { 519 sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null); 520 } 521 }; 522 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"); 532 return true; 533 } 534 } 535 } 536 } 537 return false; 538 } 539 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); 556 } else { 557 // reset the persist property for Non VZW 558 SystemProperties.set(LPP_PROFILE, ""); 559 } 560 reloadGpsProperties(context, mProperties); 561 mNIHandler.setSuplEsEnabled(mSuplEsEnabled); 562 } 563 } else { 564 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available"); 565 } 566 } 567 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."); 572 return; 573 } 574 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); 580 } 581 } 582 } 583 } 584 585 private void checkWapSuplInit(Intent intent) { 586 byte[] suplInit = intent.getByteArrayExtra("data"); 587 if (suplInit == null) { 588 return; 589 } 590 native_agps_ni_message(suplInit,suplInit.length); 591 } 592 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(); 601 break; 602 } 603 if (disableGps != mDisableGps) { 604 mDisableGps = disableGps; 605 updateRequirements(); 606 } 607 } 608 609 public static boolean isSupported() { 610 return native_is_supported(); 611 } 612 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); 616 617 boolean isPropertiesLoadedFromFile = false; 618 final String gpsHardware = SystemProperties.get("ro.hardware.gps"); 619 620 if (!TextUtils.isEmpty(gpsHardware)) { 621 final String propFilename = 622 PROPERTIES_FILE_PREFIX + "." + gpsHardware + PROPERTIES_FILE_SUFFIX; 623 isPropertiesLoadedFromFile = 624 loadPropertiesFromFile(propFilename, properties); 625 } 626 if (!isPropertiesLoadedFromFile) { 627 loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties); 628 } 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); 634 } 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) { 641 try { 642 mC2KServerPort = Integer.parseInt(portString); 643 } catch (NumberFormatException e) { 644 Log.e(TAG, "unable to parse C2K_PORT: " + portString); 645 } 646 } 647 648 if (native_is_gnss_configuration_supported()) { 649 try { 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"); 657 } 658 } else if (DEBUG) { 659 Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not" 660 + " supported"); 661 } 662 663 // SUPL_ES configuration. 664 String suplESProperty = mProperties.getProperty("SUPL_ES"); 665 if (suplESProperty != null) { 666 try { 667 mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1); 668 } catch (NumberFormatException e) { 669 Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty); 670 } 671 } 672 } 673 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]); 684 } else { 685 Log.w(TAG, "malformed contents: " + item); 686 } 687 } 688 } 689 690 private boolean loadPropertiesFromFile(String filename, 691 Properties properties) { 692 try { 693 File file = new File(filename); 694 FileInputStream stream = null; 695 try { 696 stream = new FileInputStream(file); 697 properties.load(stream); 698 } finally { 699 IoUtils.closeQuietly(stream); 700 } 701 702 } catch (IOException e) { 703 Log.w(TAG, "Could not open GPS configuration file " + filename); 704 return false; 705 } 706 return true; 707 } 708 709 public GnssLocationProvider(Context context, ILocationManager ilocationManager, 710 Looper looper) { 711 mContext = context; 712 mNtpTime = NtpTrustedTime.getInstance(context); 713 mILocationManager = ilocationManager; 714 715 mLocation.setExtras(mLocationExtras); 716 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); 721 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); 725 726 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); 727 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)); 731 732 // Battery statistics service to be notified when GPS turns on or off 733 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 734 BatteryStats.SERVICE_NAME)); 735 736 // Construct internal handler 737 mHandler = new ProviderHandler(looper); 738 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); 746 747 // Create a GPS net-initiated handler. 748 mNIHandler = new GpsNetInitiatedHandler(context, 749 mNetInitiatedListener, 750 mSuplEsEnabled); 751 752 mListenerHelper = new GnssStatusListenerHelper(mHandler) { 753 @Override 754 protected boolean isAvailableInPlatform() { 755 return isSupported(); 756 } 757 758 @Override 759 protected boolean isGpsEnabled() { 760 return isEnabled(); 761 } 762 }; 763 764 mGnssMeasurementsProvider = new GnssMeasurementsProvider(mHandler) { 765 @Override 766 public boolean isAvailableInPlatform() { 767 return native_is_measurement_supported(); 768 } 769 770 @Override 771 protected boolean registerWithService() { 772 return native_start_measurement_collection(); 773 } 774 775 @Override 776 protected void unregisterFromService() { 777 native_stop_measurement_collection(); 778 } 779 780 @Override 781 protected boolean isGpsEnabled() { 782 return isEnabled(); 783 } 784 }; 785 786 mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) { 787 @Override 788 protected boolean isAvailableInPlatform() { 789 return native_is_navigation_message_supported(); 790 } 791 792 @Override 793 protected boolean registerWithService() { 794 return native_start_navigation_message_collection(); 795 } 796 797 @Override 798 protected void unregisterFromService() { 799 native_stop_navigation_message_collection(); 800 } 801 802 @Override 803 protected boolean isGpsEnabled() { 804 return isEnabled(); 805 } 806 }; 807 } 808 809 /** 810 * Returns the name of this provider. 811 */ 812 @Override 813 public String getName() { 814 return LocationManager.GPS_PROVIDER; 815 } 816 817 @Override 818 public ProviderProperties getProperties() { 819 return PROPERTIES; 820 } 821 822 private void handleUpdateNetworkState(Network network) { 823 // retrieve NetworkInfo for this UID 824 NetworkInfo info = mConnMgr.getNetworkInfo(network); 825 if (info == null) { 826 return; 827 } 828 829 boolean isConnected = info.isConnected(); 830 if (DEBUG) { 831 String message = String.format( 832 "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S", 833 agpsDataConnStateAsString(), 834 isConnected, 835 info, 836 mConnMgr.getNetworkCapabilities(network)); 837 Log.d(TAG, message); 838 } 839 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"; 846 } 847 848 native_update_network_state( 849 isConnected, 850 info.getType(), 851 info.isRoaming(), 852 networkAvailable, 853 info.getExtraInfo(), 854 defaultApn); 855 } else if (DEBUG) { 856 Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported"); 857 } 858 859 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { 860 if (isConnected) { 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"; 866 } 867 int apnIpType = getApnIpType(apnName); 868 setRouting(); 869 if (DEBUG) { 870 String message = String.format( 871 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s", 872 apnName, 873 apnIpType); 874 Log.d(TAG, message); 875 } 876 native_agps_data_conn_open(apnName, apnIpType); 877 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 878 } else { 879 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED); 880 } 881 } 882 } 883 884 private void handleRequestSuplConnection(InetAddress address) { 885 if (DEBUG) { 886 String message = String.format( 887 "requestSuplConnection, state=%s, address=%s", 888 agpsDataConnStateAsString(), 889 address); 890 Log.d(TAG, message); 891 } 892 893 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) { 894 return; 895 } 896 mAGpsDataConnectionIpAddr = address; 897 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; 898 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( 904 request, 905 mSuplConnectivityCallback, 906 ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS); 907 } 908 909 private void handleReleaseSuplConnection(int agpsDataConnStatus) { 910 if (DEBUG) { 911 String message = String.format( 912 "releaseSuplConnection, state=%s, status=%s", 913 agpsDataConnStateAsString(), 914 agpsDataConnStatusAsString(agpsDataConnStatus)); 915 Log.d(TAG, message); 916 } 917 918 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) { 919 return; 920 } 921 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 922 923 mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback); 924 switch (agpsDataConnStatus) { 925 case GPS_AGPS_DATA_CONN_FAILED: 926 native_agps_data_conn_failed(); 927 break; 928 case GPS_RELEASE_AGPS_DATA_CONN: 929 native_agps_data_conn_closed(); 930 break; 931 default: 932 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus); 933 } 934 } 935 936 private void handleInjectNtpTime() { 937 if (mInjectNtpTimePending == STATE_DOWNLOADING) { 938 // already downloading data 939 return; 940 } 941 if (!isDataNetworkConnected()) { 942 // try again when network is up 943 mInjectNtpTimePending = STATE_PENDING_NETWORK; 944 return; 945 } 946 mInjectNtpTimePending = STATE_DOWNLOADING; 947 948 // hold wake lock while task runs 949 mWakeLock.acquire(); 950 Log.i(TAG, "WakeLock acquired by handleInjectNtpTime()"); 951 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { 952 @Override 953 public void run() { 954 long delay; 955 956 // force refresh NTP cache when outdated 957 boolean refreshSuccess = true; 958 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) { 959 refreshSuccess = mNtpTime.forceRefresh(); 960 } 961 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(); 968 969 if (DEBUG) { 970 Log.d(TAG, "NTP server returned: " 971 + time + " (" + new Date(time) 972 + ") reference: " + timeReference 973 + " certainty: " + certainty 974 + " system time offset: " + (time - now)); 975 } 976 977 native_inject_time(time, timeReference, (int) certainty); 978 delay = NTP_INTERVAL; 979 mNtpBackOff.reset(); 980 } else { 981 Log.e(TAG, "requestTime failed"); 982 delay = mNtpBackOff.nextBackoffMillis(); 983 } 984 985 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null); 986 987 if (DEBUG) { 988 String message = String.format( 989 "onDemandTimeInjection=%s, refreshSuccess=%s, delay=%s", 990 mOnDemandTimeInjection, 991 refreshSuccess, 992 delay); 993 Log.d(TAG, message); 994 } 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); 999 } 1000 1001 // release wake lock held by task 1002 mWakeLock.release(); 1003 Log.i(TAG, "WakeLock released by handleInjectNtpTime()"); 1004 } 1005 }); 1006 } 1007 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"); 1012 return; 1013 } 1014 if (mDownloadXtraDataPending == STATE_DOWNLOADING) { 1015 // already downloading data 1016 return; 1017 } 1018 if (!isDataNetworkConnected()) { 1019 // try again when network is up 1020 mDownloadXtraDataPending = STATE_PENDING_NETWORK; 1021 return; 1022 } 1023 mDownloadXtraDataPending = STATE_DOWNLOADING; 1024 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() { 1029 @Override 1030 public void run() { 1031 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties); 1032 byte[] data = xtraDownloader.downloadXtraData(); 1033 if (data != null) { 1034 if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data"); 1035 native_inject_xtra_data(data, data.length); 1036 mXtraBackOff.reset(); 1037 } 1038 1039 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null); 1040 1041 if (data == null) { 1042 // try again later 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()); 1046 } 1047 1048 // release wake lock held by task 1049 mWakeLock.release(); 1050 Log.i(TAG, "WakeLock released by handleDownloadXtraData()"); 1051 } 1052 }); 1053 } 1054 1055 private void handleUpdateLocation(Location location) { 1056 if (location.hasAccuracy()) { 1057 native_inject_location(location.getLatitude(), location.getLongitude(), 1058 location.getAccuracy()); 1059 } 1060 } 1061 1062 /** 1063 * Enables this provider. When enabled, calls to getStatus() 1064 * must be handled. Hardware may be started up 1065 * when the provider is enabled. 1066 */ 1067 @Override 1068 public void enable() { 1069 synchronized (mLock) { 1070 if (mEnabled) return; 1071 mEnabled = true; 1072 } 1073 1074 sendMessage(ENABLE, 1, null); 1075 } 1076 1077 private void setSuplHostPort(String hostString, String portString) { 1078 if (hostString != null) { 1079 mSuplServerHost = hostString; 1080 } 1081 if (portString != null) { 1082 try { 1083 mSuplServerPort = Integer.parseInt(portString); 1084 } catch (NumberFormatException e) { 1085 Log.e(TAG, "unable to parse SUPL_PORT: " + portString); 1086 } 1087 } 1088 if (mSuplServerHost != null 1089 && mSuplServerPort > TCP_MIN_PORT 1090 && mSuplServerPort <= TCP_MAX_PORT) { 1091 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); 1092 } 1093 } 1094 1095 /** 1096 * Checks what SUPL mode to use, according to the AGPS mode as well as the 1097 * allowed mode from properties. 1098 * 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) 1103 */ 1104 private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) { 1105 if (agpsEnabled) { 1106 String modeString = properties.getProperty("SUPL_MODE"); 1107 int suplMode = 0; 1108 if (!TextUtils.isEmpty(modeString)) { 1109 try { 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; 1114 } 1115 } 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; 1120 } 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 1124 if (singleShot 1125 && hasCapability(GPS_CAPABILITY_MSA) 1126 && (suplMode & AGPS_SUPL_MODE_MSA) != 0) { 1127 return GPS_POSITION_MODE_MS_ASSISTED; 1128 } 1129 } 1130 return GPS_POSITION_MODE_STANDALONE; 1131 } 1132 1133 private void handleEnable() { 1134 if (DEBUG) Log.d(TAG, "handleEnable"); 1135 1136 boolean enabled = native_init(); 1137 1138 if (enabled) { 1139 mSupportsXtra = native_supports_xtra(); 1140 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); 1144 } 1145 if (mC2KServerHost != null) { 1146 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort); 1147 } 1148 1149 mGnssMeasurementsProvider.onGpsEnabledChanged(); 1150 mGnssNavigationMessageProvider.onGpsEnabledChanged(); 1151 } else { 1152 synchronized (mLock) { 1153 mEnabled = false; 1154 } 1155 Log.w(TAG, "Failed to enable location provider"); 1156 } 1157 } 1158 1159 /** 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. 1163 */ 1164 @Override 1165 public void disable() { 1166 synchronized (mLock) { 1167 if (!mEnabled) return; 1168 mEnabled = false; 1169 } 1170 1171 sendMessage(ENABLE, 0, null); 1172 } 1173 1174 private void handleDisable() { 1175 if (DEBUG) Log.d(TAG, "handleDisable"); 1176 1177 updateClientUids(new WorkSource()); 1178 stopNavigating(); 1179 mAlarmManager.cancel(mWakeupIntent); 1180 mAlarmManager.cancel(mTimeoutIntent); 1181 1182 // do this before releasing wakelock 1183 native_cleanup(); 1184 1185 mGnssMeasurementsProvider.onGpsEnabledChanged(); 1186 mGnssNavigationMessageProvider.onGpsEnabledChanged(); 1187 } 1188 1189 @Override 1190 public boolean isEnabled() { 1191 synchronized (mLock) { 1192 return mEnabled; 1193 } 1194 } 1195 1196 @Override 1197 public int getStatus(Bundle extras) { 1198 if (extras != null) { 1199 extras.putInt("satellites", mSvCount); 1200 } 1201 return mStatus; 1202 } 1203 1204 private void updateStatus(int status, int svCount) { 1205 if (status != mStatus || svCount != mSvCount) { 1206 mStatus = status; 1207 mSvCount = svCount; 1208 mLocationExtras.putInt("satellites", svCount); 1209 mStatusUpdateTime = SystemClock.elapsedRealtime(); 1210 } 1211 } 1212 1213 @Override 1214 public long getStatusUpdateTime() { 1215 return mStatusUpdateTime; 1216 } 1217 1218 @Override 1219 public void setRequest(ProviderRequest request, WorkSource source) { 1220 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source)); 1221 } 1222 1223 private void handleSetRequest(ProviderRequest request, WorkSource source) { 1224 mProviderRequest = request; 1225 mWorkSource = source; 1226 updateRequirements(); 1227 } 1228 1229 // Called when the requirements for GPS may have changed 1230 private void updateRequirements() { 1231 if (mProviderRequest == null || mWorkSource == null) { 1232 return; 1233 } 1234 1235 boolean singleShot = false; 1236 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 1242 singleShot = true; 1243 1244 for (LocationRequest lr : mProviderRequest.locationRequests) { 1245 if (lr.getNumUpdates() != 1) { 1246 singleShot = false; 1247 } 1248 } 1249 } 1250 1251 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest); 1252 if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) { 1253 // update client uids 1254 updateClientUids(mWorkSource); 1255 1256 mFixInterval = (int) mProviderRequest.interval; 1257 1258 // check for overflow 1259 if (mFixInterval != mProviderRequest.interval) { 1260 Log.w(TAG, "interval overflow: " + mProviderRequest.interval); 1261 mFixInterval = Integer.MAX_VALUE; 1262 } 1263 1264 // apply request to GPS engine 1265 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) { 1266 // change period 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()"); 1270 } 1271 } else if (!mStarted) { 1272 // start GPS 1273 startNavigating(singleShot); 1274 } 1275 } else { 1276 updateClientUids(new WorkSource()); 1277 1278 stopNavigating(); 1279 mAlarmManager.cancel(mWakeupIntent); 1280 mAlarmManager.cancel(mTimeoutIntent); 1281 } 1282 } 1283 1284 private void updateClientUids(WorkSource source) { 1285 // Update work source. 1286 WorkSource[] changes = mClientSource.setReturningDiffs(source); 1287 if (changes == null) { 1288 return; 1289 } 1290 WorkSource newWork = changes[0]; 1291 WorkSource goneWork = changes[1]; 1292 1293 // Update sources that were not previously tracked. 1294 if (newWork != null) { 1295 int lastuid = -1; 1296 for (int i=0; i<newWork.size(); i++) { 1297 try { 1298 int uid = newWork.get(i); 1299 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), 1300 AppOpsManager.OP_GPS, uid, newWork.getName(i)); 1301 if (uid != lastuid) { 1302 lastuid = uid; 1303 mBatteryStats.noteStartGps(uid); 1304 } 1305 } catch (RemoteException e) { 1306 Log.w(TAG, "RemoteException", e); 1307 } 1308 } 1309 } 1310 1311 // Update sources that are no longer tracked. 1312 if (goneWork != null) { 1313 int lastuid = -1; 1314 for (int i=0; i<goneWork.size(); i++) { 1315 try { 1316 int uid = goneWork.get(i); 1317 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), 1318 AppOpsManager.OP_GPS, uid, goneWork.getName(i)); 1319 if (uid != lastuid) { 1320 lastuid = uid; 1321 mBatteryStats.noteStopGps(uid); 1322 } 1323 } catch (RemoteException e) { 1324 Log.w(TAG, "RemoteException", e); 1325 } 1326 } 1327 } 1328 } 1329 1330 @Override 1331 public boolean sendExtraCommand(String command, Bundle extras) { 1332 1333 long identity = Binder.clearCallingIdentity(); 1334 boolean result = false; 1335 1336 if ("delete_aiding_data".equals(command)) { 1337 result = deleteAidingData(extras); 1338 } else if ("force_time_injection".equals(command)) { 1339 requestUtcTime(); 1340 result = true; 1341 } else if ("force_xtra_injection".equals(command)) { 1342 if (mSupportsXtra) { 1343 xtraDownloadRequest(); 1344 result = true; 1345 } 1346 } else { 1347 Log.w(TAG, "sendExtraCommand: unknown command " + command); 1348 } 1349 1350 Binder.restoreCallingIdentity(identity); 1351 return result; 1352 } 1353 1354 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() { 1355 public boolean isHardwareGeofenceSupported() { 1356 return native_is_geofence_supported(); 1357 } 1358 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); 1364 } 1365 1366 public boolean removeHardwareGeofence(int geofenceId) { 1367 return native_remove_geofence(geofenceId); 1368 } 1369 1370 public boolean pauseHardwareGeofence(int geofenceId) { 1371 return native_pause_geofence(geofenceId); 1372 } 1373 1374 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) { 1375 return native_resume_geofence(geofenceId, monitorTransition); 1376 } 1377 }; 1378 1379 private boolean deleteAidingData(Bundle extras) { 1380 int flags; 1381 1382 if (extras == null) { 1383 flags = GPS_DELETE_ALL; 1384 } else { 1385 flags = 0; 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; 1399 } 1400 1401 if (flags != 0) { 1402 native_delete_aiding_data(flags); 1403 return true; 1404 } 1405 1406 return false; 1407 } 1408 1409 private void startNavigating(boolean singleShot) { 1410 if (!mStarted) { 1411 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot); 1412 mTimeToFirstFix = 0; 1413 mLastFixTime = 0; 1414 mStarted = true; 1415 mSingleShot = singleShot; 1416 mPositionMode = GPS_POSITION_MODE_STANDALONE; 1417 1418 boolean agpsEnabled = 1419 (Settings.Global.getInt(mContext.getContentResolver(), 1420 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0); 1421 mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot); 1422 1423 if (DEBUG) { 1424 String mode; 1425 1426 switch(mPositionMode) { 1427 case GPS_POSITION_MODE_STANDALONE: 1428 mode = "standalone"; 1429 break; 1430 case GPS_POSITION_MODE_MS_ASSISTED: 1431 mode = "MS_ASSISTED"; 1432 break; 1433 case GPS_POSITION_MODE_MS_BASED: 1434 mode = "MS_BASED"; 1435 break; 1436 default: 1437 mode = "unknown"; 1438 break; 1439 } 1440 Log.d(TAG, "setting position_mode to " + mode); 1441 } 1442 1443 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000); 1444 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 1445 interval, 0, 0)) { 1446 mStarted = false; 1447 Log.e(TAG, "set_position_mode failed in startNavigating()"); 1448 return; 1449 } 1450 if (!native_start()) { 1451 mStarted = false; 1452 Log.e(TAG, "native_start failed in startNavigating()"); 1453 return; 1454 } 1455 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); 1465 } 1466 } 1467 } 1468 } 1469 1470 private void stopNavigating() { 1471 if (DEBUG) Log.d(TAG, "stopNavigating"); 1472 if (mStarted) { 1473 mStarted = false; 1474 mSingleShot = false; 1475 native_stop(); 1476 mTimeToFirstFix = 0; 1477 mLastFixTime = 0; 1478 mLocationFlags = LOCATION_INVALID; 1479 1480 // reset SV count to zero 1481 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); 1482 } 1483 } 1484 1485 private void hibernate() { 1486 // stop GPS until our next fix interval arrives 1487 stopNavigating(); 1488 mAlarmManager.cancel(mTimeoutIntent); 1489 mAlarmManager.cancel(mWakeupIntent); 1490 long now = SystemClock.elapsedRealtime(); 1491 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent); 1492 } 1493 1494 private boolean hasCapability(int capability) { 1495 return ((mEngineCapabilities & capability) != 0); 1496 } 1497 1498 1499 /** 1500 * called from native code to update our position. 1501 */ 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); 1506 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()); 1516 } 1517 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { 1518 mLocation.setAltitude(altitude); 1519 } else { 1520 mLocation.removeAltitude(); 1521 } 1522 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { 1523 mLocation.setSpeed(speed); 1524 } else { 1525 mLocation.removeSpeed(); 1526 } 1527 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { 1528 mLocation.setBearing(bearing); 1529 } else { 1530 mLocation.removeBearing(); 1531 } 1532 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { 1533 mLocation.setAccuracy(accuracy); 1534 } else { 1535 mLocation.removeAccuracy(); 1536 } 1537 mLocation.setExtras(mLocationExtras); 1538 1539 try { 1540 mILocationManager.reportLocation(mLocation, false); 1541 } catch (RemoteException e) { 1542 Log.e(TAG, "RemoteException calling reportLocation"); 1543 } 1544 } 1545 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); 1551 1552 // notify status listeners 1553 mListenerHelper.onFirstFix(mTimeToFirstFix); 1554 } 1555 1556 if (mSingleShot) { 1557 stopNavigating(); 1558 } 1559 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); 1565 } 1566 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); 1572 } 1573 1574 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted && 1575 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { 1576 if (DEBUG) Log.d(TAG, "got fix, hibernating"); 1577 hibernate(); 1578 } 1579 } 1580 1581 /** 1582 * called from native code to update our status 1583 */ 1584 private void reportStatus(int status) { 1585 if (DEBUG) Log.v(TAG, "reportStatus status: " + status); 1586 1587 boolean wasNavigating = mNavigating; 1588 switch (status) { 1589 case GPS_STATUS_SESSION_BEGIN: 1590 mNavigating = true; 1591 mEngineOn = true; 1592 break; 1593 case GPS_STATUS_SESSION_END: 1594 mNavigating = false; 1595 break; 1596 case GPS_STATUS_ENGINE_ON: 1597 mEngineOn = true; 1598 break; 1599 case GPS_STATUS_ENGINE_OFF: 1600 mEngineOn = false; 1601 mNavigating = false; 1602 break; 1603 } 1604 1605 if (wasNavigating != mNavigating) { 1606 mListenerHelper.onStatusChanged(mNavigating); 1607 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); 1612 } 1613 } 1614 1615 /** 1616 * called from native code to update SV info 1617 */ 1618 private void reportSvStatus() { 1619 int svCount = native_read_sv_status(mSvidWithFlags, mCn0s, mSvElevations, mSvAzimuths); 1620 mListenerHelper.onSvStatusChanged( 1621 svCount, 1622 mSvidWithFlags, 1623 mCn0s, 1624 mSvElevations, 1625 mSvAzimuths); 1626 1627 if (VERBOSE) { 1628 Log.v(TAG, "SV count: " + svCount); 1629 } 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) { 1634 ++usedInFixCount; 1635 } 1636 if (VERBOSE) { 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 1642 ? " " : " E") + 1643 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0 1644 ? " " : " A") + 1645 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0 1646 ? "" : "U")); 1647 } 1648 } 1649 // return number of sets used in fix instead of total 1650 updateStatus(mStatus, usedInFixCount); 1651 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); 1659 } 1660 } 1661 1662 /** 1663 * called from native code to update AGPS status 1664 */ 1665 private void reportAGpsStatus(int type, int status, byte[] ipaddr) { 1666 switch (status) { 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) { 1672 try { 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); 1677 } 1678 } 1679 sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress); 1680 break; 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); 1684 break; 1685 case GPS_AGPS_DATA_CONNECTED: 1686 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED"); 1687 break; 1688 case GPS_AGPS_DATA_CONN_DONE: 1689 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE"); 1690 break; 1691 case GPS_AGPS_DATA_CONN_FAILED: 1692 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED"); 1693 break; 1694 default: 1695 if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status); 1696 } 1697 } 1698 1699 private void releaseSuplConnection(int connStatus) { 1700 sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/); 1701 } 1702 1703 /** 1704 * called from native code to report NMEA data received 1705 */ 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); 1710 } 1711 1712 /** 1713 * called from native code - Gps measurements callback 1714 */ 1715 private void reportMeasurementData(GnssMeasurementsEvent event) { 1716 mGnssMeasurementsProvider.onMeasurementsAvailable(event); 1717 } 1718 1719 /** 1720 * called from native code - GPS navigation message callback 1721 */ 1722 private void reportNavigationMessage(GnssNavigationMessage event) { 1723 mGnssNavigationMessageProvider.onNavigationMessageAvailable(event); 1724 } 1725 1726 /** 1727 * called from native code to inform us what the GPS engine capabilities are 1728 */ 1729 private void setEngineCapabilities(int capabilities) { 1730 mEngineCapabilities = capabilities; 1731 1732 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) { 1733 mOnDemandTimeInjection = true; 1734 requestUtcTime(); 1735 } 1736 1737 mGnssMeasurementsProvider.onCapabilitiesUpdated( 1738 (capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS); 1739 mGnssNavigationMessageProvider.onCapabilitiesUpdated( 1740 (capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES); 1741 } 1742 1743 /** 1744 * Called from native code to inform us the hardware information. 1745 */ 1746 private void setGnssYearOfHardware(int yearOfHardware) { 1747 if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware); 1748 mYearOfHardware = yearOfHardware; 1749 } 1750 1751 public interface GnssSystemInfoProvider { 1752 /** 1753 * Returns the year of GPS hardware. 1754 */ 1755 int getGnssYearOfHardware(); 1756 } 1757 1758 /** 1759 * @hide 1760 */ 1761 public GnssSystemInfoProvider getGnssSystemInfoProvider() { 1762 return new GnssSystemInfoProvider() { 1763 @Override 1764 public int getGnssYearOfHardware() { 1765 return mYearOfHardware; 1766 } 1767 }; 1768 } 1769 1770 /** 1771 * called from native code to request XTRA data 1772 */ 1773 private void xtraDownloadRequest() { 1774 if (DEBUG) Log.d(TAG, "xtraDownloadRequest"); 1775 sendMessage(DOWNLOAD_XTRA_DATA, 0, null); 1776 } 1777 1778 /** 1779 * Helper method to construct a location object. 1780 */ 1781 private Location buildLocation( 1782 int flags, 1783 double latitude, 1784 double longitude, 1785 double altitude, 1786 float speed, 1787 float bearing, 1788 float accuracy, 1789 long timestamp) { 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()); 1796 } 1797 if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { 1798 location.setAltitude(altitude); 1799 } 1800 if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { 1801 location.setSpeed(speed); 1802 } 1803 if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { 1804 location.setBearing(bearing); 1805 } 1806 if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { 1807 location.setAccuracy(accuracy); 1808 } 1809 return location; 1810 } 1811 1812 /** 1813 * Converts the GPS HAL status to the internal Geofence Hardware status. 1814 */ 1815 private int getGeofenceStatus(int status) { 1816 switch(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; 1829 default: 1830 return -1; 1831 } 1832 } 1833 1834 /** 1835 * Called from native to report GPS Geofence transition 1836 * All geofence callbacks are called on the same thread 1837 */ 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); 1843 } 1844 Location location = buildLocation( 1845 flags, 1846 latitude, 1847 longitude, 1848 altitude, 1849 speed, 1850 bearing, 1851 accuracy, 1852 timestamp); 1853 mGeofenceHardwareImpl.reportGeofenceTransition( 1854 geofenceId, 1855 location, 1856 transition, 1857 transitionTimestamp, 1858 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 1859 FusedBatchOptions.SourceTechnologies.GNSS); 1860 } 1861 1862 /** 1863 * called from native code to report GPS status change. 1864 */ 1865 private void reportGeofenceStatus(int status, int flags, double latitude, 1866 double longitude, double altitude, float speed, float bearing, float accuracy, 1867 long timestamp) { 1868 if (mGeofenceHardwareImpl == null) { 1869 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1870 } 1871 Location location = buildLocation( 1872 flags, 1873 latitude, 1874 longitude, 1875 altitude, 1876 speed, 1877 bearing, 1878 accuracy, 1879 timestamp); 1880 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; 1881 if(status == GPS_GEOFENCE_AVAILABLE) { 1882 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; 1883 } 1884 mGeofenceHardwareImpl.reportGeofenceMonitorStatus( 1885 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 1886 monitorStatus, 1887 location, 1888 FusedBatchOptions.SourceTechnologies.GNSS); 1889 } 1890 1891 /** 1892 * called from native code - Geofence Add callback 1893 */ 1894 private void reportGeofenceAddStatus(int geofenceId, int status) { 1895 if (mGeofenceHardwareImpl == null) { 1896 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1897 } 1898 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status)); 1899 } 1900 1901 /** 1902 * called from native code - Geofence Remove callback 1903 */ 1904 private void reportGeofenceRemoveStatus(int geofenceId, int status) { 1905 if (mGeofenceHardwareImpl == null) { 1906 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1907 } 1908 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status)); 1909 } 1910 1911 /** 1912 * called from native code - Geofence Pause callback 1913 */ 1914 private void reportGeofencePauseStatus(int geofenceId, int status) { 1915 if (mGeofenceHardwareImpl == null) { 1916 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1917 } 1918 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status)); 1919 } 1920 1921 /** 1922 * called from native code - Geofence Resume callback 1923 */ 1924 private void reportGeofenceResumeStatus(int geofenceId, int status) { 1925 if (mGeofenceHardwareImpl == null) { 1926 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1927 } 1928 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status)); 1929 } 1930 1931 //============================================================= 1932 // NI Client support 1933 //============================================================= 1934 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() { 1935 // Sends a response for an NI request to HAL. 1936 @Override 1937 public boolean sendNiResponse(int notificationId, int userResponse) 1938 { 1939 // TODO Add Permission check 1940 1941 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId + 1942 ", response: " + userResponse); 1943 native_send_ni_response(notificationId, userResponse); 1944 return true; 1945 } 1946 }; 1947 1948 public INetInitiatedListener getNetInitiatedListener() { 1949 return mNetInitiatedListener; 1950 } 1951 1952 // Called by JNI function to report an NI request. 1953 public void reportNiNotification( 1954 int notificationId, 1955 int niType, 1956 int notifyFlags, 1957 int timeout, 1958 int defaultResponse, 1959 String requestorId, 1960 String text, 1961 int requestorIdEncoding, 1962 int textEncoding, 1963 String extras // Encoded extra data 1964 ) 1965 { 1966 Log.i(TAG, "reportNiNotification: entered"); 1967 Log.i(TAG, "notificationId: " + notificationId + 1968 ", niType: " + niType + 1969 ", notifyFlags: " + notifyFlags + 1970 ", timeout: " + timeout + 1971 ", defaultResponse: " + defaultResponse); 1972 1973 Log.i(TAG, "requestorId: " + requestorId + 1974 ", text: " + text + 1975 ", requestorIdEncoding: " + requestorIdEncoding + 1976 ", textEncoding: " + textEncoding); 1977 1978 GpsNiNotification notification = new GpsNiNotification(); 1979 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; 1991 1992 // Process extras, assuming the format is 1993 // one of more lines of "key = value" 1994 Bundle bundle = new Bundle(); 1995 1996 if (extras == null) extras = ""; 1997 Properties extraProp = new Properties(); 1998 1999 try { 2000 extraProp.load(new StringReader(extras)); 2001 } 2002 catch (IOException e) 2003 { 2004 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras); 2005 } 2006 2007 for (Entry<Object, Object> ent : extraProp.entrySet()) 2008 { 2009 bundle.putString((String) ent.getKey(), (String) ent.getValue()); 2010 } 2011 2012 notification.extras = bundle; 2013 2014 mNIHandler.handleNiNotification(notification); 2015 } 2016 2017 /** 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. 2021 */ 2022 2023 private void requestSetID(int flags) { 2024 TelephonyManager phone = (TelephonyManager) 2025 mContext.getSystemService(Context.TELEPHONY_SERVICE); 2026 int type = AGPS_SETID_TYPE_NONE; 2027 String data = ""; 2028 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. 2033 } else { 2034 // This means the framework has the SIM card. 2035 data = data_temp; 2036 type = AGPS_SETID_TYPE_IMSI; 2037 } 2038 } 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. 2043 } else { 2044 // This means the framework has the SIM card. 2045 data = data_temp; 2046 type = AGPS_SETID_TYPE_MSISDN; 2047 } 2048 } 2049 native_agps_set_id(type, data); 2050 } 2051 2052 /** 2053 * Called from native code to request utc time info 2054 */ 2055 private void requestUtcTime() { 2056 if (DEBUG) Log.d(TAG, "utcTimeRequest"); 2057 sendMessage(INJECT_NTP_TIME, 0, null); 2058 } 2059 2060 /** 2061 * Called from native code to request reference location info 2062 */ 2063 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)) { 2072 int type; 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; 2082 } else { 2083 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID; 2084 } 2085 native_agps_set_ref_location_cellid(type, mcc, mnc, 2086 gsm_cell.getLac(), gsm_cell.getCid()); 2087 } else { 2088 Log.e(TAG,"Error getting cell location info."); 2089 } 2090 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { 2091 Log.e(TAG, "CDMA not supported."); 2092 } 2093 } 2094 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(); 2102 } 2103 2104 private final class ProviderHandler extends Handler { 2105 public ProviderHandler(Looper looper) { 2106 super(looper, null, true /*async*/); 2107 } 2108 2109 @Override 2110 public void handleMessage(Message msg) { 2111 int message = msg.what; 2112 switch (message) { 2113 case ENABLE: 2114 if (msg.arg1 == 1) { 2115 handleEnable(); 2116 } else { 2117 handleDisable(); 2118 } 2119 break; 2120 case SET_REQUEST: 2121 GpsRequest gpsRequest = (GpsRequest) msg.obj; 2122 handleSetRequest(gpsRequest.request, gpsRequest.source); 2123 break; 2124 case UPDATE_NETWORK_STATE: 2125 handleUpdateNetworkState((Network) msg.obj); 2126 break; 2127 case REQUEST_SUPL_CONNECTION: 2128 handleRequestSuplConnection((InetAddress) msg.obj); 2129 break; 2130 case RELEASE_SUPL_CONNECTION: 2131 handleReleaseSuplConnection(msg.arg1); 2132 break; 2133 case INJECT_NTP_TIME: 2134 handleInjectNtpTime(); 2135 break; 2136 case DOWNLOAD_XTRA_DATA: 2137 handleDownloadXtraData(); 2138 break; 2139 case INJECT_NTP_TIME_FINISHED: 2140 mInjectNtpTimePending = STATE_IDLE; 2141 break; 2142 case DOWNLOAD_XTRA_DATA_FINISHED: 2143 mDownloadXtraDataPending = STATE_IDLE; 2144 break; 2145 case UPDATE_LOCATION: 2146 handleUpdateLocation((Location) msg.obj); 2147 break; 2148 case SUBSCRIPTION_OR_SIM_CHANGED: 2149 subscriptionOrSimChanged(mContext); 2150 break; 2151 case INITIALIZE_HANDLER: 2152 handleInitialize(); 2153 break; 2154 } 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 + ", " 2159 + msg.obj + ")"); 2160 } 2161 } 2162 2163 /** 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 2166 * this handler. 2167 */ 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); 2172 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. 2177 2178 // Register for SubscriptionInfo list changes which is guaranteed 2179 // to invoke onSubscriptionsChanged the first time. 2180 SubscriptionManager.from(mContext) 2181 .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener); 2182 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); 2191 2192 intentFilter = new IntentFilter(); 2193 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION); 2194 try { 2195 intentFilter.addDataType("application/vnd.omaloc-supl-init"); 2196 } catch (IntentFilter.MalformedMimeTypeException e) { 2197 Log.w(TAG, "Malformed SUPL init mime type"); 2198 } 2199 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); 2200 } else if (DEBUG) { 2201 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS" 2202 + " HAL is not supported"); 2203 } 2204 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); 2214 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); 2222 2223 // listen for PASSIVE_PROVIDER updates 2224 LocationManager locManager = 2225 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 2226 long minTime = 0; 2227 float minDistance = 0; 2228 boolean oneShot = false; 2229 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 2230 LocationManager.PASSIVE_PROVIDER, 2231 minTime, 2232 minDistance, 2233 oneShot); 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( 2238 request, 2239 new NetworkLocationListener(), 2240 getLooper()); 2241 } 2242 } 2243 2244 private final class NetworkLocationListener implements LocationListener { 2245 @Override 2246 public void onLocationChanged(Location location) { 2247 // this callback happens on mHandler looper 2248 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { 2249 handleUpdateLocation(location); 2250 } 2251 } 2252 @Override 2253 public void onStatusChanged(String provider, int status, Bundle extras) { } 2254 @Override 2255 public void onProviderEnabled(String provider) { } 2256 @Override 2257 public void onProviderDisabled(String provider) { } 2258 } 2259 2260 private String getSelectedApn() { 2261 Uri uri = Uri.parse("content://telephony/carriers/preferapn"); 2262 Cursor cursor = null; 2263 try { 2264 cursor = mContext.getContentResolver().query( 2265 uri, 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); 2272 } else { 2273 Log.e(TAG, "No APN found to select."); 2274 } 2275 } catch (Exception e) { 2276 Log.e(TAG, "Error encountered on selecting the APN.", e); 2277 } finally { 2278 if (cursor != null) { 2279 cursor.close(); 2280 } 2281 } 2282 2283 return null; 2284 } 2285 2286 private int getApnIpType(String apn) { 2287 ensureInHandlerThread(); 2288 if (apn == null) { 2289 return APN_INVALID; 2290 } 2291 2292 String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn); 2293 Cursor cursor = null; 2294 try { 2295 cursor = mContext.getContentResolver().query( 2296 Carriers.CONTENT_URI, 2297 new String[] { Carriers.PROTOCOL }, 2298 selection, 2299 null, 2300 Carriers.DEFAULT_SORT_ORDER); 2301 2302 if (null != cursor && cursor.moveToFirst()) { 2303 return translateToApnIpType(cursor.getString(0), apn); 2304 } else { 2305 Log.e(TAG, "No entry found in query for APN: " + apn); 2306 } 2307 } catch (Exception e) { 2308 Log.e(TAG, "Error encountered on APN query for: " + apn, e); 2309 } finally { 2310 if (cursor != null) { 2311 cursor.close(); 2312 } 2313 } 2314 2315 return APN_INVALID; 2316 } 2317 2318 private int translateToApnIpType(String ipProtocol, String apn) { 2319 if ("IP".equals(ipProtocol)) { 2320 return APN_IPV4; 2321 } 2322 if ("IPV6".equals(ipProtocol)) { 2323 return APN_IPV6; 2324 } 2325 if ("IPV4V6".equals(ipProtocol)) { 2326 return APN_IPV4V6; 2327 } 2328 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); 2332 return APN_INVALID; 2333 } 2334 2335 private void setRouting() { 2336 if (mAGpsDataConnectionIpAddr == null) { 2337 return; 2338 } 2339 2340 // TODO: replace the use of this deprecated API 2341 boolean result = mConnMgr.requestRouteToHostAddress( 2342 ConnectivityManager.TYPE_MOBILE_SUPL, 2343 mAGpsDataConnectionIpAddr); 2344 2345 if (!result) { 2346 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr); 2347 } else if (DEBUG) { 2348 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr); 2349 } 2350 } 2351 2352 /** 2353 * @return {@code true} if there is a data network available for outgoing connections, 2354 * {@code false} otherwise. 2355 */ 2356 private boolean isDataNetworkConnected() { 2357 NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo(); 2358 return activeNetworkInfo != null && activeNetworkInfo.isConnected(); 2359 } 2360 2361 /** 2362 * Ensures the calling function is running in the thread associated with {@link #mHandler}. 2363 */ 2364 private void ensureInHandlerThread() { 2365 if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) { 2366 return; 2367 } 2368 throw new RuntimeException("This method must run on the Handler thread."); 2369 } 2370 2371 /** 2372 * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}. 2373 */ 2374 private String agpsDataConnStateAsString() { 2375 switch(mAGpsDataConnectionState) { 2376 case AGPS_DATA_CONNECTION_CLOSED: 2377 return "CLOSED"; 2378 case AGPS_DATA_CONNECTION_OPEN: 2379 return "OPEN"; 2380 case AGPS_DATA_CONNECTION_OPENING: 2381 return "OPENING"; 2382 default: 2383 return "<Unknown>"; 2384 } 2385 } 2386 2387 /** 2388 * @return A string representing the given GPS_AGPS_DATA status. 2389 */ 2390 private String agpsDataConnStatusAsString(int agpsDataConnStatus) { 2391 switch (agpsDataConnStatus) { 2392 case GPS_AGPS_DATA_CONNECTED: 2393 return "CONNECTED"; 2394 case GPS_AGPS_DATA_CONN_DONE: 2395 return "DONE"; 2396 case GPS_AGPS_DATA_CONN_FAILED: 2397 return "FAILED"; 2398 case GPS_RELEASE_AGPS_DATA_CONN: 2399 return "RELEASE"; 2400 case GPS_REQUEST_AGPS_DATA_CONN: 2401 return "REQUEST"; 2402 default: 2403 return "<Unknown>"; 2404 } 2405 } 2406 2407 @Override 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)); 2413 s.append(" ( "); 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 "); 2422 s.append(")\n"); 2423 2424 s.append(native_get_internal_state()); 2425 pw.append(s); 2426 } 2427 2428 /** 2429 * A simple implementation of exponential backoff. 2430 */ 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; 2436 2437 public BackOff(long initIntervalMillis, long maxIntervalMillis) { 2438 mInitIntervalMillis = initIntervalMillis; 2439 mMaxIntervalMillis = maxIntervalMillis; 2440 2441 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER; 2442 } 2443 2444 public long nextBackoffMillis() { 2445 if (mCurrentIntervalMillis > mMaxIntervalMillis) { 2446 return mMaxIntervalMillis; 2447 } 2448 2449 mCurrentIntervalMillis *= MULTIPLIER; 2450 return mCurrentIntervalMillis; 2451 } 2452 2453 public void reset() { 2454 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER; 2455 } 2456 } 2457 2458 // for GPS SV statistics 2459 private static final int MAX_SVS = 64; 2460 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]; 2469 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(); 2475 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, 2486 float[] azimuths); 2487 private native int native_read_nmea(byte[] buffer, int bufferSize); 2488 private native void native_inject_location(double latitude, double longitude, float accuracy); 2489 2490 // XTRA Support 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); 2494 2495 // DEBUG Support 2496 private native String native_get_internal_state(); 2497 2498 // AGPS Support 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); 2504 2505 // Network-initiated (NI) Support 2506 private native void native_send_ni_response(int notificationId, int userResponse); 2507 2508 // AGPS ril suport 2509 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, 2510 int lac, int cid); 2511 private native void native_agps_set_id(int type, String setid); 2512 2513 private native void native_update_network_state(boolean connected, int type, 2514 boolean roaming, boolean available, String extraInfo, String defaultAPN); 2515 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); 2524 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(); 2529 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(); 2534 2535 // GNSS Configuration 2536 private static native void native_configuration_update(String configData); 2537 } 2538