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 requestUtcTime(); 456 xtraDownloadRequest(); 457 } 458 }; 459 460 /** 461 * Callback used to listen for availability of a requested SUPL connection. 462 * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to 463 * manage the registration/un-registration lifetimes separate. 464 */ 465 private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback = 466 new ConnectivityManager.NetworkCallback() { 467 @Override 468 public void onAvailable(Network network) { 469 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network); 470 } 471 472 @Override 473 public void onLost(Network network) { 474 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN); 475 } 476 477 @Override 478 public void onUnavailable() { 479 // timeout, it was not possible to establish the required connection 480 releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED); 481 } 482 }; 483 484 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 485 @Override public void onReceive(Context context, Intent intent) { 486 String action = intent.getAction(); 487 if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action); 488 if (action == null) { 489 return; 490 } 491 492 if (action.equals(ALARM_WAKEUP)) { 493 startNavigating(false); 494 } else if (action.equals(ALARM_TIMEOUT)) { 495 hibernate(); 496 } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) { 497 checkSmsSuplInit(intent); 498 } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) { 499 checkWapSuplInit(intent); 500 } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action) 501 || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action) 502 || Intent.ACTION_SCREEN_OFF.equals(action) 503 || Intent.ACTION_SCREEN_ON.equals(action)) { 504 updateLowPowerMode(); 505 } else if (action.equals(SIM_STATE_CHANGED)) { 506 subscriptionOrSimChanged(context); 507 } 508 } 509 }; 510 511 private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener = 512 new OnSubscriptionsChangedListener() { 513 @Override 514 public void onSubscriptionsChanged() { 515 sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null); 516 } 517 }; 518 519 private final boolean isVerizon(String mccMnc, String imsi, String groupId) { 520 if (DEBUG) Log.d(TAG, "simOperator: " + mccMnc); 521 if (!TextUtils.isEmpty(mccMnc) || !TextUtils.isEmpty(imsi)) { 522 for (int i = 0; i < VzwMccMncList.length; i++) { 523 if ((!TextUtils.isEmpty(mccMnc) && mccMnc.equals(VzwMccMncList[i])) || 524 (!TextUtils.isEmpty(imsi) && imsi.startsWith(VzwMccMncList[i]))) { 525 // check gid too if needed 526 if (TextUtils.isEmpty(VzwGid1List[i]) || VzwGid1List[i].equals(groupId)) { 527 if (DEBUG) Log.d(TAG, "Verizon UICC"); 528 return true; 529 } 530 } 531 } 532 } 533 return false; 534 } 535 536 private void subscriptionOrSimChanged(Context context) { 537 if (DEBUG) Log.d(TAG, "received SIM related action: "); 538 TelephonyManager phone = (TelephonyManager) 539 mContext.getSystemService(Context.TELEPHONY_SERVICE); 540 String mccMnc = phone.getSimOperator(); 541 String imsi = phone.getSubscriberId(); 542 String groupId = phone.getGroupIdLevel1(); 543 if (!TextUtils.isEmpty(mccMnc)) { 544 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc); 545 synchronized (mLock) { 546 if (isVerizon(mccMnc, imsi, groupId)) { 547 // load current properties for carrier VZW 548 loadPropertiesFromResource(context, mProperties); 549 String lpp_profile = mProperties.getProperty("LPP_PROFILE"); 550 // set the persist property LPP_PROFILE for VZW 551 SystemProperties.set(LPP_PROFILE, lpp_profile); 552 } else { 553 // reset the persist property for Non VZW 554 SystemProperties.set(LPP_PROFILE, ""); 555 } 556 reloadGpsProperties(context, mProperties); 557 mNIHandler.setSuplEsEnabled(mSuplEsEnabled); 558 } 559 } else { 560 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available"); 561 } 562 } 563 564 private void checkSmsSuplInit(Intent intent) { 565 SmsMessage[] messages = Intents.getMessagesFromIntent(intent); 566 if (messages == null) { 567 Log.e(TAG, "Message does not exist in the intent."); 568 return; 569 } 570 571 for (SmsMessage message : messages) { 572 if (message != null && message.mWrappedSmsMessage != null) { 573 byte[] suplInit = message.getUserData(); 574 if (suplInit != null) { 575 native_agps_ni_message(suplInit, suplInit.length); 576 } 577 } 578 } 579 } 580 581 private void checkWapSuplInit(Intent intent) { 582 byte[] suplInit = intent.getByteArrayExtra("data"); 583 if (suplInit == null) { 584 return; 585 } 586 native_agps_ni_message(suplInit,suplInit.length); 587 } 588 589 private void updateLowPowerMode() { 590 // Disable GPS if we are in device idle mode. 591 boolean disableGps = mPowerManager.isDeviceIdleMode(); 592 switch (Settings.Secure.getInt(mContext.getContentResolver(), BATTERY_SAVER_GPS_MODE, 593 BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF)) { 594 case BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF: 595 // If we are in battery saver mode and the screen is off, disable GPS. 596 disableGps |= mPowerManager.isPowerSaveMode() && !mPowerManager.isInteractive(); 597 break; 598 } 599 if (disableGps != mDisableGps) { 600 mDisableGps = disableGps; 601 updateRequirements(); 602 } 603 } 604 605 public static boolean isSupported() { 606 return native_is_supported(); 607 } 608 609 private void reloadGpsProperties(Context context, Properties properties) { 610 if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size()); 611 loadPropertiesFromResource(context, properties); 612 613 boolean isPropertiesLoadedFromFile = false; 614 final String gpsHardware = SystemProperties.get("ro.hardware.gps"); 615 616 if (!TextUtils.isEmpty(gpsHardware)) { 617 final String propFilename = 618 PROPERTIES_FILE_PREFIX + "." + gpsHardware + PROPERTIES_FILE_SUFFIX; 619 isPropertiesLoadedFromFile = 620 loadPropertiesFromFile(propFilename, properties); 621 } 622 if (!isPropertiesLoadedFromFile) { 623 loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties); 624 } 625 if (DEBUG) Log.d(TAG, "GPS properties reloaded, size = " + properties.size()); 626 String lpp_prof = SystemProperties.get(LPP_PROFILE); 627 if (!TextUtils.isEmpty(lpp_prof)) { 628 // override default value of this if lpp_prof is not empty 629 properties.setProperty("LPP_PROFILE", lpp_prof); 630 } 631 // TODO: we should get rid of C2K specific setting. 632 setSuplHostPort(properties.getProperty("SUPL_HOST"), 633 properties.getProperty("SUPL_PORT")); 634 mC2KServerHost = properties.getProperty("C2K_HOST"); 635 String portString = properties.getProperty("C2K_PORT"); 636 if (mC2KServerHost != null && portString != null) { 637 try { 638 mC2KServerPort = Integer.parseInt(portString); 639 } catch (NumberFormatException e) { 640 Log.e(TAG, "unable to parse C2K_PORT: " + portString); 641 } 642 } 643 644 if (native_is_gnss_configuration_supported()) { 645 try { 646 // Convert properties to string contents and send it to HAL. 647 ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); 648 properties.store(baos, null); 649 native_configuration_update(baos.toString()); 650 if (DEBUG) Log.d(TAG, "final config = " + baos.toString()); 651 } catch (IOException ex) { 652 Log.e(TAG, "failed to dump properties contents"); 653 } 654 } else if (DEBUG) { 655 Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not" 656 + " supported"); 657 } 658 659 // SUPL_ES configuration. 660 String suplESProperty = mProperties.getProperty("SUPL_ES"); 661 if (suplESProperty != null) { 662 try { 663 mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1); 664 } catch (NumberFormatException e) { 665 Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty); 666 } 667 } 668 } 669 670 private void loadPropertiesFromResource(Context context, 671 Properties properties) { 672 String[] configValues = context.getResources().getStringArray( 673 com.android.internal.R.array.config_gpsParameters); 674 for (String item : configValues) { 675 if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item); 676 // We need to support "KEY =", but not "=VALUE". 677 String[] split = item.split("="); 678 if (split.length == 2) { 679 properties.setProperty(split[0].trim().toUpperCase(), split[1]); 680 } else { 681 Log.w(TAG, "malformed contents: " + item); 682 } 683 } 684 } 685 686 private boolean loadPropertiesFromFile(String filename, 687 Properties properties) { 688 try { 689 File file = new File(filename); 690 FileInputStream stream = null; 691 try { 692 stream = new FileInputStream(file); 693 properties.load(stream); 694 } finally { 695 IoUtils.closeQuietly(stream); 696 } 697 698 } catch (IOException e) { 699 Log.w(TAG, "Could not open GPS configuration file " + filename); 700 return false; 701 } 702 return true; 703 } 704 705 public GnssLocationProvider(Context context, ILocationManager ilocationManager, 706 Looper looper) { 707 mContext = context; 708 mNtpTime = NtpTrustedTime.getInstance(context); 709 mILocationManager = ilocationManager; 710 711 mLocation.setExtras(mLocationExtras); 712 713 // Create a wake lock 714 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 715 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 716 mWakeLock.setReferenceCounted(true); 717 718 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 719 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0); 720 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0); 721 722 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); 723 724 // App ops service to keep track of who is accessing the GPS 725 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService( 726 Context.APP_OPS_SERVICE)); 727 728 // Battery statistics service to be notified when GPS turns on or off 729 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 730 BatteryStats.SERVICE_NAME)); 731 732 // Construct internal handler 733 mHandler = new ProviderHandler(looper); 734 735 // Load GPS configuration and register listeners in the background: 736 // some operations, such as opening files and registering broadcast receivers, can take a 737 // relative long time, so the ctor() is kept to create objects needed by this instance, 738 // while IO initialization and registration is delegated to our internal handler 739 // this approach is just fine because events are posted to our handler anyway 740 mProperties = new Properties(); 741 sendMessage(INITIALIZE_HANDLER, 0, null); 742 743 // Create a GPS net-initiated handler. 744 mNIHandler = new GpsNetInitiatedHandler(context, 745 mNetInitiatedListener, 746 mSuplEsEnabled); 747 748 mListenerHelper = new GnssStatusListenerHelper(mHandler) { 749 @Override 750 protected boolean isAvailableInPlatform() { 751 return isSupported(); 752 } 753 754 @Override 755 protected boolean isGpsEnabled() { 756 return isEnabled(); 757 } 758 }; 759 760 mGnssMeasurementsProvider = new GnssMeasurementsProvider(mHandler) { 761 @Override 762 public boolean isAvailableInPlatform() { 763 return native_is_measurement_supported(); 764 } 765 766 @Override 767 protected boolean registerWithService() { 768 return native_start_measurement_collection(); 769 } 770 771 @Override 772 protected void unregisterFromService() { 773 native_stop_measurement_collection(); 774 } 775 776 @Override 777 protected boolean isGpsEnabled() { 778 return isEnabled(); 779 } 780 }; 781 782 mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) { 783 @Override 784 protected boolean isAvailableInPlatform() { 785 return native_is_navigation_message_supported(); 786 } 787 788 @Override 789 protected boolean registerWithService() { 790 return native_start_navigation_message_collection(); 791 } 792 793 @Override 794 protected void unregisterFromService() { 795 native_stop_navigation_message_collection(); 796 } 797 798 @Override 799 protected boolean isGpsEnabled() { 800 return isEnabled(); 801 } 802 }; 803 } 804 805 /** 806 * Returns the name of this provider. 807 */ 808 @Override 809 public String getName() { 810 return LocationManager.GPS_PROVIDER; 811 } 812 813 @Override 814 public ProviderProperties getProperties() { 815 return PROPERTIES; 816 } 817 818 private void handleUpdateNetworkState(Network network) { 819 // retrieve NetworkInfo for this UID 820 NetworkInfo info = mConnMgr.getNetworkInfo(network); 821 if (info == null) { 822 return; 823 } 824 825 boolean isConnected = info.isConnected(); 826 if (DEBUG) { 827 String message = String.format( 828 "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S", 829 agpsDataConnStateAsString(), 830 isConnected, 831 info, 832 mConnMgr.getNetworkCapabilities(network)); 833 Log.d(TAG, message); 834 } 835 836 if (native_is_agps_ril_supported()) { 837 boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled(); 838 boolean networkAvailable = info.isAvailable() && dataEnabled; 839 String defaultApn = getSelectedApn(); 840 if (defaultApn == null) { 841 defaultApn = "dummy-apn"; 842 } 843 844 native_update_network_state( 845 isConnected, 846 info.getType(), 847 info.isRoaming(), 848 networkAvailable, 849 info.getExtraInfo(), 850 defaultApn); 851 } else if (DEBUG) { 852 Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported"); 853 } 854 855 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { 856 if (isConnected) { 857 String apnName = info.getExtraInfo(); 858 if (apnName == null) { 859 // assign a dummy value in the case of C2K as otherwise we will have a runtime 860 // exception in the following call to native_agps_data_conn_open 861 apnName = "dummy-apn"; 862 } 863 int apnIpType = getApnIpType(apnName); 864 setRouting(); 865 if (DEBUG) { 866 String message = String.format( 867 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s", 868 apnName, 869 apnIpType); 870 Log.d(TAG, message); 871 } 872 native_agps_data_conn_open(apnName, apnIpType); 873 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 874 } else { 875 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED); 876 } 877 } 878 } 879 880 private void handleRequestSuplConnection(InetAddress address) { 881 if (DEBUG) { 882 String message = String.format( 883 "requestSuplConnection, state=%s, address=%s", 884 agpsDataConnStateAsString(), 885 address); 886 Log.d(TAG, message); 887 } 888 889 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) { 890 return; 891 } 892 mAGpsDataConnectionIpAddr = address; 893 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; 894 895 NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder(); 896 requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); 897 requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); 898 NetworkRequest request = requestBuilder.build(); 899 mConnMgr.requestNetwork( 900 request, 901 mSuplConnectivityCallback, 902 ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS); 903 } 904 905 private void handleReleaseSuplConnection(int agpsDataConnStatus) { 906 if (DEBUG) { 907 String message = String.format( 908 "releaseSuplConnection, state=%s, status=%s", 909 agpsDataConnStateAsString(), 910 agpsDataConnStatusAsString(agpsDataConnStatus)); 911 Log.d(TAG, message); 912 } 913 914 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) { 915 return; 916 } 917 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 918 919 mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback); 920 switch (agpsDataConnStatus) { 921 case GPS_AGPS_DATA_CONN_FAILED: 922 native_agps_data_conn_failed(); 923 break; 924 case GPS_RELEASE_AGPS_DATA_CONN: 925 native_agps_data_conn_closed(); 926 break; 927 default: 928 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus); 929 } 930 } 931 932 private void handleInjectNtpTime() { 933 if (mInjectNtpTimePending == STATE_DOWNLOADING) { 934 // already downloading data 935 return; 936 } 937 if (!isDataNetworkConnected()) { 938 // try again when network is up 939 mInjectNtpTimePending = STATE_PENDING_NETWORK; 940 return; 941 } 942 mInjectNtpTimePending = STATE_DOWNLOADING; 943 944 // hold wake lock while task runs 945 mWakeLock.acquire(); 946 Log.i(TAG, "WakeLock acquired by handleInjectNtpTime()"); 947 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { 948 @Override 949 public void run() { 950 long delay; 951 952 // force refresh NTP cache when outdated 953 boolean refreshSuccess = true; 954 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) { 955 refreshSuccess = mNtpTime.forceRefresh(); 956 } 957 958 // only update when NTP time is fresh 959 if (mNtpTime.getCacheAge() < NTP_INTERVAL) { 960 long time = mNtpTime.getCachedNtpTime(); 961 long timeReference = mNtpTime.getCachedNtpTimeReference(); 962 long certainty = mNtpTime.getCacheCertainty(); 963 long now = System.currentTimeMillis(); 964 965 if (DEBUG) { 966 Log.d(TAG, "NTP server returned: " 967 + time + " (" + new Date(time) 968 + ") reference: " + timeReference 969 + " certainty: " + certainty 970 + " system time offset: " + (time - now)); 971 } 972 973 native_inject_time(time, timeReference, (int) certainty); 974 delay = NTP_INTERVAL; 975 mNtpBackOff.reset(); 976 } else { 977 Log.e(TAG, "requestTime failed"); 978 delay = mNtpBackOff.nextBackoffMillis(); 979 } 980 981 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null); 982 983 if (DEBUG) { 984 String message = String.format( 985 "onDemandTimeInjection=%s, refreshSuccess=%s, delay=%s", 986 mOnDemandTimeInjection, 987 refreshSuccess, 988 delay); 989 Log.d(TAG, message); 990 } 991 if (mOnDemandTimeInjection || !refreshSuccess) { 992 // send delayed message for next NTP injection 993 // since this is delayed and not urgent we do not hold a wake lock here 994 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay); 995 } 996 997 // release wake lock held by task 998 mWakeLock.release(); 999 Log.i(TAG, "WakeLock released by handleInjectNtpTime()"); 1000 } 1001 }); 1002 } 1003 1004 private void handleDownloadXtraData() { 1005 if (mDownloadXtraDataPending == STATE_DOWNLOADING) { 1006 // already downloading data 1007 return; 1008 } 1009 if (!isDataNetworkConnected()) { 1010 // try again when network is up 1011 mDownloadXtraDataPending = STATE_PENDING_NETWORK; 1012 return; 1013 } 1014 mDownloadXtraDataPending = STATE_DOWNLOADING; 1015 1016 // hold wake lock while task runs 1017 mWakeLock.acquire(); 1018 Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()"); 1019 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { 1020 @Override 1021 public void run() { 1022 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties); 1023 byte[] data = xtraDownloader.downloadXtraData(); 1024 if (data != null) { 1025 if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data"); 1026 native_inject_xtra_data(data, data.length); 1027 mXtraBackOff.reset(); 1028 } 1029 1030 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null); 1031 1032 if (data == null) { 1033 // try again later 1034 // since this is delayed and not urgent we do not hold a wake lock here 1035 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA, 1036 mXtraBackOff.nextBackoffMillis()); 1037 } 1038 1039 // release wake lock held by task 1040 mWakeLock.release(); 1041 Log.i(TAG, "WakeLock released by handleDownloadXtraData()"); 1042 } 1043 }); 1044 } 1045 1046 private void handleUpdateLocation(Location location) { 1047 if (location.hasAccuracy()) { 1048 native_inject_location(location.getLatitude(), location.getLongitude(), 1049 location.getAccuracy()); 1050 } 1051 } 1052 1053 /** 1054 * Enables this provider. When enabled, calls to getStatus() 1055 * must be handled. Hardware may be started up 1056 * when the provider is enabled. 1057 */ 1058 @Override 1059 public void enable() { 1060 synchronized (mLock) { 1061 if (mEnabled) return; 1062 mEnabled = true; 1063 } 1064 1065 sendMessage(ENABLE, 1, null); 1066 } 1067 1068 private void setSuplHostPort(String hostString, String portString) { 1069 if (hostString != null) { 1070 mSuplServerHost = hostString; 1071 } 1072 if (portString != null) { 1073 try { 1074 mSuplServerPort = Integer.parseInt(portString); 1075 } catch (NumberFormatException e) { 1076 Log.e(TAG, "unable to parse SUPL_PORT: " + portString); 1077 } 1078 } 1079 if (mSuplServerHost != null 1080 && mSuplServerPort > TCP_MIN_PORT 1081 && mSuplServerPort <= TCP_MAX_PORT) { 1082 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); 1083 } 1084 } 1085 1086 /** 1087 * Checks what SUPL mode to use, according to the AGPS mode as well as the 1088 * allowed mode from properties. 1089 * 1090 * @param properties GPS properties 1091 * @param agpsEnabled whether AGPS is enabled by settings value 1092 * @param singleShot whether "singleshot" is needed 1093 * @return SUPL mode (MSA vs MSB vs STANDALONE) 1094 */ 1095 private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) { 1096 if (agpsEnabled) { 1097 String modeString = properties.getProperty("SUPL_MODE"); 1098 int suplMode = 0; 1099 if (!TextUtils.isEmpty(modeString)) { 1100 try { 1101 suplMode = Integer.parseInt(modeString); 1102 } catch (NumberFormatException e) { 1103 Log.e(TAG, "unable to parse SUPL_MODE: " + modeString); 1104 return GPS_POSITION_MODE_STANDALONE; 1105 } 1106 } 1107 // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor 1108 // such mode when it is available 1109 if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) { 1110 return GPS_POSITION_MODE_MS_BASED; 1111 } 1112 // for now, just as the legacy code did, we fallback to MS-Assisted if it is available, 1113 // do fallback only for single-shot requests, because it is too expensive to do for 1114 // periodic requests as well 1115 if (singleShot 1116 && hasCapability(GPS_CAPABILITY_MSA) 1117 && (suplMode & AGPS_SUPL_MODE_MSA) != 0) { 1118 return GPS_POSITION_MODE_MS_ASSISTED; 1119 } 1120 } 1121 return GPS_POSITION_MODE_STANDALONE; 1122 } 1123 1124 private void handleEnable() { 1125 if (DEBUG) Log.d(TAG, "handleEnable"); 1126 1127 boolean enabled = native_init(); 1128 1129 if (enabled) { 1130 mSupportsXtra = native_supports_xtra(); 1131 1132 // TODO: remove the following native calls if we can make sure they are redundant. 1133 if (mSuplServerHost != null) { 1134 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); 1135 } 1136 if (mC2KServerHost != null) { 1137 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort); 1138 } 1139 1140 mGnssMeasurementsProvider.onGpsEnabledChanged(); 1141 mGnssNavigationMessageProvider.onGpsEnabledChanged(); 1142 } else { 1143 synchronized (mLock) { 1144 mEnabled = false; 1145 } 1146 Log.w(TAG, "Failed to enable location provider"); 1147 } 1148 } 1149 1150 /** 1151 * Disables this provider. When disabled, calls to getStatus() 1152 * need not be handled. Hardware may be shut 1153 * down while the provider is disabled. 1154 */ 1155 @Override 1156 public void disable() { 1157 synchronized (mLock) { 1158 if (!mEnabled) return; 1159 mEnabled = false; 1160 } 1161 1162 sendMessage(ENABLE, 0, null); 1163 } 1164 1165 private void handleDisable() { 1166 if (DEBUG) Log.d(TAG, "handleDisable"); 1167 1168 updateClientUids(new WorkSource()); 1169 stopNavigating(); 1170 mAlarmManager.cancel(mWakeupIntent); 1171 mAlarmManager.cancel(mTimeoutIntent); 1172 1173 // do this before releasing wakelock 1174 native_cleanup(); 1175 1176 mGnssMeasurementsProvider.onGpsEnabledChanged(); 1177 mGnssNavigationMessageProvider.onGpsEnabledChanged(); 1178 } 1179 1180 @Override 1181 public boolean isEnabled() { 1182 synchronized (mLock) { 1183 return mEnabled; 1184 } 1185 } 1186 1187 @Override 1188 public int getStatus(Bundle extras) { 1189 if (extras != null) { 1190 extras.putInt("satellites", mSvCount); 1191 } 1192 return mStatus; 1193 } 1194 1195 private void updateStatus(int status, int svCount) { 1196 if (status != mStatus || svCount != mSvCount) { 1197 mStatus = status; 1198 mSvCount = svCount; 1199 mLocationExtras.putInt("satellites", svCount); 1200 mStatusUpdateTime = SystemClock.elapsedRealtime(); 1201 } 1202 } 1203 1204 @Override 1205 public long getStatusUpdateTime() { 1206 return mStatusUpdateTime; 1207 } 1208 1209 @Override 1210 public void setRequest(ProviderRequest request, WorkSource source) { 1211 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source)); 1212 } 1213 1214 private void handleSetRequest(ProviderRequest request, WorkSource source) { 1215 mProviderRequest = request; 1216 mWorkSource = source; 1217 updateRequirements(); 1218 } 1219 1220 // Called when the requirements for GPS may have changed 1221 private void updateRequirements() { 1222 if (mProviderRequest == null || mWorkSource == null) { 1223 return; 1224 } 1225 1226 boolean singleShot = false; 1227 1228 // see if the request is for a single update 1229 if (mProviderRequest.locationRequests != null 1230 && mProviderRequest.locationRequests.size() > 0) { 1231 // if any request has zero or more than one updates 1232 // requested, then this is not single-shot mode 1233 singleShot = true; 1234 1235 for (LocationRequest lr : mProviderRequest.locationRequests) { 1236 if (lr.getNumUpdates() != 1) { 1237 singleShot = false; 1238 } 1239 } 1240 } 1241 1242 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest); 1243 if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) { 1244 // update client uids 1245 updateClientUids(mWorkSource); 1246 1247 mFixInterval = (int) mProviderRequest.interval; 1248 1249 // check for overflow 1250 if (mFixInterval != mProviderRequest.interval) { 1251 Log.w(TAG, "interval overflow: " + mProviderRequest.interval); 1252 mFixInterval = Integer.MAX_VALUE; 1253 } 1254 1255 // apply request to GPS engine 1256 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) { 1257 // change period 1258 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 1259 mFixInterval, 0, 0)) { 1260 Log.e(TAG, "set_position_mode failed in setMinTime()"); 1261 } 1262 } else if (!mStarted) { 1263 // start GPS 1264 startNavigating(singleShot); 1265 } 1266 } else { 1267 updateClientUids(new WorkSource()); 1268 1269 stopNavigating(); 1270 mAlarmManager.cancel(mWakeupIntent); 1271 mAlarmManager.cancel(mTimeoutIntent); 1272 } 1273 } 1274 1275 private void updateClientUids(WorkSource source) { 1276 // Update work source. 1277 WorkSource[] changes = mClientSource.setReturningDiffs(source); 1278 if (changes == null) { 1279 return; 1280 } 1281 WorkSource newWork = changes[0]; 1282 WorkSource goneWork = changes[1]; 1283 1284 // Update sources that were not previously tracked. 1285 if (newWork != null) { 1286 int lastuid = -1; 1287 for (int i=0; i<newWork.size(); i++) { 1288 try { 1289 int uid = newWork.get(i); 1290 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), 1291 AppOpsManager.OP_GPS, uid, newWork.getName(i)); 1292 if (uid != lastuid) { 1293 lastuid = uid; 1294 mBatteryStats.noteStartGps(uid); 1295 } 1296 } catch (RemoteException e) { 1297 Log.w(TAG, "RemoteException", e); 1298 } 1299 } 1300 } 1301 1302 // Update sources that are no longer tracked. 1303 if (goneWork != null) { 1304 int lastuid = -1; 1305 for (int i=0; i<goneWork.size(); i++) { 1306 try { 1307 int uid = goneWork.get(i); 1308 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), 1309 AppOpsManager.OP_GPS, uid, goneWork.getName(i)); 1310 if (uid != lastuid) { 1311 lastuid = uid; 1312 mBatteryStats.noteStopGps(uid); 1313 } 1314 } catch (RemoteException e) { 1315 Log.w(TAG, "RemoteException", e); 1316 } 1317 } 1318 } 1319 } 1320 1321 @Override 1322 public boolean sendExtraCommand(String command, Bundle extras) { 1323 1324 long identity = Binder.clearCallingIdentity(); 1325 boolean result = false; 1326 1327 if ("delete_aiding_data".equals(command)) { 1328 result = deleteAidingData(extras); 1329 } else if ("force_time_injection".equals(command)) { 1330 requestUtcTime(); 1331 result = true; 1332 } else if ("force_xtra_injection".equals(command)) { 1333 if (mSupportsXtra) { 1334 xtraDownloadRequest(); 1335 result = true; 1336 } 1337 } else { 1338 Log.w(TAG, "sendExtraCommand: unknown command " + command); 1339 } 1340 1341 Binder.restoreCallingIdentity(identity); 1342 return result; 1343 } 1344 1345 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() { 1346 public boolean isHardwareGeofenceSupported() { 1347 return native_is_geofence_supported(); 1348 } 1349 1350 public boolean addCircularHardwareGeofence(int geofenceId, double latitude, 1351 double longitude, double radius, int lastTransition, int monitorTransitions, 1352 int notificationResponsiveness, int unknownTimer) { 1353 return native_add_geofence(geofenceId, latitude, longitude, radius, 1354 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer); 1355 } 1356 1357 public boolean removeHardwareGeofence(int geofenceId) { 1358 return native_remove_geofence(geofenceId); 1359 } 1360 1361 public boolean pauseHardwareGeofence(int geofenceId) { 1362 return native_pause_geofence(geofenceId); 1363 } 1364 1365 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) { 1366 return native_resume_geofence(geofenceId, monitorTransition); 1367 } 1368 }; 1369 1370 private boolean deleteAidingData(Bundle extras) { 1371 int flags; 1372 1373 if (extras == null) { 1374 flags = GPS_DELETE_ALL; 1375 } else { 1376 flags = 0; 1377 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS; 1378 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC; 1379 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION; 1380 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME; 1381 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO; 1382 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC; 1383 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH; 1384 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR; 1385 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER; 1386 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA; 1387 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI; 1388 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO; 1389 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL; 1390 } 1391 1392 if (flags != 0) { 1393 native_delete_aiding_data(flags); 1394 return true; 1395 } 1396 1397 return false; 1398 } 1399 1400 private void startNavigating(boolean singleShot) { 1401 if (!mStarted) { 1402 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot); 1403 mTimeToFirstFix = 0; 1404 mLastFixTime = 0; 1405 mStarted = true; 1406 mSingleShot = singleShot; 1407 mPositionMode = GPS_POSITION_MODE_STANDALONE; 1408 1409 boolean agpsEnabled = 1410 (Settings.Global.getInt(mContext.getContentResolver(), 1411 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0); 1412 mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot); 1413 1414 if (DEBUG) { 1415 String mode; 1416 1417 switch(mPositionMode) { 1418 case GPS_POSITION_MODE_STANDALONE: 1419 mode = "standalone"; 1420 break; 1421 case GPS_POSITION_MODE_MS_ASSISTED: 1422 mode = "MS_ASSISTED"; 1423 break; 1424 case GPS_POSITION_MODE_MS_BASED: 1425 mode = "MS_BASED"; 1426 break; 1427 default: 1428 mode = "unknown"; 1429 break; 1430 } 1431 Log.d(TAG, "setting position_mode to " + mode); 1432 } 1433 1434 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000); 1435 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 1436 interval, 0, 0)) { 1437 mStarted = false; 1438 Log.e(TAG, "set_position_mode failed in startNavigating()"); 1439 return; 1440 } 1441 if (!native_start()) { 1442 mStarted = false; 1443 Log.e(TAG, "native_start failed in startNavigating()"); 1444 return; 1445 } 1446 1447 // reset SV count to zero 1448 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); 1449 mFixRequestTime = System.currentTimeMillis(); 1450 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) { 1451 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 1452 // and our fix interval is not short 1453 if (mFixInterval >= NO_FIX_TIMEOUT) { 1454 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1455 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); 1456 } 1457 } 1458 } 1459 } 1460 1461 private void stopNavigating() { 1462 if (DEBUG) Log.d(TAG, "stopNavigating"); 1463 if (mStarted) { 1464 mStarted = false; 1465 mSingleShot = false; 1466 native_stop(); 1467 mTimeToFirstFix = 0; 1468 mLastFixTime = 0; 1469 mLocationFlags = LOCATION_INVALID; 1470 1471 // reset SV count to zero 1472 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); 1473 } 1474 } 1475 1476 private void hibernate() { 1477 // stop GPS until our next fix interval arrives 1478 stopNavigating(); 1479 mAlarmManager.cancel(mTimeoutIntent); 1480 mAlarmManager.cancel(mWakeupIntent); 1481 long now = SystemClock.elapsedRealtime(); 1482 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent); 1483 } 1484 1485 private boolean hasCapability(int capability) { 1486 return ((mEngineCapabilities & capability) != 0); 1487 } 1488 1489 1490 /** 1491 * called from native code to update our position. 1492 */ 1493 private void reportLocation(int flags, double latitude, double longitude, double altitude, 1494 float speed, float bearing, float accuracy, long timestamp) { 1495 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude + 1496 " timestamp: " + timestamp); 1497 1498 synchronized (mLocation) { 1499 mLocationFlags = flags; 1500 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1501 mLocation.setLatitude(latitude); 1502 mLocation.setLongitude(longitude); 1503 mLocation.setTime(timestamp); 1504 // It would be nice to push the elapsed real-time timestamp 1505 // further down the stack, but this is still useful 1506 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 1507 } 1508 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { 1509 mLocation.setAltitude(altitude); 1510 } else { 1511 mLocation.removeAltitude(); 1512 } 1513 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { 1514 mLocation.setSpeed(speed); 1515 } else { 1516 mLocation.removeSpeed(); 1517 } 1518 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { 1519 mLocation.setBearing(bearing); 1520 } else { 1521 mLocation.removeBearing(); 1522 } 1523 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { 1524 mLocation.setAccuracy(accuracy); 1525 } else { 1526 mLocation.removeAccuracy(); 1527 } 1528 mLocation.setExtras(mLocationExtras); 1529 1530 try { 1531 mILocationManager.reportLocation(mLocation, false); 1532 } catch (RemoteException e) { 1533 Log.e(TAG, "RemoteException calling reportLocation"); 1534 } 1535 } 1536 1537 mLastFixTime = System.currentTimeMillis(); 1538 // report time to first fix 1539 if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1540 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime); 1541 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix); 1542 1543 // notify status listeners 1544 mListenerHelper.onFirstFix(mTimeToFirstFix); 1545 } 1546 1547 if (mSingleShot) { 1548 stopNavigating(); 1549 } 1550 1551 if (mStarted && mStatus != LocationProvider.AVAILABLE) { 1552 // we want to time out if we do not receive a fix 1553 // within the time out and we are requesting infrequent fixes 1554 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) { 1555 mAlarmManager.cancel(mTimeoutIntent); 1556 } 1557 1558 // send an intent to notify that the GPS is receiving fixes. 1559 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1560 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true); 1561 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1562 updateStatus(LocationProvider.AVAILABLE, mSvCount); 1563 } 1564 1565 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted && 1566 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { 1567 if (DEBUG) Log.d(TAG, "got fix, hibernating"); 1568 hibernate(); 1569 } 1570 } 1571 1572 /** 1573 * called from native code to update our status 1574 */ 1575 private void reportStatus(int status) { 1576 if (DEBUG) Log.v(TAG, "reportStatus status: " + status); 1577 1578 boolean wasNavigating = mNavigating; 1579 switch (status) { 1580 case GPS_STATUS_SESSION_BEGIN: 1581 mNavigating = true; 1582 mEngineOn = true; 1583 break; 1584 case GPS_STATUS_SESSION_END: 1585 mNavigating = false; 1586 break; 1587 case GPS_STATUS_ENGINE_ON: 1588 mEngineOn = true; 1589 break; 1590 case GPS_STATUS_ENGINE_OFF: 1591 mEngineOn = false; 1592 mNavigating = false; 1593 break; 1594 } 1595 1596 if (wasNavigating != mNavigating) { 1597 mListenerHelper.onStatusChanged(mNavigating); 1598 1599 // send an intent to notify that the GPS has been enabled or disabled 1600 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION); 1601 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating); 1602 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1603 } 1604 } 1605 1606 /** 1607 * called from native code to update SV info 1608 */ 1609 private void reportSvStatus() { 1610 int svCount = native_read_sv_status(mSvidWithFlags, mCn0s, mSvElevations, mSvAzimuths); 1611 mListenerHelper.onSvStatusChanged( 1612 svCount, 1613 mSvidWithFlags, 1614 mCn0s, 1615 mSvElevations, 1616 mSvAzimuths); 1617 1618 if (VERBOSE) { 1619 Log.v(TAG, "SV count: " + svCount); 1620 } 1621 // Calculate number of sets used in fix. 1622 int usedInFixCount = 0; 1623 for (int i = 0; i < svCount; i++) { 1624 if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) { 1625 ++usedInFixCount; 1626 } 1627 if (VERBOSE) { 1628 Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) + 1629 " cn0: " + mCn0s[i]/10 + 1630 " elev: " + mSvElevations[i] + 1631 " azimuth: " + mSvAzimuths[i] + 1632 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0 1633 ? " " : " E") + 1634 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0 1635 ? " " : " A") + 1636 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0 1637 ? "" : "U")); 1638 } 1639 } 1640 // return number of sets used in fix instead of total 1641 updateStatus(mStatus, usedInFixCount); 1642 1643 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 && 1644 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) { 1645 // send an intent to notify that the GPS is no longer receiving fixes. 1646 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1647 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false); 1648 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1649 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount); 1650 } 1651 } 1652 1653 /** 1654 * called from native code to update AGPS status 1655 */ 1656 private void reportAGpsStatus(int type, int status, byte[] ipaddr) { 1657 switch (status) { 1658 case GPS_REQUEST_AGPS_DATA_CONN: 1659 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN"); 1660 Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr)); 1661 InetAddress connectionIpAddress = null; 1662 if (ipaddr != null) { 1663 try { 1664 connectionIpAddress = InetAddress.getByAddress(ipaddr); 1665 if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress); 1666 } catch (UnknownHostException e) { 1667 Log.e(TAG, "Bad IP Address: " + ipaddr, e); 1668 } 1669 } 1670 sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress); 1671 break; 1672 case GPS_RELEASE_AGPS_DATA_CONN: 1673 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN"); 1674 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN); 1675 break; 1676 case GPS_AGPS_DATA_CONNECTED: 1677 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED"); 1678 break; 1679 case GPS_AGPS_DATA_CONN_DONE: 1680 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE"); 1681 break; 1682 case GPS_AGPS_DATA_CONN_FAILED: 1683 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED"); 1684 break; 1685 default: 1686 if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status); 1687 } 1688 } 1689 1690 private void releaseSuplConnection(int connStatus) { 1691 sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/); 1692 } 1693 1694 /** 1695 * called from native code to report NMEA data received 1696 */ 1697 private void reportNmea(long timestamp) { 1698 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length); 1699 String nmea = new String(mNmeaBuffer, 0 /* offset */, length); 1700 mListenerHelper.onNmeaReceived(timestamp, nmea); 1701 } 1702 1703 /** 1704 * called from native code - Gps measurements callback 1705 */ 1706 private void reportMeasurementData(GnssMeasurementsEvent event) { 1707 mGnssMeasurementsProvider.onMeasurementsAvailable(event); 1708 } 1709 1710 /** 1711 * called from native code - GPS navigation message callback 1712 */ 1713 private void reportNavigationMessage(GnssNavigationMessage event) { 1714 mGnssNavigationMessageProvider.onNavigationMessageAvailable(event); 1715 } 1716 1717 /** 1718 * called from native code to inform us what the GPS engine capabilities are 1719 */ 1720 private void setEngineCapabilities(int capabilities) { 1721 mEngineCapabilities = capabilities; 1722 1723 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) { 1724 mOnDemandTimeInjection = true; 1725 requestUtcTime(); 1726 } 1727 1728 mGnssMeasurementsProvider.onCapabilitiesUpdated( 1729 (capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS); 1730 mGnssNavigationMessageProvider.onCapabilitiesUpdated( 1731 (capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES); 1732 } 1733 1734 /** 1735 * Called from native code to inform us the hardware information. 1736 */ 1737 private void setGnssYearOfHardware(int yearOfHardware) { 1738 if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware); 1739 mYearOfHardware = yearOfHardware; 1740 } 1741 1742 public interface GnssSystemInfoProvider { 1743 /** 1744 * Returns the year of GPS hardware. 1745 */ 1746 int getGnssYearOfHardware(); 1747 } 1748 1749 /** 1750 * @hide 1751 */ 1752 public GnssSystemInfoProvider getGnssSystemInfoProvider() { 1753 return new GnssSystemInfoProvider() { 1754 @Override 1755 public int getGnssYearOfHardware() { 1756 return mYearOfHardware; 1757 } 1758 }; 1759 } 1760 1761 /** 1762 * called from native code to request XTRA data 1763 */ 1764 private void xtraDownloadRequest() { 1765 if (DEBUG) Log.d(TAG, "xtraDownloadRequest"); 1766 sendMessage(DOWNLOAD_XTRA_DATA, 0, null); 1767 } 1768 1769 /** 1770 * Helper method to construct a location object. 1771 */ 1772 private Location buildLocation( 1773 int flags, 1774 double latitude, 1775 double longitude, 1776 double altitude, 1777 float speed, 1778 float bearing, 1779 float accuracy, 1780 long timestamp) { 1781 Location location = new Location(LocationManager.GPS_PROVIDER); 1782 if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1783 location.setLatitude(latitude); 1784 location.setLongitude(longitude); 1785 location.setTime(timestamp); 1786 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 1787 } 1788 if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { 1789 location.setAltitude(altitude); 1790 } 1791 if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { 1792 location.setSpeed(speed); 1793 } 1794 if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { 1795 location.setBearing(bearing); 1796 } 1797 if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { 1798 location.setAccuracy(accuracy); 1799 } 1800 return location; 1801 } 1802 1803 /** 1804 * Converts the GPS HAL status to the internal Geofence Hardware status. 1805 */ 1806 private int getGeofenceStatus(int status) { 1807 switch(status) { 1808 case GPS_GEOFENCE_OPERATION_SUCCESS: 1809 return GeofenceHardware.GEOFENCE_SUCCESS; 1810 case GPS_GEOFENCE_ERROR_GENERIC: 1811 return GeofenceHardware.GEOFENCE_FAILURE; 1812 case GPS_GEOFENCE_ERROR_ID_EXISTS: 1813 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; 1814 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION: 1815 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; 1816 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES: 1817 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; 1818 case GPS_GEOFENCE_ERROR_ID_UNKNOWN: 1819 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; 1820 default: 1821 return -1; 1822 } 1823 } 1824 1825 /** 1826 * Called from native to report GPS Geofence transition 1827 * All geofence callbacks are called on the same thread 1828 */ 1829 private void reportGeofenceTransition(int geofenceId, int flags, double latitude, 1830 double longitude, double altitude, float speed, float bearing, float accuracy, 1831 long timestamp, int transition, long transitionTimestamp) { 1832 if (mGeofenceHardwareImpl == null) { 1833 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1834 } 1835 Location location = buildLocation( 1836 flags, 1837 latitude, 1838 longitude, 1839 altitude, 1840 speed, 1841 bearing, 1842 accuracy, 1843 timestamp); 1844 mGeofenceHardwareImpl.reportGeofenceTransition( 1845 geofenceId, 1846 location, 1847 transition, 1848 transitionTimestamp, 1849 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 1850 FusedBatchOptions.SourceTechnologies.GNSS); 1851 } 1852 1853 /** 1854 * called from native code to report GPS status change. 1855 */ 1856 private void reportGeofenceStatus(int status, int flags, double latitude, 1857 double longitude, double altitude, float speed, float bearing, float accuracy, 1858 long timestamp) { 1859 if (mGeofenceHardwareImpl == null) { 1860 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1861 } 1862 Location location = buildLocation( 1863 flags, 1864 latitude, 1865 longitude, 1866 altitude, 1867 speed, 1868 bearing, 1869 accuracy, 1870 timestamp); 1871 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; 1872 if(status == GPS_GEOFENCE_AVAILABLE) { 1873 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; 1874 } 1875 mGeofenceHardwareImpl.reportGeofenceMonitorStatus( 1876 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 1877 monitorStatus, 1878 location, 1879 FusedBatchOptions.SourceTechnologies.GNSS); 1880 } 1881 1882 /** 1883 * called from native code - Geofence Add callback 1884 */ 1885 private void reportGeofenceAddStatus(int geofenceId, int status) { 1886 if (mGeofenceHardwareImpl == null) { 1887 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1888 } 1889 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status)); 1890 } 1891 1892 /** 1893 * called from native code - Geofence Remove callback 1894 */ 1895 private void reportGeofenceRemoveStatus(int geofenceId, int status) { 1896 if (mGeofenceHardwareImpl == null) { 1897 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1898 } 1899 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status)); 1900 } 1901 1902 /** 1903 * called from native code - Geofence Pause callback 1904 */ 1905 private void reportGeofencePauseStatus(int geofenceId, int status) { 1906 if (mGeofenceHardwareImpl == null) { 1907 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1908 } 1909 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status)); 1910 } 1911 1912 /** 1913 * called from native code - Geofence Resume callback 1914 */ 1915 private void reportGeofenceResumeStatus(int geofenceId, int status) { 1916 if (mGeofenceHardwareImpl == null) { 1917 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1918 } 1919 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status)); 1920 } 1921 1922 //============================================================= 1923 // NI Client support 1924 //============================================================= 1925 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() { 1926 // Sends a response for an NI request to HAL. 1927 @Override 1928 public boolean sendNiResponse(int notificationId, int userResponse) 1929 { 1930 // TODO Add Permission check 1931 1932 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId + 1933 ", response: " + userResponse); 1934 native_send_ni_response(notificationId, userResponse); 1935 return true; 1936 } 1937 }; 1938 1939 public INetInitiatedListener getNetInitiatedListener() { 1940 return mNetInitiatedListener; 1941 } 1942 1943 // Called by JNI function to report an NI request. 1944 public void reportNiNotification( 1945 int notificationId, 1946 int niType, 1947 int notifyFlags, 1948 int timeout, 1949 int defaultResponse, 1950 String requestorId, 1951 String text, 1952 int requestorIdEncoding, 1953 int textEncoding, 1954 String extras // Encoded extra data 1955 ) 1956 { 1957 Log.i(TAG, "reportNiNotification: entered"); 1958 Log.i(TAG, "notificationId: " + notificationId + 1959 ", niType: " + niType + 1960 ", notifyFlags: " + notifyFlags + 1961 ", timeout: " + timeout + 1962 ", defaultResponse: " + defaultResponse); 1963 1964 Log.i(TAG, "requestorId: " + requestorId + 1965 ", text: " + text + 1966 ", requestorIdEncoding: " + requestorIdEncoding + 1967 ", textEncoding: " + textEncoding); 1968 1969 GpsNiNotification notification = new GpsNiNotification(); 1970 1971 notification.notificationId = notificationId; 1972 notification.niType = niType; 1973 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0; 1974 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0; 1975 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0; 1976 notification.timeout = timeout; 1977 notification.defaultResponse = defaultResponse; 1978 notification.requestorId = requestorId; 1979 notification.text = text; 1980 notification.requestorIdEncoding = requestorIdEncoding; 1981 notification.textEncoding = textEncoding; 1982 1983 // Process extras, assuming the format is 1984 // one of more lines of "key = value" 1985 Bundle bundle = new Bundle(); 1986 1987 if (extras == null) extras = ""; 1988 Properties extraProp = new Properties(); 1989 1990 try { 1991 extraProp.load(new StringReader(extras)); 1992 } 1993 catch (IOException e) 1994 { 1995 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras); 1996 } 1997 1998 for (Entry<Object, Object> ent : extraProp.entrySet()) 1999 { 2000 bundle.putString((String) ent.getKey(), (String) ent.getValue()); 2001 } 2002 2003 notification.extras = bundle; 2004 2005 mNIHandler.handleNiNotification(notification); 2006 } 2007 2008 /** 2009 * Called from native code to request set id info. 2010 * We should be careful about receiving null string from the TelephonyManager, 2011 * because sending null String to JNI function would cause a crash. 2012 */ 2013 2014 private void requestSetID(int flags) { 2015 TelephonyManager phone = (TelephonyManager) 2016 mContext.getSystemService(Context.TELEPHONY_SERVICE); 2017 int type = AGPS_SETID_TYPE_NONE; 2018 String data = ""; 2019 2020 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) { 2021 String data_temp = phone.getSubscriberId(); 2022 if (data_temp == null) { 2023 // This means the framework does not have the SIM card ready. 2024 } else { 2025 // This means the framework has the SIM card. 2026 data = data_temp; 2027 type = AGPS_SETID_TYPE_IMSI; 2028 } 2029 } 2030 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) { 2031 String data_temp = phone.getLine1Number(); 2032 if (data_temp == null) { 2033 // This means the framework does not have the SIM card ready. 2034 } else { 2035 // This means the framework has the SIM card. 2036 data = data_temp; 2037 type = AGPS_SETID_TYPE_MSISDN; 2038 } 2039 } 2040 native_agps_set_id(type, data); 2041 } 2042 2043 /** 2044 * Called from native code to request utc time info 2045 */ 2046 private void requestUtcTime() { 2047 if (DEBUG) Log.d(TAG, "utcTimeRequest"); 2048 sendMessage(INJECT_NTP_TIME, 0, null); 2049 } 2050 2051 /** 2052 * Called from native code to request reference location info 2053 */ 2054 2055 private void requestRefLocation(int flags) { 2056 TelephonyManager phone = (TelephonyManager) 2057 mContext.getSystemService(Context.TELEPHONY_SERVICE); 2058 final int phoneType = phone.getPhoneType(); 2059 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) { 2060 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation(); 2061 if ((gsm_cell != null) && (phone.getNetworkOperator() != null) 2062 && (phone.getNetworkOperator().length() > 3)) { 2063 int type; 2064 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3)); 2065 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3)); 2066 int networkType = phone.getNetworkType(); 2067 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS 2068 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA 2069 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA 2070 || networkType == TelephonyManager.NETWORK_TYPE_HSPA 2071 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) { 2072 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID; 2073 } else { 2074 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID; 2075 } 2076 native_agps_set_ref_location_cellid(type, mcc, mnc, 2077 gsm_cell.getLac(), gsm_cell.getCid()); 2078 } else { 2079 Log.e(TAG,"Error getting cell location info."); 2080 } 2081 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { 2082 Log.e(TAG, "CDMA not supported."); 2083 } 2084 } 2085 2086 private void sendMessage(int message, int arg, Object obj) { 2087 // hold a wake lock until this message is delivered 2088 // note that this assumes the message will not be removed from the queue before 2089 // it is handled (otherwise the wake lock would be leaked). 2090 mWakeLock.acquire(); 2091 Log.i(TAG, "WakeLock acquired by sendMessage(" + message + ", " + arg + ", " + obj + ")"); 2092 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget(); 2093 } 2094 2095 private final class ProviderHandler extends Handler { 2096 public ProviderHandler(Looper looper) { 2097 super(looper, null, true /*async*/); 2098 } 2099 2100 @Override 2101 public void handleMessage(Message msg) { 2102 int message = msg.what; 2103 switch (message) { 2104 case ENABLE: 2105 if (msg.arg1 == 1) { 2106 handleEnable(); 2107 } else { 2108 handleDisable(); 2109 } 2110 break; 2111 case SET_REQUEST: 2112 GpsRequest gpsRequest = (GpsRequest) msg.obj; 2113 handleSetRequest(gpsRequest.request, gpsRequest.source); 2114 break; 2115 case UPDATE_NETWORK_STATE: 2116 handleUpdateNetworkState((Network) msg.obj); 2117 break; 2118 case REQUEST_SUPL_CONNECTION: 2119 handleRequestSuplConnection((InetAddress) msg.obj); 2120 break; 2121 case RELEASE_SUPL_CONNECTION: 2122 handleReleaseSuplConnection(msg.arg1); 2123 break; 2124 case INJECT_NTP_TIME: 2125 handleInjectNtpTime(); 2126 break; 2127 case DOWNLOAD_XTRA_DATA: 2128 if (mSupportsXtra) { 2129 handleDownloadXtraData(); 2130 } 2131 break; 2132 case INJECT_NTP_TIME_FINISHED: 2133 mInjectNtpTimePending = STATE_IDLE; 2134 break; 2135 case DOWNLOAD_XTRA_DATA_FINISHED: 2136 mDownloadXtraDataPending = STATE_IDLE; 2137 break; 2138 case UPDATE_LOCATION: 2139 handleUpdateLocation((Location) msg.obj); 2140 break; 2141 case SUBSCRIPTION_OR_SIM_CHANGED: 2142 subscriptionOrSimChanged(mContext); 2143 break; 2144 case INITIALIZE_HANDLER: 2145 handleInitialize(); 2146 break; 2147 } 2148 if (msg.arg2 == 1) { 2149 // wakelock was taken for this message, release it 2150 mWakeLock.release(); 2151 Log.i(TAG, "WakeLock released by handleMessage(" + message + ", " + msg.arg1 + ", " 2152 + msg.obj + ")"); 2153 } 2154 } 2155 2156 /** 2157 * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}. 2158 * It is in charge of loading properties and registering for events that will be posted to 2159 * this handler. 2160 */ 2161 private void handleInitialize() { 2162 // load default GPS configuration 2163 // (this configuration might change in the future based on SIM changes) 2164 reloadGpsProperties(mContext, mProperties); 2165 2166 // TODO: When this object "finishes" we should unregister by invoking 2167 // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener); 2168 // This is not strictly necessary because it will be unregistered if the 2169 // notification fails but it is good form. 2170 2171 // Register for SubscriptionInfo list changes which is guaranteed 2172 // to invoke onSubscriptionsChanged the first time. 2173 SubscriptionManager.from(mContext) 2174 .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener); 2175 2176 // listen for events 2177 IntentFilter intentFilter; 2178 if (native_is_agps_ril_supported()) { 2179 intentFilter = new IntentFilter(); 2180 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION); 2181 intentFilter.addDataScheme("sms"); 2182 intentFilter.addDataAuthority("localhost", "7275"); 2183 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); 2184 2185 intentFilter = new IntentFilter(); 2186 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION); 2187 try { 2188 intentFilter.addDataType("application/vnd.omaloc-supl-init"); 2189 } catch (IntentFilter.MalformedMimeTypeException e) { 2190 Log.w(TAG, "Malformed SUPL init mime type"); 2191 } 2192 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); 2193 } else if (DEBUG) { 2194 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS" 2195 + " HAL is not supported"); 2196 } 2197 2198 intentFilter = new IntentFilter(); 2199 intentFilter.addAction(ALARM_WAKEUP); 2200 intentFilter.addAction(ALARM_TIMEOUT); 2201 intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); 2202 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); 2203 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 2204 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 2205 intentFilter.addAction(SIM_STATE_CHANGED); 2206 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); 2207 2208 // register for connectivity change events, this is equivalent to the deprecated way of 2209 // registering for CONNECTIVITY_ACTION broadcasts 2210 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder(); 2211 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); 2212 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); 2213 NetworkRequest networkRequest = networkRequestBuilder.build(); 2214 mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback); 2215 2216 // listen for PASSIVE_PROVIDER updates 2217 LocationManager locManager = 2218 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 2219 long minTime = 0; 2220 float minDistance = 0; 2221 boolean oneShot = false; 2222 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 2223 LocationManager.PASSIVE_PROVIDER, 2224 minTime, 2225 minDistance, 2226 oneShot); 2227 // Don't keep track of this request since it's done on behalf of other clients 2228 // (which are kept track of separately). 2229 request.setHideFromAppOps(true); 2230 locManager.requestLocationUpdates( 2231 request, 2232 new NetworkLocationListener(), 2233 getLooper()); 2234 } 2235 } 2236 2237 private final class NetworkLocationListener implements LocationListener { 2238 @Override 2239 public void onLocationChanged(Location location) { 2240 // this callback happens on mHandler looper 2241 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { 2242 handleUpdateLocation(location); 2243 } 2244 } 2245 @Override 2246 public void onStatusChanged(String provider, int status, Bundle extras) { } 2247 @Override 2248 public void onProviderEnabled(String provider) { } 2249 @Override 2250 public void onProviderDisabled(String provider) { } 2251 } 2252 2253 private String getSelectedApn() { 2254 Uri uri = Uri.parse("content://telephony/carriers/preferapn"); 2255 Cursor cursor = null; 2256 try { 2257 cursor = mContext.getContentResolver().query( 2258 uri, 2259 new String[] { "apn" }, 2260 null /* selection */, 2261 null /* selectionArgs */, 2262 Carriers.DEFAULT_SORT_ORDER); 2263 if (cursor != null && cursor.moveToFirst()) { 2264 return cursor.getString(0); 2265 } else { 2266 Log.e(TAG, "No APN found to select."); 2267 } 2268 } catch (Exception e) { 2269 Log.e(TAG, "Error encountered on selecting the APN.", e); 2270 } finally { 2271 if (cursor != null) { 2272 cursor.close(); 2273 } 2274 } 2275 2276 return null; 2277 } 2278 2279 private int getApnIpType(String apn) { 2280 ensureInHandlerThread(); 2281 if (apn == null) { 2282 return APN_INVALID; 2283 } 2284 2285 String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn); 2286 Cursor cursor = null; 2287 try { 2288 cursor = mContext.getContentResolver().query( 2289 Carriers.CONTENT_URI, 2290 new String[] { Carriers.PROTOCOL }, 2291 selection, 2292 null, 2293 Carriers.DEFAULT_SORT_ORDER); 2294 2295 if (null != cursor && cursor.moveToFirst()) { 2296 return translateToApnIpType(cursor.getString(0), apn); 2297 } else { 2298 Log.e(TAG, "No entry found in query for APN: " + apn); 2299 } 2300 } catch (Exception e) { 2301 Log.e(TAG, "Error encountered on APN query for: " + apn, e); 2302 } finally { 2303 if (cursor != null) { 2304 cursor.close(); 2305 } 2306 } 2307 2308 return APN_INVALID; 2309 } 2310 2311 private int translateToApnIpType(String ipProtocol, String apn) { 2312 if ("IP".equals(ipProtocol)) { 2313 return APN_IPV4; 2314 } 2315 if ("IPV6".equals(ipProtocol)) { 2316 return APN_IPV6; 2317 } 2318 if ("IPV4V6".equals(ipProtocol)) { 2319 return APN_IPV4V6; 2320 } 2321 2322 // we hit the default case so the ipProtocol is not recognized 2323 String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn); 2324 Log.e(TAG, message); 2325 return APN_INVALID; 2326 } 2327 2328 private void setRouting() { 2329 if (mAGpsDataConnectionIpAddr == null) { 2330 return; 2331 } 2332 2333 // TODO: replace the use of this deprecated API 2334 boolean result = mConnMgr.requestRouteToHostAddress( 2335 ConnectivityManager.TYPE_MOBILE_SUPL, 2336 mAGpsDataConnectionIpAddr); 2337 2338 if (!result) { 2339 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr); 2340 } else if (DEBUG) { 2341 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr); 2342 } 2343 } 2344 2345 /** 2346 * @return {@code true} if there is a data network available for outgoing connections, 2347 * {@code false} otherwise. 2348 */ 2349 private boolean isDataNetworkConnected() { 2350 NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo(); 2351 return activeNetworkInfo != null && activeNetworkInfo.isConnected(); 2352 } 2353 2354 /** 2355 * Ensures the calling function is running in the thread associated with {@link #mHandler}. 2356 */ 2357 private void ensureInHandlerThread() { 2358 if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) { 2359 return; 2360 } 2361 throw new RuntimeException("This method must run on the Handler thread."); 2362 } 2363 2364 /** 2365 * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}. 2366 */ 2367 private String agpsDataConnStateAsString() { 2368 switch(mAGpsDataConnectionState) { 2369 case AGPS_DATA_CONNECTION_CLOSED: 2370 return "CLOSED"; 2371 case AGPS_DATA_CONNECTION_OPEN: 2372 return "OPEN"; 2373 case AGPS_DATA_CONNECTION_OPENING: 2374 return "OPENING"; 2375 default: 2376 return "<Unknown>"; 2377 } 2378 } 2379 2380 /** 2381 * @return A string representing the given GPS_AGPS_DATA status. 2382 */ 2383 private String agpsDataConnStatusAsString(int agpsDataConnStatus) { 2384 switch (agpsDataConnStatus) { 2385 case GPS_AGPS_DATA_CONNECTED: 2386 return "CONNECTED"; 2387 case GPS_AGPS_DATA_CONN_DONE: 2388 return "DONE"; 2389 case GPS_AGPS_DATA_CONN_FAILED: 2390 return "FAILED"; 2391 case GPS_RELEASE_AGPS_DATA_CONN: 2392 return "RELEASE"; 2393 case GPS_REQUEST_AGPS_DATA_CONN: 2394 return "REQUEST"; 2395 default: 2396 return "<Unknown>"; 2397 } 2398 } 2399 2400 @Override 2401 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2402 StringBuilder s = new StringBuilder(); 2403 s.append(" mFixInterval=").append(mFixInterval).append('\n'); 2404 s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append('\n'); 2405 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)); 2406 s.append(" ( "); 2407 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING "); 2408 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB "); 2409 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA "); 2410 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT "); 2411 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME "); 2412 if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING "); 2413 if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS "); 2414 if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES "); 2415 s.append(")\n"); 2416 2417 s.append(native_get_internal_state()); 2418 pw.append(s); 2419 } 2420 2421 /** 2422 * A simple implementation of exponential backoff. 2423 */ 2424 private static final class BackOff { 2425 private static final int MULTIPLIER = 2; 2426 private final long mInitIntervalMillis; 2427 private final long mMaxIntervalMillis; 2428 private long mCurrentIntervalMillis; 2429 2430 public BackOff(long initIntervalMillis, long maxIntervalMillis) { 2431 mInitIntervalMillis = initIntervalMillis; 2432 mMaxIntervalMillis = maxIntervalMillis; 2433 2434 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER; 2435 } 2436 2437 public long nextBackoffMillis() { 2438 if (mCurrentIntervalMillis > mMaxIntervalMillis) { 2439 return mMaxIntervalMillis; 2440 } 2441 2442 mCurrentIntervalMillis *= MULTIPLIER; 2443 return mCurrentIntervalMillis; 2444 } 2445 2446 public void reset() { 2447 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER; 2448 } 2449 } 2450 2451 // for GPS SV statistics 2452 private static final int MAX_SVS = 64; 2453 2454 // preallocated arrays, to avoid memory allocation in reportStatus() 2455 private int mSvidWithFlags[] = new int[MAX_SVS]; 2456 private float mCn0s[] = new float[MAX_SVS]; 2457 private float mSvElevations[] = new float[MAX_SVS]; 2458 private float mSvAzimuths[] = new float[MAX_SVS]; 2459 private int mSvCount; 2460 // preallocated to avoid memory allocation in reportNmea() 2461 private byte[] mNmeaBuffer = new byte[120]; 2462 2463 static { class_init_native(); } 2464 private static native void class_init_native(); 2465 private static native boolean native_is_supported(); 2466 private static native boolean native_is_agps_ril_supported(); 2467 private static native boolean native_is_gnss_configuration_supported(); 2468 2469 private native boolean native_init(); 2470 private native void native_cleanup(); 2471 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval, 2472 int preferred_accuracy, int preferred_time); 2473 private native boolean native_start(); 2474 private native boolean native_stop(); 2475 private native void native_delete_aiding_data(int flags); 2476 // returns number of SVs 2477 // mask[0] is ephemeris mask and mask[1] is almanac mask 2478 private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations, 2479 float[] azimuths); 2480 private native int native_read_nmea(byte[] buffer, int bufferSize); 2481 private native void native_inject_location(double latitude, double longitude, float accuracy); 2482 2483 // XTRA Support 2484 private native void native_inject_time(long time, long timeReference, int uncertainty); 2485 private native boolean native_supports_xtra(); 2486 private native void native_inject_xtra_data(byte[] data, int length); 2487 2488 // DEBUG Support 2489 private native String native_get_internal_state(); 2490 2491 // AGPS Support 2492 private native void native_agps_data_conn_open(String apn, int apnIpType); 2493 private native void native_agps_data_conn_closed(); 2494 private native void native_agps_data_conn_failed(); 2495 private native void native_agps_ni_message(byte [] msg, int length); 2496 private native void native_set_agps_server(int type, String hostname, int port); 2497 2498 // Network-initiated (NI) Support 2499 private native void native_send_ni_response(int notificationId, int userResponse); 2500 2501 // AGPS ril suport 2502 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, 2503 int lac, int cid); 2504 private native void native_agps_set_id(int type, String setid); 2505 2506 private native void native_update_network_state(boolean connected, int type, 2507 boolean roaming, boolean available, String extraInfo, String defaultAPN); 2508 2509 // Hardware Geofence support. 2510 private static native boolean native_is_geofence_supported(); 2511 private static native boolean native_add_geofence(int geofenceId, double latitude, 2512 double longitude, double radius, int lastTransition,int monitorTransitions, 2513 int notificationResponsivenes, int unknownTimer); 2514 private static native boolean native_remove_geofence(int geofenceId); 2515 private static native boolean native_resume_geofence(int geofenceId, int transitions); 2516 private static native boolean native_pause_geofence(int geofenceId); 2517 2518 // Gps Hal measurements support. 2519 private static native boolean native_is_measurement_supported(); 2520 private native boolean native_start_measurement_collection(); 2521 private native boolean native_stop_measurement_collection(); 2522 2523 // Gps Navigation message support. 2524 private static native boolean native_is_navigation_message_supported(); 2525 private native boolean native_start_navigation_message_collection(); 2526 private native boolean native_stop_navigation_message_collection(); 2527 2528 // GNSS Configuration 2529 private static native void native_configuration_update(String configData); 2530 } 2531