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