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