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