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 import com.android.internal.telephony.Phone; 26 import com.android.internal.telephony.PhoneConstants; 27 28 import android.app.AlarmManager; 29 import android.app.AppOpsManager; 30 import android.app.PendingIntent; 31 import android.content.BroadcastReceiver; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.IntentFilter; 35 import android.database.Cursor; 36 import android.hardware.location.GeofenceHardware; 37 import android.hardware.location.GeofenceHardwareImpl; 38 import android.location.Criteria; 39 import android.location.FusedBatchOptions; 40 import android.location.GpsMeasurementsEvent; 41 import android.location.GpsNavigationMessageEvent; 42 import android.location.IGpsGeofenceHardware; 43 import android.location.IGpsStatusListener; 44 import android.location.IGpsStatusProvider; 45 import android.location.ILocationManager; 46 import android.location.INetInitiatedListener; 47 import android.location.Location; 48 import android.location.LocationListener; 49 import android.location.LocationManager; 50 import android.location.LocationProvider; 51 import android.location.LocationRequest; 52 import android.net.ConnectivityManager; 53 import android.net.NetworkInfo; 54 import android.net.Uri; 55 import android.os.AsyncTask; 56 import android.os.BatteryStats; 57 import android.os.Binder; 58 import android.os.Bundle; 59 import android.os.Handler; 60 import android.os.Looper; 61 import android.os.Message; 62 import android.os.PowerManager; 63 import android.os.RemoteException; 64 import android.os.ServiceManager; 65 import android.os.SystemClock; 66 import android.os.SystemProperties; 67 import android.os.UserHandle; 68 import android.os.WorkSource; 69 import android.provider.Settings; 70 import android.provider.Telephony.Carriers; 71 import android.provider.Telephony.Sms.Intents; 72 import android.telephony.SmsMessage; 73 import android.telephony.SubscriptionManager; 74 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; 75 import android.telephony.TelephonyManager; 76 import android.telephony.gsm.GsmCellLocation; 77 import android.text.TextUtils; 78 import android.util.Log; 79 import android.util.NtpTrustedTime; 80 81 import java.io.ByteArrayOutputStream; 82 import java.io.File; 83 import java.io.FileDescriptor; 84 import java.io.FileInputStream; 85 import java.io.IOException; 86 import java.io.PrintWriter; 87 import java.io.StringReader; 88 import java.net.InetAddress; 89 import java.net.UnknownHostException; 90 import java.util.Date; 91 import java.util.Map.Entry; 92 import java.util.Properties; 93 94 import libcore.io.IoUtils; 95 96 /** 97 * A GPS implementation of LocationProvider used by LocationManager. 98 * 99 * {@hide} 100 */ 101 public class GpsLocationProvider implements LocationProviderInterface { 102 103 private static final String TAG = "GpsLocationProvider"; 104 105 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 106 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 107 108 private static final ProviderProperties PROPERTIES = new ProviderProperties( 109 true, true, false, false, true, true, true, 110 Criteria.POWER_HIGH, Criteria.ACCURACY_FINE); 111 112 // these need to match GpsPositionMode enum in gps.h 113 private static final int GPS_POSITION_MODE_STANDALONE = 0; 114 private static final int GPS_POSITION_MODE_MS_BASED = 1; 115 private static final int GPS_POSITION_MODE_MS_ASSISTED = 2; 116 117 // these need to match GpsPositionRecurrence enum in gps.h 118 private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0; 119 private static final int GPS_POSITION_RECURRENCE_SINGLE = 1; 120 121 // these need to match GpsStatusValue defines in gps.h 122 private static final int GPS_STATUS_NONE = 0; 123 private static final int GPS_STATUS_SESSION_BEGIN = 1; 124 private static final int GPS_STATUS_SESSION_END = 2; 125 private static final int GPS_STATUS_ENGINE_ON = 3; 126 private static final int GPS_STATUS_ENGINE_OFF = 4; 127 128 // these need to match GpsApgsStatusValue defines in gps.h 129 /** AGPS status event values. */ 130 private static final int GPS_REQUEST_AGPS_DATA_CONN = 1; 131 private static final int GPS_RELEASE_AGPS_DATA_CONN = 2; 132 private static final int GPS_AGPS_DATA_CONNECTED = 3; 133 private static final int GPS_AGPS_DATA_CONN_DONE = 4; 134 private static final int GPS_AGPS_DATA_CONN_FAILED = 5; 135 136 // these need to match GpsLocationFlags enum in gps.h 137 private static final int LOCATION_INVALID = 0; 138 private static final int LOCATION_HAS_LAT_LONG = 1; 139 private static final int LOCATION_HAS_ALTITUDE = 2; 140 private static final int LOCATION_HAS_SPEED = 4; 141 private static final int LOCATION_HAS_BEARING = 8; 142 private static final int LOCATION_HAS_ACCURACY = 16; 143 144 // IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h 145 private static final int GPS_DELETE_EPHEMERIS = 0x0001; 146 private static final int GPS_DELETE_ALMANAC = 0x0002; 147 private static final int GPS_DELETE_POSITION = 0x0004; 148 private static final int GPS_DELETE_TIME = 0x0008; 149 private static final int GPS_DELETE_IONO = 0x0010; 150 private static final int GPS_DELETE_UTC = 0x0020; 151 private static final int GPS_DELETE_HEALTH = 0x0040; 152 private static final int GPS_DELETE_SVDIR = 0x0080; 153 private static final int GPS_DELETE_SVSTEER = 0x0100; 154 private static final int GPS_DELETE_SADATA = 0x0200; 155 private static final int GPS_DELETE_RTI = 0x0400; 156 private static final int GPS_DELETE_CELLDB_INFO = 0x8000; 157 private static final int GPS_DELETE_ALL = 0xFFFF; 158 159 // The GPS_CAPABILITY_* flags must match the values in gps.h 160 private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001; 161 private static final int GPS_CAPABILITY_MSB = 0x0000002; 162 private static final int GPS_CAPABILITY_MSA = 0x0000004; 163 private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008; 164 private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010; 165 private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020; 166 private static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040; 167 private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080; 168 169 // The AGPS SUPL mode 170 private static final int AGPS_SUPL_MODE_MSA = 0x02; 171 private static final int AGPS_SUPL_MODE_MSB = 0x01; 172 173 // these need to match AGpsType enum in gps.h 174 private static final int AGPS_TYPE_SUPL = 1; 175 private static final int AGPS_TYPE_C2K = 2; 176 177 // these must match the definitions in gps.h 178 private static final int APN_INVALID = 0; 179 private static final int APN_IPV4 = 1; 180 private static final int APN_IPV6 = 2; 181 private static final int APN_IPV4V6 = 3; 182 183 // for mAGpsDataConnectionState 184 private static final int AGPS_DATA_CONNECTION_CLOSED = 0; 185 private static final int AGPS_DATA_CONNECTION_OPENING = 1; 186 private static final int AGPS_DATA_CONNECTION_OPEN = 2; 187 188 // Handler messages 189 private static final int CHECK_LOCATION = 1; 190 private static final int ENABLE = 2; 191 private static final int SET_REQUEST = 3; 192 private static final int UPDATE_NETWORK_STATE = 4; 193 private static final int INJECT_NTP_TIME = 5; 194 private static final int DOWNLOAD_XTRA_DATA = 6; 195 private static final int UPDATE_LOCATION = 7; 196 private static final int ADD_LISTENER = 8; 197 private static final int REMOVE_LISTENER = 9; 198 private static final int INJECT_NTP_TIME_FINISHED = 10; 199 private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11; 200 private static final int SUBSCRIPTION_OR_SIM_CHANGED = 12; 201 private static final int INITIALIZE_HANDLER = 13; 202 203 // Request setid 204 private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1; 205 private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2; 206 207 // Request ref location 208 private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1; 209 private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2; 210 211 // ref. location info 212 private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1; 213 private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2; 214 private static final int AGPS_REG_LOCATION_TYPE_MAC = 3; 215 216 // set id info 217 private static final int AGPS_SETID_TYPE_NONE = 0; 218 private static final int AGPS_SETID_TYPE_IMSI = 1; 219 private static final int AGPS_SETID_TYPE_MSISDN = 2; 220 221 private static final String PROPERTIES_FILE_PREFIX = "/etc/gps"; 222 private static final String PROPERTIES_FILE_SUFFIX = ".conf"; 223 private static final String DEFAULT_PROPERTIES_FILE = PROPERTIES_FILE_PREFIX + PROPERTIES_FILE_SUFFIX; 224 225 private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L; 226 private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L; 227 228 // GPS Geofence errors. Should match gps.h constants. 229 private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0; 230 private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100; 231 private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101; 232 private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102; 233 private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103; 234 private static final int GPS_GEOFENCE_ERROR_GENERIC = -149; 235 236 // TCP/IP constants. 237 // Valid TCP/UDP port range is (0, 65535]. 238 private static final int TCP_MIN_PORT = 0; 239 private static final int TCP_MAX_PORT = 0xffff; 240 241 // Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode. 242 private static final int BATTERY_SAVER_MODE_NO_CHANGE = 0; 243 // Value of batterySaverGpsMode such that GPS is disabled when battery saver mode 244 // is enabled and the screen is off. 245 private static final int BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF = 1; 246 // Secure setting for GPS behavior when battery saver mode is on. 247 private static final String BATTERY_SAVER_GPS_MODE = "batterySaverGpsMode"; 248 249 /** simpler wrapper for ProviderRequest + Worksource */ 250 private static class GpsRequest { 251 public ProviderRequest request; 252 public WorkSource source; 253 public GpsRequest(ProviderRequest request, WorkSource source) { 254 this.request = request; 255 this.source = source; 256 } 257 } 258 259 private Object mLock = new Object(); 260 261 private int mLocationFlags = LOCATION_INVALID; 262 263 // current status 264 private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE; 265 266 // time for last status update 267 private long mStatusUpdateTime = SystemClock.elapsedRealtime(); 268 269 // turn off GPS fix icon if we haven't received a fix in 10 seconds 270 private static final long RECENT_FIX_TIMEOUT = 10 * 1000; 271 272 // stop trying if we do not receive a fix within 60 seconds 273 private static final int NO_FIX_TIMEOUT = 60 * 1000; 274 275 // if the fix interval is below this we leave GPS on, 276 // if above then we cycle the GPS driver. 277 // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane. 278 private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000; 279 280 // how often to request NTP time, in milliseconds 281 // current setting 24 hours 282 private static final long NTP_INTERVAL = 24*60*60*1000; 283 // how long to wait if we have a network error in NTP or XTRA downloading 284 // the initial value of the exponential backoff 285 // current setting - 5 minutes 286 private static final long RETRY_INTERVAL = 5*60*1000; 287 // how long to wait if we have a network error in NTP or XTRA downloading 288 // the max value of the exponential backoff 289 // current setting - 4 hours 290 private static final long MAX_RETRY_INTERVAL = 4*60*60*1000; 291 292 private BackOff mNtpBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL); 293 private BackOff mXtraBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL); 294 295 // true if we are enabled, protected by this 296 private boolean mEnabled; 297 298 // true if we have network connectivity 299 private boolean mNetworkAvailable; 300 301 // states for injecting ntp and downloading xtra data 302 private static final int STATE_PENDING_NETWORK = 0; 303 private static final int STATE_DOWNLOADING = 1; 304 private static final int STATE_IDLE = 2; 305 306 // flags to trigger NTP or XTRA data download when network becomes available 307 // initialized to true so we do NTP and XTRA when the network comes up after booting 308 private int mInjectNtpTimePending = STATE_PENDING_NETWORK; 309 private int mDownloadXtraDataPending = STATE_PENDING_NETWORK; 310 311 // set to true if the GPS engine does not do on-demand NTP time requests 312 private boolean mPeriodicTimeInjection; 313 314 // true if GPS is navigating 315 private boolean mNavigating; 316 317 // true if GPS engine is on 318 private boolean mEngineOn; 319 320 // requested frequency of fixes, in milliseconds 321 private int mFixInterval = 1000; 322 323 // true if we started navigation 324 private boolean mStarted; 325 326 // true if single shot request is in progress 327 private boolean mSingleShot; 328 329 // capabilities of the GPS engine 330 private int mEngineCapabilities; 331 332 // true if XTRA is supported 333 private boolean mSupportsXtra; 334 335 // for calculating time to first fix 336 private long mFixRequestTime = 0; 337 // time to first fix for most recent session 338 private int mTimeToFirstFix = 0; 339 // time we received our last fix 340 private long mLastFixTime; 341 342 private int mPositionMode; 343 344 // Current request from underlying location clients. 345 private ProviderRequest mProviderRequest = null; 346 // Current list of underlying location clients. 347 private WorkSource mWorkSource = null; 348 // True if gps should be disabled (used to support battery saver mode in settings). 349 private boolean mDisableGps = false; 350 351 /** 352 * Properties loaded from PROPERTIES_FILE. 353 * It must be accessed only inside {@link #mHandler}. 354 */ 355 private Properties mProperties; 356 357 private String mSuplServerHost; 358 private int mSuplServerPort = TCP_MIN_PORT; 359 private String mC2KServerHost; 360 private int mC2KServerPort; 361 private boolean mSuplEsEnabled = false; 362 363 private final Context mContext; 364 private final NtpTrustedTime mNtpTime; 365 private final ILocationManager mILocationManager; 366 private Location mLocation = new Location(LocationManager.GPS_PROVIDER); 367 private Bundle mLocationExtras = new Bundle(); 368 private final GpsStatusListenerHelper mListenerHelper; 369 private final GpsMeasurementsProvider mGpsMeasurementsProvider; 370 private final GpsNavigationMessageProvider mGpsNavigationMessageProvider; 371 372 // Handler for processing events 373 private Handler mHandler; 374 375 private String mAGpsApn; 376 private int mApnIpType; 377 private int mAGpsDataConnectionState; 378 private InetAddress mAGpsDataConnectionIpAddr; 379 private final ConnectivityManager mConnMgr; 380 private final GpsNetInitiatedHandler mNIHandler; 381 382 // Wakelocks 383 private final static String WAKELOCK_KEY = "GpsLocationProvider"; 384 private final PowerManager.WakeLock mWakeLock; 385 386 // Alarms 387 private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP"; 388 private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT"; 389 390 // SIM/Carrier info. 391 private final static String SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED"; 392 393 private final PowerManager mPowerManager; 394 private final AlarmManager mAlarmManager; 395 private final PendingIntent mWakeupIntent; 396 private final PendingIntent mTimeoutIntent; 397 398 private final IAppOpsService mAppOpsService; 399 private final IBatteryStats mBatteryStats; 400 401 // only modified on handler thread 402 private WorkSource mClientSource = new WorkSource(); 403 404 private GeofenceHardwareImpl mGeofenceHardwareImpl; 405 406 private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() { 407 @Override 408 public void addGpsStatusListener(IGpsStatusListener listener) { 409 mListenerHelper.addListener(listener); 410 } 411 412 @Override 413 public void removeGpsStatusListener(IGpsStatusListener listener) { 414 mListenerHelper.removeListener(listener); 415 } 416 }; 417 418 public IGpsStatusProvider getGpsStatusProvider() { 419 return mGpsStatusProvider; 420 } 421 422 public IGpsGeofenceHardware getGpsGeofenceProxy() { 423 return mGpsGeofenceBinder; 424 } 425 426 public GpsMeasurementsProvider getGpsMeasurementsProvider() { 427 return mGpsMeasurementsProvider; 428 } 429 430 public GpsNavigationMessageProvider getGpsNavigationMessageProvider() { 431 return mGpsNavigationMessageProvider; 432 } 433 434 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 435 @Override public void onReceive(Context context, Intent intent) { 436 String action = intent.getAction(); 437 438 if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action); 439 if (action.equals(ALARM_WAKEUP)) { 440 startNavigating(false); 441 } else if (action.equals(ALARM_TIMEOUT)) { 442 hibernate(); 443 } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) { 444 checkSmsSuplInit(intent); 445 } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) { 446 checkWapSuplInit(intent); 447 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 448 // retrieve NetworkInfo result for this UID 449 NetworkInfo info = 450 intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO); 451 ConnectivityManager connManager = (ConnectivityManager) 452 mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 453 info = connManager.getNetworkInfo(info.getType()); 454 455 int networkState; 456 if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false) || 457 !info.isConnected()) { 458 networkState = LocationProvider.TEMPORARILY_UNAVAILABLE; 459 } else { 460 networkState = LocationProvider.AVAILABLE; 461 } 462 463 updateNetworkState(networkState, info); 464 } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action) 465 || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action) 466 || Intent.ACTION_SCREEN_OFF.equals(action) 467 || Intent.ACTION_SCREEN_ON.equals(action)) { 468 updateLowPowerMode(); 469 } else if (action.equals(SIM_STATE_CHANGED)) { 470 subscriptionOrSimChanged(context); 471 } 472 } 473 }; 474 475 private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener = 476 new OnSubscriptionsChangedListener() { 477 @Override 478 public void onSubscriptionsChanged() { 479 sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null); 480 } 481 }; 482 483 private void subscriptionOrSimChanged(Context context) { 484 Log.d(TAG, "received SIM related action: "); 485 TelephonyManager phone = (TelephonyManager) 486 mContext.getSystemService(Context.TELEPHONY_SERVICE); 487 String mccMnc = phone.getSimOperator(); 488 if (!TextUtils.isEmpty(mccMnc)) { 489 Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc); 490 synchronized (mLock) { 491 reloadGpsProperties(context, mProperties); 492 mNIHandler.setSuplEsEnabled(mSuplEsEnabled); 493 } 494 } else { 495 Log.d(TAG, "SIM MCC/MNC is still not available"); 496 } 497 } 498 499 private void checkSmsSuplInit(Intent intent) { 500 SmsMessage[] messages = Intents.getMessagesFromIntent(intent); 501 for (int i=0; i <messages.length; i++) { 502 byte[] supl_init = messages[i].getUserData(); 503 native_agps_ni_message(supl_init,supl_init.length); 504 } 505 } 506 507 private void checkWapSuplInit(Intent intent) { 508 byte[] supl_init = (byte[]) intent.getExtra("data"); 509 native_agps_ni_message(supl_init,supl_init.length); 510 } 511 512 private void updateLowPowerMode() { 513 // Disable GPS if we are in device idle mode. 514 boolean disableGps = mPowerManager.isDeviceIdleMode(); 515 switch (Settings.Secure.getInt(mContext.getContentResolver(), BATTERY_SAVER_GPS_MODE, 516 BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF)) { 517 case BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF: 518 // If we are in battery saver mode and the screen is off, disable GPS. 519 disableGps |= mPowerManager.isPowerSaveMode() && !mPowerManager.isInteractive(); 520 break; 521 } 522 if (disableGps != mDisableGps) { 523 mDisableGps = disableGps; 524 updateRequirements(); 525 } 526 } 527 528 public static boolean isSupported() { 529 return native_is_supported(); 530 } 531 532 private void reloadGpsProperties(Context context, Properties properties) { 533 Log.d(TAG, "Reset GPS properties, previous size = " + properties.size()); 534 loadPropertiesFromResource(context, properties); 535 boolean isPropertiesLoadedFromFile = false; 536 final String gpsHardware = SystemProperties.get("ro.hardware.gps"); 537 if (!TextUtils.isEmpty(gpsHardware)) { 538 final String propFilename = 539 PROPERTIES_FILE_PREFIX + "." + gpsHardware + PROPERTIES_FILE_SUFFIX; 540 isPropertiesLoadedFromFile = 541 loadPropertiesFromFile(propFilename, properties); 542 } 543 if (!isPropertiesLoadedFromFile) { 544 loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties); 545 } 546 Log.d(TAG, "GPS properties reloaded, size = " + properties.size()); 547 548 // TODO: we should get rid of C2K specific setting. 549 setSuplHostPort(properties.getProperty("SUPL_HOST"), 550 properties.getProperty("SUPL_PORT")); 551 mC2KServerHost = properties.getProperty("C2K_HOST"); 552 String portString = properties.getProperty("C2K_PORT"); 553 if (mC2KServerHost != null && portString != null) { 554 try { 555 mC2KServerPort = Integer.parseInt(portString); 556 } catch (NumberFormatException e) { 557 Log.e(TAG, "unable to parse C2K_PORT: " + portString); 558 } 559 } 560 561 if (native_is_gnss_configuration_supported()) { 562 try { 563 // Convert properties to string contents and send it to HAL. 564 ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); 565 properties.store(baos, null); 566 native_configuration_update(baos.toString()); 567 Log.d(TAG, "final config = " + baos.toString()); 568 } catch (IOException ex) { 569 Log.w(TAG, "failed to dump properties contents"); 570 } 571 } else if (DEBUG) { 572 Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not" 573 + " supported"); 574 } 575 576 // SUPL_ES configuration. 577 String suplESProperty = mProperties.getProperty("SUPL_ES"); 578 if (suplESProperty != null) { 579 try { 580 mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1); 581 } catch (NumberFormatException e) { 582 Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty); 583 } 584 } 585 } 586 587 private void loadPropertiesFromResource(Context context, 588 Properties properties) { 589 String[] configValues = context.getResources().getStringArray( 590 com.android.internal.R.array.config_gpsParameters); 591 for (String item : configValues) { 592 Log.d(TAG, "GpsParamsResource: " + item); 593 // We need to support "KEY =", but not "=VALUE". 594 String[] split = item.split("="); 595 if (split.length == 2) { 596 properties.setProperty(split[0].trim().toUpperCase(), split[1]); 597 } else { 598 Log.w(TAG, "malformed contents: " + item); 599 } 600 } 601 } 602 603 private boolean loadPropertiesFromFile(String filename, 604 Properties properties) { 605 try { 606 File file = new File(filename); 607 FileInputStream stream = null; 608 try { 609 stream = new FileInputStream(file); 610 properties.load(stream); 611 } finally { 612 IoUtils.closeQuietly(stream); 613 } 614 615 } catch (IOException e) { 616 Log.w(TAG, "Could not open GPS configuration file " + filename); 617 return false; 618 } 619 return true; 620 } 621 622 public GpsLocationProvider(Context context, ILocationManager ilocationManager, 623 Looper looper) { 624 mContext = context; 625 mNtpTime = NtpTrustedTime.getInstance(context); 626 mILocationManager = ilocationManager; 627 628 mLocation.setExtras(mLocationExtras); 629 630 // Create a wake lock 631 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 632 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 633 mWakeLock.setReferenceCounted(true); 634 635 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 636 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0); 637 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0); 638 639 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); 640 641 // App ops service to keep track of who is accessing the GPS 642 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService( 643 Context.APP_OPS_SERVICE)); 644 645 // Battery statistics service to be notified when GPS turns on or off 646 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 647 BatteryStats.SERVICE_NAME)); 648 649 // Construct internal handler 650 mHandler = new ProviderHandler(looper); 651 652 // Load GPS configuration and register listeners in the background: 653 // some operations, such as opening files and registering broadcast receivers, can take a 654 // relative long time, so the ctor() is kept to create objects needed by this instance, 655 // while IO initialization and registration is delegated to our internal handler 656 // this approach is just fine because events are posted to our handler anyway 657 mProperties = new Properties(); 658 sendMessage(INITIALIZE_HANDLER, 0, null); 659 660 // Create a GPS net-initiated handler. 661 mNIHandler = new GpsNetInitiatedHandler(context, 662 mNetInitiatedListener, 663 mSuplEsEnabled); 664 665 mListenerHelper = new GpsStatusListenerHelper(mHandler) { 666 @Override 667 protected boolean isAvailableInPlatform() { 668 return isSupported(); 669 } 670 671 @Override 672 protected boolean isGpsEnabled() { 673 return isEnabled(); 674 } 675 }; 676 677 mGpsMeasurementsProvider = new GpsMeasurementsProvider(mHandler) { 678 @Override 679 public boolean isAvailableInPlatform() { 680 return native_is_measurement_supported(); 681 } 682 683 @Override 684 protected boolean registerWithService() { 685 return native_start_measurement_collection(); 686 } 687 688 @Override 689 protected void unregisterFromService() { 690 native_stop_measurement_collection(); 691 } 692 693 @Override 694 protected boolean isGpsEnabled() { 695 return isEnabled(); 696 } 697 }; 698 699 mGpsNavigationMessageProvider = new GpsNavigationMessageProvider(mHandler) { 700 @Override 701 protected boolean isAvailableInPlatform() { 702 return native_is_navigation_message_supported(); 703 } 704 705 @Override 706 protected boolean registerWithService() { 707 return native_start_navigation_message_collection(); 708 } 709 710 @Override 711 protected void unregisterFromService() { 712 native_stop_navigation_message_collection(); 713 } 714 715 @Override 716 protected boolean isGpsEnabled() { 717 return isEnabled(); 718 } 719 }; 720 } 721 722 /** 723 * Returns the name of this provider. 724 */ 725 @Override 726 public String getName() { 727 return LocationManager.GPS_PROVIDER; 728 } 729 730 @Override 731 public ProviderProperties getProperties() { 732 return PROPERTIES; 733 } 734 735 public void updateNetworkState(int state, NetworkInfo info) { 736 sendMessage(UPDATE_NETWORK_STATE, state, info); 737 } 738 739 private void handleUpdateNetworkState(int state, NetworkInfo info) { 740 mNetworkAvailable = (state == LocationProvider.AVAILABLE); 741 742 if (DEBUG) { 743 Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable") 744 + " info: " + info); 745 } 746 747 if (info != null) { 748 if (native_is_agps_ril_supported()) { 749 boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled(); 750 boolean networkAvailable = info.isAvailable() && dataEnabled; 751 String defaultApn = getSelectedApn(); 752 if (defaultApn == null) { 753 defaultApn = "dummy-apn"; 754 } 755 756 native_update_network_state(info.isConnected(), info.getType(), 757 info.isRoaming(), networkAvailable, 758 info.getExtraInfo(), defaultApn); 759 } else if (DEBUG) { 760 Log.d(TAG, "Skipped network state update because AGPS-RIL in GPS HAL is not" 761 + " supported"); 762 } 763 } 764 765 if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL 766 && mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { 767 if (mNetworkAvailable) { 768 String apnName = info.getExtraInfo(); 769 if (apnName == null) { 770 /* Assign a dummy value in the case of C2K as otherwise we will have a runtime 771 exception in the following call to native_agps_data_conn_open*/ 772 apnName = "dummy-apn"; 773 } 774 mAGpsApn = apnName; 775 mApnIpType = getApnIpType(apnName); 776 setRouting(); 777 if (DEBUG) { 778 String message = String.format( 779 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s", 780 mAGpsApn, mApnIpType); 781 Log.d(TAG, message); 782 } 783 native_agps_data_conn_open(mAGpsApn, mApnIpType); 784 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 785 } else { 786 Log.e(TAG, "call native_agps_data_conn_failed, info: " + info); 787 mAGpsApn = null; 788 mApnIpType = APN_INVALID; 789 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 790 native_agps_data_conn_failed(); 791 } 792 } 793 794 if (mNetworkAvailable) { 795 if (mInjectNtpTimePending == STATE_PENDING_NETWORK) { 796 sendMessage(INJECT_NTP_TIME, 0, null); 797 } 798 if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) { 799 sendMessage(DOWNLOAD_XTRA_DATA, 0, null); 800 } 801 } 802 } 803 804 private void handleInjectNtpTime() { 805 if (mInjectNtpTimePending == STATE_DOWNLOADING) { 806 // already downloading data 807 return; 808 } 809 if (!mNetworkAvailable) { 810 // try again when network is up 811 mInjectNtpTimePending = STATE_PENDING_NETWORK; 812 return; 813 } 814 mInjectNtpTimePending = STATE_DOWNLOADING; 815 816 // hold wake lock while task runs 817 mWakeLock.acquire(); 818 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { 819 @Override 820 public void run() { 821 long delay; 822 823 // force refresh NTP cache when outdated 824 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) { 825 mNtpTime.forceRefresh(); 826 } 827 828 // only update when NTP time is fresh 829 if (mNtpTime.getCacheAge() < NTP_INTERVAL) { 830 long time = mNtpTime.getCachedNtpTime(); 831 long timeReference = mNtpTime.getCachedNtpTimeReference(); 832 long certainty = mNtpTime.getCacheCertainty(); 833 long now = System.currentTimeMillis(); 834 835 Log.d(TAG, "NTP server returned: " 836 + time + " (" + new Date(time) 837 + ") reference: " + timeReference 838 + " certainty: " + certainty 839 + " system time offset: " + (time - now)); 840 841 native_inject_time(time, timeReference, (int) certainty); 842 delay = NTP_INTERVAL; 843 mNtpBackOff.reset(); 844 } else { 845 if (DEBUG) Log.d(TAG, "requestTime failed"); 846 delay = mNtpBackOff.nextBackoffMillis(); 847 } 848 849 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null); 850 851 if (mPeriodicTimeInjection) { 852 // send delayed message for next NTP injection 853 // since this is delayed and not urgent we do not hold a wake lock here 854 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay); 855 } 856 857 // release wake lock held by task 858 mWakeLock.release(); 859 } 860 }); 861 } 862 863 private void handleDownloadXtraData() { 864 if (mDownloadXtraDataPending == STATE_DOWNLOADING) { 865 // already downloading data 866 return; 867 } 868 if (!mNetworkAvailable) { 869 // try again when network is up 870 mDownloadXtraDataPending = STATE_PENDING_NETWORK; 871 return; 872 } 873 mDownloadXtraDataPending = STATE_DOWNLOADING; 874 875 // hold wake lock while task runs 876 mWakeLock.acquire(); 877 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { 878 @Override 879 public void run() { 880 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties); 881 byte[] data = xtraDownloader.downloadXtraData(); 882 if (data != null) { 883 if (DEBUG) { 884 Log.d(TAG, "calling native_inject_xtra_data"); 885 } 886 native_inject_xtra_data(data, data.length); 887 mXtraBackOff.reset(); 888 } 889 890 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null); 891 892 if (data == null) { 893 // try again later 894 // since this is delayed and not urgent we do not hold a wake lock here 895 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA, 896 mXtraBackOff.nextBackoffMillis()); 897 } 898 899 // release wake lock held by task 900 mWakeLock.release(); 901 } 902 }); 903 } 904 905 private void handleUpdateLocation(Location location) { 906 if (location.hasAccuracy()) { 907 native_inject_location(location.getLatitude(), location.getLongitude(), 908 location.getAccuracy()); 909 } 910 } 911 912 /** 913 * Enables this provider. When enabled, calls to getStatus() 914 * must be handled. Hardware may be started up 915 * when the provider is enabled. 916 */ 917 @Override 918 public void enable() { 919 synchronized (mLock) { 920 if (mEnabled) return; 921 mEnabled = true; 922 } 923 924 sendMessage(ENABLE, 1, null); 925 } 926 927 private void setSuplHostPort(String hostString, String portString) { 928 if (hostString != null) { 929 mSuplServerHost = hostString; 930 } 931 if (portString != null) { 932 try { 933 mSuplServerPort = Integer.parseInt(portString); 934 } catch (NumberFormatException e) { 935 Log.e(TAG, "unable to parse SUPL_PORT: " + portString); 936 } 937 } 938 if (mSuplServerHost != null 939 && mSuplServerPort > TCP_MIN_PORT 940 && mSuplServerPort <= TCP_MAX_PORT) { 941 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); 942 } 943 } 944 945 /** 946 * Checks what SUPL mode to use, according to the AGPS mode as well as the 947 * allowed mode from properties. 948 * 949 * @param properties GPS properties 950 * @param agpsEnabled whether AGPS is enabled by settings value 951 * @param singleShot whether "singleshot" is needed 952 * @return SUPL mode (MSA vs MSB vs STANDALONE) 953 */ 954 private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) { 955 if (agpsEnabled) { 956 String modeString = properties.getProperty("SUPL_MODE"); 957 int suplMode = 0; 958 if (!TextUtils.isEmpty(modeString)) { 959 try { 960 suplMode = Integer.parseInt(modeString); 961 } catch (NumberFormatException e) { 962 Log.e(TAG, "unable to parse SUPL_MODE: " + modeString); 963 return GPS_POSITION_MODE_STANDALONE; 964 } 965 } 966 // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor 967 // such mode when it is available 968 if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) { 969 return GPS_POSITION_MODE_MS_BASED; 970 } 971 // for now, just as the legacy code did, we fallback to MS-Assisted if it is available, 972 // do fallback only for single-shot requests, because it is too expensive to do for 973 // periodic requests as well 974 if (singleShot 975 && hasCapability(GPS_CAPABILITY_MSA) 976 && (suplMode & AGPS_SUPL_MODE_MSA) != 0) { 977 return GPS_POSITION_MODE_MS_ASSISTED; 978 } 979 } 980 return GPS_POSITION_MODE_STANDALONE; 981 } 982 983 private void handleEnable() { 984 if (DEBUG) Log.d(TAG, "handleEnable"); 985 986 boolean enabled = native_init(); 987 988 if (enabled) { 989 mSupportsXtra = native_supports_xtra(); 990 991 // TODO: remove the following native calls if we can make sure they are redundant. 992 if (mSuplServerHost != null) { 993 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); 994 } 995 if (mC2KServerHost != null) { 996 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort); 997 } 998 999 mGpsMeasurementsProvider.onGpsEnabledChanged(); 1000 mGpsNavigationMessageProvider.onGpsEnabledChanged(); 1001 } else { 1002 synchronized (mLock) { 1003 mEnabled = false; 1004 } 1005 Log.w(TAG, "Failed to enable location provider"); 1006 } 1007 } 1008 1009 /** 1010 * Disables this provider. When disabled, calls to getStatus() 1011 * need not be handled. Hardware may be shut 1012 * down while the provider is disabled. 1013 */ 1014 @Override 1015 public void disable() { 1016 synchronized (mLock) { 1017 if (!mEnabled) return; 1018 mEnabled = false; 1019 } 1020 1021 sendMessage(ENABLE, 0, null); 1022 } 1023 1024 private void handleDisable() { 1025 if (DEBUG) Log.d(TAG, "handleDisable"); 1026 1027 updateClientUids(new WorkSource()); 1028 stopNavigating(); 1029 mAlarmManager.cancel(mWakeupIntent); 1030 mAlarmManager.cancel(mTimeoutIntent); 1031 1032 // do this before releasing wakelock 1033 native_cleanup(); 1034 1035 mGpsMeasurementsProvider.onGpsEnabledChanged(); 1036 mGpsNavigationMessageProvider.onGpsEnabledChanged(); 1037 } 1038 1039 @Override 1040 public boolean isEnabled() { 1041 synchronized (mLock) { 1042 return mEnabled; 1043 } 1044 } 1045 1046 @Override 1047 public int getStatus(Bundle extras) { 1048 if (extras != null) { 1049 extras.putInt("satellites", mSvCount); 1050 } 1051 return mStatus; 1052 } 1053 1054 private void updateStatus(int status, int svCount) { 1055 if (status != mStatus || svCount != mSvCount) { 1056 mStatus = status; 1057 mSvCount = svCount; 1058 mLocationExtras.putInt("satellites", svCount); 1059 mStatusUpdateTime = SystemClock.elapsedRealtime(); 1060 } 1061 } 1062 1063 @Override 1064 public long getStatusUpdateTime() { 1065 return mStatusUpdateTime; 1066 } 1067 1068 @Override 1069 public void setRequest(ProviderRequest request, WorkSource source) { 1070 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source)); 1071 } 1072 1073 private void handleSetRequest(ProviderRequest request, WorkSource source) { 1074 mProviderRequest = request; 1075 mWorkSource = source; 1076 updateRequirements(); 1077 } 1078 1079 // Called when the requirements for GPS may have changed 1080 private void updateRequirements() { 1081 if (mProviderRequest == null || mWorkSource == null) { 1082 return; 1083 } 1084 1085 boolean singleShot = false; 1086 1087 // see if the request is for a single update 1088 if (mProviderRequest.locationRequests != null 1089 && mProviderRequest.locationRequests.size() > 0) { 1090 // if any request has zero or more than one updates 1091 // requested, then this is not single-shot mode 1092 singleShot = true; 1093 1094 for (LocationRequest lr : mProviderRequest.locationRequests) { 1095 if (lr.getNumUpdates() != 1) { 1096 singleShot = false; 1097 } 1098 } 1099 } 1100 1101 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest); 1102 if (mProviderRequest.reportLocation && !mDisableGps) { 1103 // update client uids 1104 updateClientUids(mWorkSource); 1105 1106 mFixInterval = (int) mProviderRequest.interval; 1107 1108 // check for overflow 1109 if (mFixInterval != mProviderRequest.interval) { 1110 Log.w(TAG, "interval overflow: " + mProviderRequest.interval); 1111 mFixInterval = Integer.MAX_VALUE; 1112 } 1113 1114 // apply request to GPS engine 1115 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) { 1116 // change period 1117 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 1118 mFixInterval, 0, 0)) { 1119 Log.e(TAG, "set_position_mode failed in setMinTime()"); 1120 } 1121 } else if (!mStarted) { 1122 // start GPS 1123 startNavigating(singleShot); 1124 } 1125 } else { 1126 updateClientUids(new WorkSource()); 1127 1128 stopNavigating(); 1129 mAlarmManager.cancel(mWakeupIntent); 1130 mAlarmManager.cancel(mTimeoutIntent); 1131 } 1132 } 1133 1134 private void updateClientUids(WorkSource source) { 1135 // Update work source. 1136 WorkSource[] changes = mClientSource.setReturningDiffs(source); 1137 if (changes == null) { 1138 return; 1139 } 1140 WorkSource newWork = changes[0]; 1141 WorkSource goneWork = changes[1]; 1142 1143 // Update sources that were not previously tracked. 1144 if (newWork != null) { 1145 int lastuid = -1; 1146 for (int i=0; i<newWork.size(); i++) { 1147 try { 1148 int uid = newWork.get(i); 1149 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), 1150 AppOpsManager.OP_GPS, uid, newWork.getName(i)); 1151 if (uid != lastuid) { 1152 lastuid = uid; 1153 mBatteryStats.noteStartGps(uid); 1154 } 1155 } catch (RemoteException e) { 1156 Log.w(TAG, "RemoteException", e); 1157 } 1158 } 1159 } 1160 1161 // Update sources that are no longer tracked. 1162 if (goneWork != null) { 1163 int lastuid = -1; 1164 for (int i=0; i<goneWork.size(); i++) { 1165 try { 1166 int uid = goneWork.get(i); 1167 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), 1168 AppOpsManager.OP_GPS, uid, goneWork.getName(i)); 1169 if (uid != lastuid) { 1170 lastuid = uid; 1171 mBatteryStats.noteStopGps(uid); 1172 } 1173 } catch (RemoteException e) { 1174 Log.w(TAG, "RemoteException", e); 1175 } 1176 } 1177 } 1178 } 1179 1180 @Override 1181 public boolean sendExtraCommand(String command, Bundle extras) { 1182 1183 long identity = Binder.clearCallingIdentity(); 1184 boolean result = false; 1185 1186 if ("delete_aiding_data".equals(command)) { 1187 result = deleteAidingData(extras); 1188 } else if ("force_time_injection".equals(command)) { 1189 sendMessage(INJECT_NTP_TIME, 0, null); 1190 result = true; 1191 } else if ("force_xtra_injection".equals(command)) { 1192 if (mSupportsXtra) { 1193 xtraDownloadRequest(); 1194 result = true; 1195 } 1196 } else { 1197 Log.w(TAG, "sendExtraCommand: unknown command " + command); 1198 } 1199 1200 Binder.restoreCallingIdentity(identity); 1201 return result; 1202 } 1203 1204 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() { 1205 public boolean isHardwareGeofenceSupported() { 1206 return native_is_geofence_supported(); 1207 } 1208 1209 public boolean addCircularHardwareGeofence(int geofenceId, double latitude, 1210 double longitude, double radius, int lastTransition, int monitorTransitions, 1211 int notificationResponsiveness, int unknownTimer) { 1212 return native_add_geofence(geofenceId, latitude, longitude, radius, 1213 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer); 1214 } 1215 1216 public boolean removeHardwareGeofence(int geofenceId) { 1217 return native_remove_geofence(geofenceId); 1218 } 1219 1220 public boolean pauseHardwareGeofence(int geofenceId) { 1221 return native_pause_geofence(geofenceId); 1222 } 1223 1224 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) { 1225 return native_resume_geofence(geofenceId, monitorTransition); 1226 } 1227 }; 1228 1229 private boolean deleteAidingData(Bundle extras) { 1230 int flags; 1231 1232 if (extras == null) { 1233 flags = GPS_DELETE_ALL; 1234 } else { 1235 flags = 0; 1236 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS; 1237 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC; 1238 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION; 1239 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME; 1240 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO; 1241 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC; 1242 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH; 1243 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR; 1244 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER; 1245 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA; 1246 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI; 1247 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO; 1248 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL; 1249 } 1250 1251 if (flags != 0) { 1252 native_delete_aiding_data(flags); 1253 return true; 1254 } 1255 1256 return false; 1257 } 1258 1259 private void startNavigating(boolean singleShot) { 1260 if (!mStarted) { 1261 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot); 1262 mTimeToFirstFix = 0; 1263 mLastFixTime = 0; 1264 mStarted = true; 1265 mSingleShot = singleShot; 1266 mPositionMode = GPS_POSITION_MODE_STANDALONE; 1267 1268 boolean agpsEnabled = 1269 (Settings.Global.getInt(mContext.getContentResolver(), 1270 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0); 1271 mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot); 1272 1273 if (DEBUG) { 1274 String mode; 1275 1276 switch(mPositionMode) { 1277 case GPS_POSITION_MODE_STANDALONE: 1278 mode = "standalone"; 1279 break; 1280 case GPS_POSITION_MODE_MS_ASSISTED: 1281 mode = "MS_ASSISTED"; 1282 break; 1283 case GPS_POSITION_MODE_MS_BASED: 1284 mode = "MS_BASED"; 1285 break; 1286 default: 1287 mode = "unknown"; 1288 break; 1289 } 1290 Log.d(TAG, "setting position_mode to " + mode); 1291 } 1292 1293 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000); 1294 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 1295 interval, 0, 0)) { 1296 mStarted = false; 1297 Log.e(TAG, "set_position_mode failed in startNavigating()"); 1298 return; 1299 } 1300 if (!native_start()) { 1301 mStarted = false; 1302 Log.e(TAG, "native_start failed in startNavigating()"); 1303 return; 1304 } 1305 1306 // reset SV count to zero 1307 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); 1308 mFixRequestTime = System.currentTimeMillis(); 1309 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) { 1310 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 1311 // and our fix interval is not short 1312 if (mFixInterval >= NO_FIX_TIMEOUT) { 1313 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1314 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); 1315 } 1316 } 1317 } 1318 } 1319 1320 private void stopNavigating() { 1321 if (DEBUG) Log.d(TAG, "stopNavigating"); 1322 if (mStarted) { 1323 mStarted = false; 1324 mSingleShot = false; 1325 native_stop(); 1326 mTimeToFirstFix = 0; 1327 mLastFixTime = 0; 1328 mLocationFlags = LOCATION_INVALID; 1329 1330 // reset SV count to zero 1331 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); 1332 } 1333 } 1334 1335 private void hibernate() { 1336 // stop GPS until our next fix interval arrives 1337 stopNavigating(); 1338 mAlarmManager.cancel(mTimeoutIntent); 1339 mAlarmManager.cancel(mWakeupIntent); 1340 long now = SystemClock.elapsedRealtime(); 1341 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent); 1342 } 1343 1344 private boolean hasCapability(int capability) { 1345 return ((mEngineCapabilities & capability) != 0); 1346 } 1347 1348 1349 /** 1350 * called from native code to update our position. 1351 */ 1352 private void reportLocation(int flags, double latitude, double longitude, double altitude, 1353 float speed, float bearing, float accuracy, long timestamp) { 1354 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude + 1355 " timestamp: " + timestamp); 1356 1357 synchronized (mLocation) { 1358 mLocationFlags = flags; 1359 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1360 mLocation.setLatitude(latitude); 1361 mLocation.setLongitude(longitude); 1362 mLocation.setTime(timestamp); 1363 // It would be nice to push the elapsed real-time timestamp 1364 // further down the stack, but this is still useful 1365 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 1366 } 1367 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { 1368 mLocation.setAltitude(altitude); 1369 } else { 1370 mLocation.removeAltitude(); 1371 } 1372 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { 1373 mLocation.setSpeed(speed); 1374 } else { 1375 mLocation.removeSpeed(); 1376 } 1377 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { 1378 mLocation.setBearing(bearing); 1379 } else { 1380 mLocation.removeBearing(); 1381 } 1382 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { 1383 mLocation.setAccuracy(accuracy); 1384 } else { 1385 mLocation.removeAccuracy(); 1386 } 1387 mLocation.setExtras(mLocationExtras); 1388 1389 try { 1390 mILocationManager.reportLocation(mLocation, false); 1391 } catch (RemoteException e) { 1392 Log.e(TAG, "RemoteException calling reportLocation"); 1393 } 1394 } 1395 1396 mLastFixTime = System.currentTimeMillis(); 1397 // report time to first fix 1398 if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1399 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime); 1400 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix); 1401 1402 // notify status listeners 1403 mListenerHelper.onFirstFix(mTimeToFirstFix); 1404 } 1405 1406 if (mSingleShot) { 1407 stopNavigating(); 1408 } 1409 1410 if (mStarted && mStatus != LocationProvider.AVAILABLE) { 1411 // we want to time out if we do not receive a fix 1412 // within the time out and we are requesting infrequent fixes 1413 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) { 1414 mAlarmManager.cancel(mTimeoutIntent); 1415 } 1416 1417 // send an intent to notify that the GPS is receiving fixes. 1418 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1419 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true); 1420 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1421 updateStatus(LocationProvider.AVAILABLE, mSvCount); 1422 } 1423 1424 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted && 1425 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { 1426 if (DEBUG) Log.d(TAG, "got fix, hibernating"); 1427 hibernate(); 1428 } 1429 } 1430 1431 /** 1432 * called from native code to update our status 1433 */ 1434 private void reportStatus(int status) { 1435 if (DEBUG) Log.v(TAG, "reportStatus status: " + status); 1436 1437 boolean wasNavigating = mNavigating; 1438 switch (status) { 1439 case GPS_STATUS_SESSION_BEGIN: 1440 mNavigating = true; 1441 mEngineOn = true; 1442 break; 1443 case GPS_STATUS_SESSION_END: 1444 mNavigating = false; 1445 break; 1446 case GPS_STATUS_ENGINE_ON: 1447 mEngineOn = true; 1448 break; 1449 case GPS_STATUS_ENGINE_OFF: 1450 mEngineOn = false; 1451 mNavigating = false; 1452 break; 1453 } 1454 1455 if (wasNavigating != mNavigating) { 1456 mListenerHelper.onStatusChanged(mNavigating); 1457 1458 // send an intent to notify that the GPS has been enabled or disabled 1459 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION); 1460 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating); 1461 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1462 } 1463 } 1464 1465 /** 1466 * called from native code to update SV info 1467 */ 1468 private void reportSvStatus() { 1469 int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks); 1470 mListenerHelper.onSvStatusChanged( 1471 svCount, 1472 mSvs, 1473 mSnrs, 1474 mSvElevations, 1475 mSvAzimuths, 1476 mSvMasks[EPHEMERIS_MASK], 1477 mSvMasks[ALMANAC_MASK], 1478 mSvMasks[USED_FOR_FIX_MASK]); 1479 1480 if (VERBOSE) { 1481 Log.v(TAG, "SV count: " + svCount + 1482 " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) + 1483 " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK])); 1484 for (int i = 0; i < svCount; i++) { 1485 Log.v(TAG, "sv: " + mSvs[i] + 1486 " snr: " + mSnrs[i]/10 + 1487 " elev: " + mSvElevations[i] + 1488 " azimuth: " + mSvAzimuths[i] + 1489 ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " E") + 1490 ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " A") + 1491 ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U")); 1492 } 1493 } 1494 1495 // return number of sets used in fix instead of total 1496 updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK])); 1497 1498 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 && 1499 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) { 1500 // send an intent to notify that the GPS is no longer receiving fixes. 1501 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1502 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false); 1503 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1504 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount); 1505 } 1506 } 1507 1508 /** 1509 * called from native code to update AGPS status 1510 */ 1511 private void reportAGpsStatus(int type, int status, byte[] ipaddr) { 1512 switch (status) { 1513 case GPS_REQUEST_AGPS_DATA_CONN: 1514 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN"); 1515 Log.v(TAG, "Received SUPL IP addr[]: " + ipaddr); 1516 // Set mAGpsDataConnectionState before calling startUsingNetworkFeature 1517 // to avoid a race condition with handleUpdateNetworkState() 1518 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; 1519 int result = mConnMgr.startUsingNetworkFeature( 1520 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); 1521 if (ipaddr != null) { 1522 try { 1523 mAGpsDataConnectionIpAddr = InetAddress.getByAddress(ipaddr); 1524 Log.v(TAG, "IP address converted to: " + mAGpsDataConnectionIpAddr); 1525 } catch (UnknownHostException e) { 1526 Log.e(TAG, "Bad IP Address: " + ipaddr, e); 1527 mAGpsDataConnectionIpAddr = null; 1528 } 1529 } 1530 1531 if (result == PhoneConstants.APN_ALREADY_ACTIVE) { 1532 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE"); 1533 if (mAGpsApn != null) { 1534 setRouting(); 1535 native_agps_data_conn_open(mAGpsApn, mApnIpType); 1536 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 1537 } else { 1538 Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE"); 1539 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1540 native_agps_data_conn_failed(); 1541 } 1542 } else if (result == PhoneConstants.APN_REQUEST_STARTED) { 1543 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_REQUEST_STARTED"); 1544 // Nothing to do here 1545 } else { 1546 if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed, value is " + 1547 result); 1548 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1549 native_agps_data_conn_failed(); 1550 } 1551 break; 1552 case GPS_RELEASE_AGPS_DATA_CONN: 1553 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN"); 1554 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) { 1555 mConnMgr.stopUsingNetworkFeature( 1556 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); 1557 native_agps_data_conn_closed(); 1558 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1559 mAGpsDataConnectionIpAddr = null; 1560 } 1561 break; 1562 case GPS_AGPS_DATA_CONNECTED: 1563 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED"); 1564 break; 1565 case GPS_AGPS_DATA_CONN_DONE: 1566 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE"); 1567 break; 1568 case GPS_AGPS_DATA_CONN_FAILED: 1569 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED"); 1570 break; 1571 default: 1572 Log.d(TAG, "Received Unknown AGPS status: " + status); 1573 } 1574 } 1575 1576 /** 1577 * called from native code to report NMEA data received 1578 */ 1579 private void reportNmea(long timestamp) { 1580 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length); 1581 String nmea = new String(mNmeaBuffer, 0 /* offset */, length); 1582 mListenerHelper.onNmeaReceived(timestamp, nmea); 1583 } 1584 1585 /** 1586 * called from native code - Gps measurements callback 1587 */ 1588 private void reportMeasurementData(GpsMeasurementsEvent event) { 1589 mGpsMeasurementsProvider.onMeasurementsAvailable(event); 1590 } 1591 1592 /** 1593 * called from native code - GPS navigation message callback 1594 */ 1595 private void reportNavigationMessage(GpsNavigationMessageEvent event) { 1596 mGpsNavigationMessageProvider.onNavigationMessageAvailable(event); 1597 } 1598 1599 /** 1600 * called from native code to inform us what the GPS engine capabilities are 1601 */ 1602 private void setEngineCapabilities(int capabilities) { 1603 mEngineCapabilities = capabilities; 1604 1605 if (!hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME) && !mPeriodicTimeInjection) { 1606 mPeriodicTimeInjection = true; 1607 requestUtcTime(); 1608 } 1609 1610 mGpsMeasurementsProvider.onCapabilitiesUpdated( 1611 (capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS); 1612 mGpsNavigationMessageProvider.onCapabilitiesUpdated( 1613 (capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES); 1614 } 1615 1616 /** 1617 * called from native code to request XTRA data 1618 */ 1619 private void xtraDownloadRequest() { 1620 if (DEBUG) Log.d(TAG, "xtraDownloadRequest"); 1621 sendMessage(DOWNLOAD_XTRA_DATA, 0, null); 1622 } 1623 1624 /** 1625 * Helper method to construct a location object. 1626 */ 1627 private Location buildLocation( 1628 int flags, 1629 double latitude, 1630 double longitude, 1631 double altitude, 1632 float speed, 1633 float bearing, 1634 float accuracy, 1635 long timestamp) { 1636 Location location = new Location(LocationManager.GPS_PROVIDER); 1637 if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1638 location.setLatitude(latitude); 1639 location.setLongitude(longitude); 1640 location.setTime(timestamp); 1641 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 1642 } 1643 if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { 1644 location.setAltitude(altitude); 1645 } 1646 if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { 1647 location.setSpeed(speed); 1648 } 1649 if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { 1650 location.setBearing(bearing); 1651 } 1652 if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { 1653 location.setAccuracy(accuracy); 1654 } 1655 return location; 1656 } 1657 1658 /** 1659 * Converts the GPS HAL status to the internal Geofence Hardware status. 1660 */ 1661 private int getGeofenceStatus(int status) { 1662 switch(status) { 1663 case GPS_GEOFENCE_OPERATION_SUCCESS: 1664 return GeofenceHardware.GEOFENCE_SUCCESS; 1665 case GPS_GEOFENCE_ERROR_GENERIC: 1666 return GeofenceHardware.GEOFENCE_FAILURE; 1667 case GPS_GEOFENCE_ERROR_ID_EXISTS: 1668 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; 1669 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION: 1670 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; 1671 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES: 1672 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; 1673 case GPS_GEOFENCE_ERROR_ID_UNKNOWN: 1674 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; 1675 default: 1676 return -1; 1677 } 1678 } 1679 1680 /** 1681 * Called from native to report GPS Geofence transition 1682 * All geofence callbacks are called on the same thread 1683 */ 1684 private void reportGeofenceTransition(int geofenceId, int flags, double latitude, 1685 double longitude, double altitude, float speed, float bearing, float accuracy, 1686 long timestamp, int transition, long transitionTimestamp) { 1687 if (mGeofenceHardwareImpl == null) { 1688 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1689 } 1690 Location location = buildLocation( 1691 flags, 1692 latitude, 1693 longitude, 1694 altitude, 1695 speed, 1696 bearing, 1697 accuracy, 1698 timestamp); 1699 mGeofenceHardwareImpl.reportGeofenceTransition( 1700 geofenceId, 1701 location, 1702 transition, 1703 transitionTimestamp, 1704 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 1705 FusedBatchOptions.SourceTechnologies.GNSS); 1706 } 1707 1708 /** 1709 * called from native code to report GPS status change. 1710 */ 1711 private void reportGeofenceStatus(int status, int flags, double latitude, 1712 double longitude, double altitude, float speed, float bearing, float accuracy, 1713 long timestamp) { 1714 if (mGeofenceHardwareImpl == null) { 1715 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1716 } 1717 Location location = buildLocation( 1718 flags, 1719 latitude, 1720 longitude, 1721 altitude, 1722 speed, 1723 bearing, 1724 accuracy, 1725 timestamp); 1726 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; 1727 if(status == GPS_GEOFENCE_AVAILABLE) { 1728 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; 1729 } 1730 mGeofenceHardwareImpl.reportGeofenceMonitorStatus( 1731 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 1732 monitorStatus, 1733 location, 1734 FusedBatchOptions.SourceTechnologies.GNSS); 1735 } 1736 1737 /** 1738 * called from native code - Geofence Add callback 1739 */ 1740 private void reportGeofenceAddStatus(int geofenceId, int status) { 1741 if (mGeofenceHardwareImpl == null) { 1742 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1743 } 1744 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status)); 1745 } 1746 1747 /** 1748 * called from native code - Geofence Remove callback 1749 */ 1750 private void reportGeofenceRemoveStatus(int geofenceId, int status) { 1751 if (mGeofenceHardwareImpl == null) { 1752 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1753 } 1754 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status)); 1755 } 1756 1757 /** 1758 * called from native code - Geofence Pause callback 1759 */ 1760 private void reportGeofencePauseStatus(int geofenceId, int status) { 1761 if (mGeofenceHardwareImpl == null) { 1762 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1763 } 1764 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status)); 1765 } 1766 1767 /** 1768 * called from native code - Geofence Resume callback 1769 */ 1770 private void reportGeofenceResumeStatus(int geofenceId, int status) { 1771 if (mGeofenceHardwareImpl == null) { 1772 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1773 } 1774 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status)); 1775 } 1776 1777 //============================================================= 1778 // NI Client support 1779 //============================================================= 1780 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() { 1781 // Sends a response for an NI request to HAL. 1782 @Override 1783 public boolean sendNiResponse(int notificationId, int userResponse) 1784 { 1785 // TODO Add Permission check 1786 1787 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId + 1788 ", response: " + userResponse); 1789 native_send_ni_response(notificationId, userResponse); 1790 return true; 1791 } 1792 }; 1793 1794 public INetInitiatedListener getNetInitiatedListener() { 1795 return mNetInitiatedListener; 1796 } 1797 1798 // Called by JNI function to report an NI request. 1799 public void reportNiNotification( 1800 int notificationId, 1801 int niType, 1802 int notifyFlags, 1803 int timeout, 1804 int defaultResponse, 1805 String requestorId, 1806 String text, 1807 int requestorIdEncoding, 1808 int textEncoding, 1809 String extras // Encoded extra data 1810 ) 1811 { 1812 Log.i(TAG, "reportNiNotification: entered"); 1813 Log.i(TAG, "notificationId: " + notificationId + 1814 ", niType: " + niType + 1815 ", notifyFlags: " + notifyFlags + 1816 ", timeout: " + timeout + 1817 ", defaultResponse: " + defaultResponse); 1818 1819 Log.i(TAG, "requestorId: " + requestorId + 1820 ", text: " + text + 1821 ", requestorIdEncoding: " + requestorIdEncoding + 1822 ", textEncoding: " + textEncoding); 1823 1824 GpsNiNotification notification = new GpsNiNotification(); 1825 1826 notification.notificationId = notificationId; 1827 notification.niType = niType; 1828 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0; 1829 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0; 1830 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0; 1831 notification.timeout = timeout; 1832 notification.defaultResponse = defaultResponse; 1833 notification.requestorId = requestorId; 1834 notification.text = text; 1835 notification.requestorIdEncoding = requestorIdEncoding; 1836 notification.textEncoding = textEncoding; 1837 1838 // Process extras, assuming the format is 1839 // one of more lines of "key = value" 1840 Bundle bundle = new Bundle(); 1841 1842 if (extras == null) extras = ""; 1843 Properties extraProp = new Properties(); 1844 1845 try { 1846 extraProp.load(new StringReader(extras)); 1847 } 1848 catch (IOException e) 1849 { 1850 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras); 1851 } 1852 1853 for (Entry<Object, Object> ent : extraProp.entrySet()) 1854 { 1855 bundle.putString((String) ent.getKey(), (String) ent.getValue()); 1856 } 1857 1858 notification.extras = bundle; 1859 1860 mNIHandler.handleNiNotification(notification); 1861 } 1862 1863 /** 1864 * Called from native code to request set id info. 1865 * We should be careful about receiving null string from the TelephonyManager, 1866 * because sending null String to JNI function would cause a crash. 1867 */ 1868 1869 private void requestSetID(int flags) { 1870 TelephonyManager phone = (TelephonyManager) 1871 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1872 int type = AGPS_SETID_TYPE_NONE; 1873 String data = ""; 1874 1875 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) { 1876 String data_temp = phone.getSubscriberId(); 1877 if (data_temp == null) { 1878 // This means the framework does not have the SIM card ready. 1879 } else { 1880 // This means the framework has the SIM card. 1881 data = data_temp; 1882 type = AGPS_SETID_TYPE_IMSI; 1883 } 1884 } 1885 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) { 1886 String data_temp = phone.getLine1Number(); 1887 if (data_temp == null) { 1888 // This means the framework does not have the SIM card ready. 1889 } else { 1890 // This means the framework has the SIM card. 1891 data = data_temp; 1892 type = AGPS_SETID_TYPE_MSISDN; 1893 } 1894 } 1895 native_agps_set_id(type, data); 1896 } 1897 1898 /** 1899 * Called from native code to request utc time info 1900 */ 1901 1902 private void requestUtcTime() { 1903 sendMessage(INJECT_NTP_TIME, 0, null); 1904 } 1905 1906 /** 1907 * Called from native code to request reference location info 1908 */ 1909 1910 private void requestRefLocation(int flags) { 1911 TelephonyManager phone = (TelephonyManager) 1912 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1913 final int phoneType = phone.getPhoneType(); 1914 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) { 1915 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation(); 1916 if ((gsm_cell != null) && (phone.getNetworkOperator() != null) 1917 && (phone.getNetworkOperator().length() > 3)) { 1918 int type; 1919 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3)); 1920 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3)); 1921 int networkType = phone.getNetworkType(); 1922 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS 1923 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA 1924 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA 1925 || networkType == TelephonyManager.NETWORK_TYPE_HSPA 1926 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) { 1927 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID; 1928 } else { 1929 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID; 1930 } 1931 native_agps_set_ref_location_cellid(type, mcc, mnc, 1932 gsm_cell.getLac(), gsm_cell.getCid()); 1933 } else { 1934 Log.e(TAG,"Error getting cell location info."); 1935 } 1936 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { 1937 Log.e(TAG, "CDMA not supported."); 1938 } 1939 } 1940 1941 private void sendMessage(int message, int arg, Object obj) { 1942 // hold a wake lock until this message is delivered 1943 // note that this assumes the message will not be removed from the queue before 1944 // it is handled (otherwise the wake lock would be leaked). 1945 mWakeLock.acquire(); 1946 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget(); 1947 } 1948 1949 private final class ProviderHandler extends Handler { 1950 public ProviderHandler(Looper looper) { 1951 super(looper, null, true /*async*/); 1952 } 1953 1954 @Override 1955 public void handleMessage(Message msg) { 1956 int message = msg.what; 1957 switch (message) { 1958 case ENABLE: 1959 if (msg.arg1 == 1) { 1960 handleEnable(); 1961 } else { 1962 handleDisable(); 1963 } 1964 break; 1965 case SET_REQUEST: 1966 GpsRequest gpsRequest = (GpsRequest) msg.obj; 1967 handleSetRequest(gpsRequest.request, gpsRequest.source); 1968 break; 1969 case UPDATE_NETWORK_STATE: 1970 handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj); 1971 break; 1972 case INJECT_NTP_TIME: 1973 handleInjectNtpTime(); 1974 break; 1975 case DOWNLOAD_XTRA_DATA: 1976 if (mSupportsXtra) { 1977 handleDownloadXtraData(); 1978 } 1979 break; 1980 case INJECT_NTP_TIME_FINISHED: 1981 mInjectNtpTimePending = STATE_IDLE; 1982 break; 1983 case DOWNLOAD_XTRA_DATA_FINISHED: 1984 mDownloadXtraDataPending = STATE_IDLE; 1985 break; 1986 case UPDATE_LOCATION: 1987 handleUpdateLocation((Location)msg.obj); 1988 break; 1989 case SUBSCRIPTION_OR_SIM_CHANGED: 1990 subscriptionOrSimChanged(mContext); 1991 break; 1992 case INITIALIZE_HANDLER: 1993 initialize(); 1994 break; 1995 } 1996 if (msg.arg2 == 1) { 1997 // wakelock was taken for this message, release it 1998 mWakeLock.release(); 1999 } 2000 } 2001 2002 /** 2003 * This method is bound to {@link #GpsLocationProvider(Context, ILocationManager, Looper)}. 2004 * It is in charge of loading properties and registering for events that will be posted to 2005 * this handler. 2006 */ 2007 private void initialize() { 2008 // load default GPS configuration 2009 // (this configuration might change in the future based on SIM changes) 2010 reloadGpsProperties(mContext, mProperties); 2011 2012 // TODO: When this object "finishes" we should unregister by invoking 2013 // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener); 2014 // This is not strictly necessary because it will be unregistered if the 2015 // notification fails but it is good form. 2016 2017 // Register for SubscriptionInfo list changes which is guaranteed 2018 // to invoke onSubscriptionsChanged the first time. 2019 SubscriptionManager.from(mContext) 2020 .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener); 2021 2022 // listen for events 2023 IntentFilter intentFilter; 2024 if (native_is_agps_ril_supported()) { 2025 intentFilter = new IntentFilter(); 2026 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION); 2027 intentFilter.addDataScheme("sms"); 2028 intentFilter.addDataAuthority("localhost", "7275"); 2029 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); 2030 2031 intentFilter = new IntentFilter(); 2032 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION); 2033 try { 2034 intentFilter.addDataType("application/vnd.omaloc-supl-init"); 2035 } catch (IntentFilter.MalformedMimeTypeException e) { 2036 Log.w(TAG, "Malformed SUPL init mime type"); 2037 } 2038 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); 2039 } else if (DEBUG) { 2040 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS" 2041 + " HAL is not supported"); 2042 } 2043 2044 intentFilter = new IntentFilter(); 2045 intentFilter.addAction(ALARM_WAKEUP); 2046 intentFilter.addAction(ALARM_TIMEOUT); 2047 intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 2048 intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); 2049 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); 2050 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 2051 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 2052 intentFilter.addAction(SIM_STATE_CHANGED); 2053 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); 2054 2055 // listen for PASSIVE_PROVIDER updates 2056 LocationManager locManager = 2057 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 2058 long minTime = 0; 2059 float minDistance = 0; 2060 boolean oneShot = false; 2061 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 2062 LocationManager.PASSIVE_PROVIDER, 2063 minTime, 2064 minDistance, 2065 oneShot); 2066 // Don't keep track of this request since it's done on behalf of other clients 2067 // (which are kept track of separately). 2068 request.setHideFromAppOps(true); 2069 locManager.requestLocationUpdates( 2070 request, 2071 new NetworkLocationListener(), 2072 getLooper()); 2073 } 2074 } 2075 2076 private final class NetworkLocationListener implements LocationListener { 2077 @Override 2078 public void onLocationChanged(Location location) { 2079 // this callback happens on mHandler looper 2080 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { 2081 handleUpdateLocation(location); 2082 } 2083 } 2084 @Override 2085 public void onStatusChanged(String provider, int status, Bundle extras) { } 2086 @Override 2087 public void onProviderEnabled(String provider) { } 2088 @Override 2089 public void onProviderDisabled(String provider) { } 2090 } 2091 2092 private String getSelectedApn() { 2093 Uri uri = Uri.parse("content://telephony/carriers/preferapn"); 2094 Cursor cursor = null; 2095 try { 2096 cursor = mContext.getContentResolver().query( 2097 uri, 2098 new String[] { "apn" }, 2099 null /* selection */, 2100 null /* selectionArgs */, 2101 Carriers.DEFAULT_SORT_ORDER); 2102 if (cursor != null && cursor.moveToFirst()) { 2103 return cursor.getString(0); 2104 } else { 2105 Log.e(TAG, "No APN found to select."); 2106 } 2107 } catch (Exception e) { 2108 Log.e(TAG, "Error encountered on selecting the APN.", e); 2109 } finally { 2110 if (cursor != null) { 2111 cursor.close(); 2112 } 2113 } 2114 2115 return null; 2116 } 2117 2118 private int getApnIpType(String apn) { 2119 if (apn == null) { 2120 return APN_INVALID; 2121 } 2122 2123 // look for cached data to use 2124 if (apn.equals(mAGpsApn) && mApnIpType != APN_INVALID) { 2125 return mApnIpType; 2126 } 2127 2128 String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn); 2129 Cursor cursor = null; 2130 try { 2131 cursor = mContext.getContentResolver().query( 2132 Carriers.CONTENT_URI, 2133 new String[] { Carriers.PROTOCOL }, 2134 selection, 2135 null, 2136 Carriers.DEFAULT_SORT_ORDER); 2137 2138 if (null != cursor && cursor.moveToFirst()) { 2139 return translateToApnIpType(cursor.getString(0), apn); 2140 } else { 2141 Log.e(TAG, "No entry found in query for APN: " + apn); 2142 } 2143 } catch (Exception e) { 2144 Log.e(TAG, "Error encountered on APN query for: " + apn, e); 2145 } finally { 2146 if (cursor != null) { 2147 cursor.close(); 2148 } 2149 } 2150 2151 return APN_INVALID; 2152 } 2153 2154 private int translateToApnIpType(String ipProtocol, String apn) { 2155 if ("IP".equals(ipProtocol)) { 2156 return APN_IPV4; 2157 } 2158 if ("IPV6".equals(ipProtocol)) { 2159 return APN_IPV6; 2160 } 2161 if ("IPV4V6".equals(ipProtocol)) { 2162 return APN_IPV4V6; 2163 } 2164 2165 // we hit the default case so the ipProtocol is not recognized 2166 String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn); 2167 Log.e(TAG, message); 2168 return APN_INVALID; 2169 } 2170 2171 private void setRouting() { 2172 if (mAGpsDataConnectionIpAddr == null) { 2173 return; 2174 } 2175 2176 boolean result = mConnMgr.requestRouteToHostAddress( 2177 ConnectivityManager.TYPE_MOBILE_SUPL, 2178 mAGpsDataConnectionIpAddr); 2179 2180 if (!result) { 2181 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr); 2182 } else if (DEBUG) { 2183 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr); 2184 } 2185 } 2186 2187 @Override 2188 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2189 StringBuilder s = new StringBuilder(); 2190 s.append(" mFixInterval=").append(mFixInterval).append("\n"); 2191 s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append("\n"); 2192 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" ("); 2193 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED "); 2194 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB "); 2195 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA "); 2196 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT "); 2197 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME "); 2198 s.append(")\n"); 2199 2200 s.append(native_get_internal_state()); 2201 pw.append(s); 2202 } 2203 2204 /** 2205 * A simple implementation of exponential backoff. 2206 */ 2207 private static final class BackOff { 2208 private static final int MULTIPLIER = 2; 2209 private final long mInitIntervalMillis; 2210 private final long mMaxIntervalMillis; 2211 private long mCurrentIntervalMillis; 2212 2213 public BackOff(long initIntervalMillis, long maxIntervalMillis) { 2214 mInitIntervalMillis = initIntervalMillis; 2215 mMaxIntervalMillis = maxIntervalMillis; 2216 2217 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER; 2218 } 2219 2220 public long nextBackoffMillis() { 2221 if (mCurrentIntervalMillis > mMaxIntervalMillis) { 2222 return mMaxIntervalMillis; 2223 } 2224 2225 mCurrentIntervalMillis *= MULTIPLIER; 2226 return mCurrentIntervalMillis; 2227 } 2228 2229 public void reset() { 2230 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER; 2231 } 2232 } 2233 2234 // for GPS SV statistics 2235 private static final int MAX_SVS = 32; 2236 private static final int EPHEMERIS_MASK = 0; 2237 private static final int ALMANAC_MASK = 1; 2238 private static final int USED_FOR_FIX_MASK = 2; 2239 2240 // preallocated arrays, to avoid memory allocation in reportStatus() 2241 private int mSvs[] = new int[MAX_SVS]; 2242 private float mSnrs[] = new float[MAX_SVS]; 2243 private float mSvElevations[] = new float[MAX_SVS]; 2244 private float mSvAzimuths[] = new float[MAX_SVS]; 2245 private int mSvMasks[] = new int[3]; 2246 private int mSvCount; 2247 // preallocated to avoid memory allocation in reportNmea() 2248 private byte[] mNmeaBuffer = new byte[120]; 2249 2250 static { class_init_native(); } 2251 private static native void class_init_native(); 2252 private static native boolean native_is_supported(); 2253 private static native boolean native_is_agps_ril_supported(); 2254 private static native boolean native_is_gnss_configuration_supported(); 2255 2256 private native boolean native_init(); 2257 private native void native_cleanup(); 2258 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval, 2259 int preferred_accuracy, int preferred_time); 2260 private native boolean native_start(); 2261 private native boolean native_stop(); 2262 private native void native_delete_aiding_data(int flags); 2263 // returns number of SVs 2264 // mask[0] is ephemeris mask and mask[1] is almanac mask 2265 private native int native_read_sv_status(int[] svs, float[] snrs, 2266 float[] elevations, float[] azimuths, int[] masks); 2267 private native int native_read_nmea(byte[] buffer, int bufferSize); 2268 private native void native_inject_location(double latitude, double longitude, float accuracy); 2269 2270 // XTRA Support 2271 private native void native_inject_time(long time, long timeReference, int uncertainty); 2272 private native boolean native_supports_xtra(); 2273 private native void native_inject_xtra_data(byte[] data, int length); 2274 2275 // DEBUG Support 2276 private native String native_get_internal_state(); 2277 2278 // AGPS Support 2279 private native void native_agps_data_conn_open(String apn, int apnIpType); 2280 private native void native_agps_data_conn_closed(); 2281 private native void native_agps_data_conn_failed(); 2282 private native void native_agps_ni_message(byte [] msg, int length); 2283 private native void native_set_agps_server(int type, String hostname, int port); 2284 2285 // Network-initiated (NI) Support 2286 private native void native_send_ni_response(int notificationId, int userResponse); 2287 2288 // AGPS ril suport 2289 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, 2290 int lac, int cid); 2291 private native void native_agps_set_id(int type, String setid); 2292 2293 private native void native_update_network_state(boolean connected, int type, 2294 boolean roaming, boolean available, String extraInfo, String defaultAPN); 2295 2296 // Hardware Geofence support. 2297 private static native boolean native_is_geofence_supported(); 2298 private static native boolean native_add_geofence(int geofenceId, double latitude, 2299 double longitude, double radius, int lastTransition,int monitorTransitions, 2300 int notificationResponsivenes, int unknownTimer); 2301 private static native boolean native_remove_geofence(int geofenceId); 2302 private static native boolean native_resume_geofence(int geofenceId, int transitions); 2303 private static native boolean native_pause_geofence(int geofenceId); 2304 2305 // Gps Hal measurements support. 2306 private static native boolean native_is_measurement_supported(); 2307 private native boolean native_start_measurement_collection(); 2308 private native boolean native_stop_measurement_collection(); 2309 2310 // Gps Navigation message support. 2311 private static native boolean native_is_navigation_message_supported(); 2312 private native boolean native_start_navigation_message_collection(); 2313 private native boolean native_stop_navigation_message_collection(); 2314 2315 // GNSS Configuration 2316 private static native void native_configuration_update(String configData); 2317 } 2318 2319