GpsLocationProvider.java revision 931a37f992c738ebc5d3c82e424d94591798a4d7
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 Log.v(TAG, "Received SUPL IP addr[]: " + ipaddr); 1376 // Set mAGpsDataConnectionState before calling startUsingNetworkFeature 1377 // to avoid a race condition with handleUpdateNetworkState() 1378 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; 1379 int result = mConnMgr.startUsingNetworkFeature( 1380 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); 1381 if (ipaddr != null) { 1382 try { 1383 mAGpsDataConnectionIpAddr = InetAddress.getByAddress(ipaddr); 1384 Log.v(TAG, "IP address converted to: " + mAGpsDataConnectionIpAddr); 1385 } catch (UnknownHostException e) { 1386 Log.e(TAG, "Bad IP Address: " + ipaddr, e); 1387 mAGpsDataConnectionIpAddr = null; 1388 } 1389 } 1390 1391 if (result == PhoneConstants.APN_ALREADY_ACTIVE) { 1392 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE"); 1393 if (mAGpsApn != null) { 1394 setRouting(); 1395 native_agps_data_conn_open(mAGpsApn, mApnIpType); 1396 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 1397 } else { 1398 Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE"); 1399 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1400 native_agps_data_conn_failed(); 1401 } 1402 } else if (result == PhoneConstants.APN_REQUEST_STARTED) { 1403 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_REQUEST_STARTED"); 1404 // Nothing to do here 1405 } else { 1406 if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed, value is " + 1407 result); 1408 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1409 native_agps_data_conn_failed(); 1410 } 1411 break; 1412 case GPS_RELEASE_AGPS_DATA_CONN: 1413 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN"); 1414 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) { 1415 mConnMgr.stopUsingNetworkFeature( 1416 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); 1417 native_agps_data_conn_closed(); 1418 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1419 mAGpsDataConnectionIpAddr = null; 1420 } 1421 break; 1422 case GPS_AGPS_DATA_CONNECTED: 1423 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED"); 1424 break; 1425 case GPS_AGPS_DATA_CONN_DONE: 1426 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE"); 1427 break; 1428 case GPS_AGPS_DATA_CONN_FAILED: 1429 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED"); 1430 break; 1431 default: 1432 Log.d(TAG, "Received Unknown AGPS status: " + status); 1433 } 1434 } 1435 1436 /** 1437 * called from native code to report NMEA data received 1438 */ 1439 private void reportNmea(long timestamp) { 1440 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length); 1441 String nmea = new String(mNmeaBuffer, 0 /* offset */, length); 1442 mListenerHelper.onNmeaReceived(timestamp, nmea); 1443 } 1444 1445 /** 1446 * called from native code - Gps measurements callback 1447 */ 1448 private void reportMeasurementData(GpsMeasurementsEvent event) { 1449 mGpsMeasurementsProvider.onMeasurementsAvailable(event); 1450 } 1451 1452 /** 1453 * called from native code - GPS navigation message callback 1454 */ 1455 private void reportNavigationMessage(GpsNavigationMessageEvent event) { 1456 mGpsNavigationMessageProvider.onNavigationMessageAvailable(event); 1457 } 1458 1459 /** 1460 * called from native code to inform us what the GPS engine capabilities are 1461 */ 1462 private void setEngineCapabilities(int capabilities) { 1463 mEngineCapabilities = capabilities; 1464 1465 if (!hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME) && !mPeriodicTimeInjection) { 1466 mPeriodicTimeInjection = true; 1467 requestUtcTime(); 1468 } 1469 } 1470 1471 /** 1472 * called from native code to request XTRA data 1473 */ 1474 private void xtraDownloadRequest() { 1475 if (DEBUG) Log.d(TAG, "xtraDownloadRequest"); 1476 sendMessage(DOWNLOAD_XTRA_DATA, 0, null); 1477 } 1478 1479 /** 1480 * Helper method to construct a location object. 1481 */ 1482 private Location buildLocation( 1483 int flags, 1484 double latitude, 1485 double longitude, 1486 double altitude, 1487 float speed, 1488 float bearing, 1489 float accuracy, 1490 long timestamp) { 1491 Location location = new Location(LocationManager.GPS_PROVIDER); 1492 if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1493 location.setLatitude(latitude); 1494 location.setLongitude(longitude); 1495 location.setTime(timestamp); 1496 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 1497 } 1498 if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { 1499 location.setAltitude(altitude); 1500 } 1501 if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { 1502 location.setSpeed(speed); 1503 } 1504 if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { 1505 location.setBearing(bearing); 1506 } 1507 if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { 1508 location.setAccuracy(accuracy); 1509 } 1510 return location; 1511 } 1512 1513 /** 1514 * Converts the GPS HAL status to the internal Geofence Hardware status. 1515 */ 1516 private int getGeofenceStatus(int status) { 1517 switch(status) { 1518 case GPS_GEOFENCE_OPERATION_SUCCESS: 1519 return GeofenceHardware.GEOFENCE_SUCCESS; 1520 case GPS_GEOFENCE_ERROR_GENERIC: 1521 return GeofenceHardware.GEOFENCE_FAILURE; 1522 case GPS_GEOFENCE_ERROR_ID_EXISTS: 1523 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; 1524 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION: 1525 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; 1526 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES: 1527 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; 1528 case GPS_GEOFENCE_ERROR_ID_UNKNOWN: 1529 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; 1530 default: 1531 return -1; 1532 } 1533 } 1534 1535 /** 1536 * Called from native to report GPS Geofence transition 1537 * All geofence callbacks are called on the same thread 1538 */ 1539 private void reportGeofenceTransition(int geofenceId, int flags, double latitude, 1540 double longitude, double altitude, float speed, float bearing, float accuracy, 1541 long timestamp, int transition, long transitionTimestamp) { 1542 if (mGeofenceHardwareImpl == null) { 1543 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1544 } 1545 Location location = buildLocation( 1546 flags, 1547 latitude, 1548 longitude, 1549 altitude, 1550 speed, 1551 bearing, 1552 accuracy, 1553 timestamp); 1554 mGeofenceHardwareImpl.reportGeofenceTransition( 1555 geofenceId, 1556 location, 1557 transition, 1558 transitionTimestamp, 1559 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 1560 FusedBatchOptions.SourceTechnologies.GNSS); 1561 } 1562 1563 /** 1564 * called from native code to report GPS status change. 1565 */ 1566 private void reportGeofenceStatus(int status, int flags, double latitude, 1567 double longitude, double altitude, float speed, float bearing, float accuracy, 1568 long timestamp) { 1569 if (mGeofenceHardwareImpl == null) { 1570 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1571 } 1572 Location location = buildLocation( 1573 flags, 1574 latitude, 1575 longitude, 1576 altitude, 1577 speed, 1578 bearing, 1579 accuracy, 1580 timestamp); 1581 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; 1582 if(status == GPS_GEOFENCE_AVAILABLE) { 1583 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; 1584 } 1585 mGeofenceHardwareImpl.reportGeofenceMonitorStatus( 1586 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 1587 monitorStatus, 1588 location, 1589 FusedBatchOptions.SourceTechnologies.GNSS); 1590 } 1591 1592 /** 1593 * called from native code - Geofence Add callback 1594 */ 1595 private void reportGeofenceAddStatus(int geofenceId, int status) { 1596 if (mGeofenceHardwareImpl == null) { 1597 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1598 } 1599 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status)); 1600 } 1601 1602 /** 1603 * called from native code - Geofence Remove callback 1604 */ 1605 private void reportGeofenceRemoveStatus(int geofenceId, int status) { 1606 if (mGeofenceHardwareImpl == null) { 1607 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1608 } 1609 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status)); 1610 } 1611 1612 /** 1613 * called from native code - Geofence Pause callback 1614 */ 1615 private void reportGeofencePauseStatus(int geofenceId, int status) { 1616 if (mGeofenceHardwareImpl == null) { 1617 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1618 } 1619 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status)); 1620 } 1621 1622 /** 1623 * called from native code - Geofence Resume callback 1624 */ 1625 private void reportGeofenceResumeStatus(int geofenceId, int status) { 1626 if (mGeofenceHardwareImpl == null) { 1627 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1628 } 1629 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status)); 1630 } 1631 1632 //============================================================= 1633 // NI Client support 1634 //============================================================= 1635 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() { 1636 // Sends a response for an NI reqeust to HAL. 1637 @Override 1638 public boolean sendNiResponse(int notificationId, int userResponse) 1639 { 1640 // TODO Add Permission check 1641 1642 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId + 1643 ", response: " + userResponse); 1644 native_send_ni_response(notificationId, userResponse); 1645 return true; 1646 } 1647 }; 1648 1649 public INetInitiatedListener getNetInitiatedListener() { 1650 return mNetInitiatedListener; 1651 } 1652 1653 // Called by JNI function to report an NI request. 1654 public void reportNiNotification( 1655 int notificationId, 1656 int niType, 1657 int notifyFlags, 1658 int timeout, 1659 int defaultResponse, 1660 String requestorId, 1661 String text, 1662 int requestorIdEncoding, 1663 int textEncoding, 1664 String extras // Encoded extra data 1665 ) 1666 { 1667 Log.i(TAG, "reportNiNotification: entered"); 1668 Log.i(TAG, "notificationId: " + notificationId + 1669 ", niType: " + niType + 1670 ", notifyFlags: " + notifyFlags + 1671 ", timeout: " + timeout + 1672 ", defaultResponse: " + defaultResponse); 1673 1674 Log.i(TAG, "requestorId: " + requestorId + 1675 ", text: " + text + 1676 ", requestorIdEncoding: " + requestorIdEncoding + 1677 ", textEncoding: " + textEncoding); 1678 1679 GpsNiNotification notification = new GpsNiNotification(); 1680 1681 notification.notificationId = notificationId; 1682 notification.niType = niType; 1683 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0; 1684 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0; 1685 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0; 1686 notification.timeout = timeout; 1687 notification.defaultResponse = defaultResponse; 1688 notification.requestorId = requestorId; 1689 notification.text = text; 1690 notification.requestorIdEncoding = requestorIdEncoding; 1691 notification.textEncoding = textEncoding; 1692 1693 // Process extras, assuming the format is 1694 // one of more lines of "key = value" 1695 Bundle bundle = new Bundle(); 1696 1697 if (extras == null) extras = ""; 1698 Properties extraProp = new Properties(); 1699 1700 try { 1701 extraProp.load(new StringReader(extras)); 1702 } 1703 catch (IOException e) 1704 { 1705 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras); 1706 } 1707 1708 for (Entry<Object, Object> ent : extraProp.entrySet()) 1709 { 1710 bundle.putString((String) ent.getKey(), (String) ent.getValue()); 1711 } 1712 1713 notification.extras = bundle; 1714 1715 mNIHandler.handleNiNotification(notification); 1716 } 1717 1718 /** 1719 * Called from native code to request set id info. 1720 * We should be careful about receiving null string from the TelephonyManager, 1721 * because sending null String to JNI function would cause a crash. 1722 */ 1723 1724 private void requestSetID(int flags) { 1725 TelephonyManager phone = (TelephonyManager) 1726 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1727 int type = AGPS_SETID_TYPE_NONE; 1728 String data = ""; 1729 1730 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) { 1731 String data_temp = phone.getSubscriberId(); 1732 if (data_temp == null) { 1733 // This means the framework does not have the SIM card ready. 1734 } else { 1735 // This means the framework has the SIM card. 1736 data = data_temp; 1737 type = AGPS_SETID_TYPE_IMSI; 1738 } 1739 } 1740 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) { 1741 String data_temp = phone.getLine1Number(); 1742 if (data_temp == null) { 1743 // This means the framework does not have the SIM card ready. 1744 } else { 1745 // This means the framework has the SIM card. 1746 data = data_temp; 1747 type = AGPS_SETID_TYPE_MSISDN; 1748 } 1749 } 1750 native_agps_set_id(type, data); 1751 } 1752 1753 /** 1754 * Called from native code to request utc time info 1755 */ 1756 1757 private void requestUtcTime() { 1758 sendMessage(INJECT_NTP_TIME, 0, null); 1759 } 1760 1761 /** 1762 * Called from native code to request reference location info 1763 */ 1764 1765 private void requestRefLocation(int flags) { 1766 TelephonyManager phone = (TelephonyManager) 1767 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1768 final int phoneType = phone.getPhoneType(); 1769 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) { 1770 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation(); 1771 if ((gsm_cell != null) && (phone.getNetworkOperator() != null) 1772 && (phone.getNetworkOperator().length() > 3)) { 1773 int type; 1774 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3)); 1775 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3)); 1776 int networkType = phone.getNetworkType(); 1777 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS 1778 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA 1779 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA 1780 || networkType == TelephonyManager.NETWORK_TYPE_HSPA 1781 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) { 1782 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID; 1783 } else { 1784 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID; 1785 } 1786 native_agps_set_ref_location_cellid(type, mcc, mnc, 1787 gsm_cell.getLac(), gsm_cell.getCid()); 1788 } else { 1789 Log.e(TAG,"Error getting cell location info."); 1790 } 1791 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { 1792 Log.e(TAG, "CDMA not supported."); 1793 } 1794 } 1795 1796 private void sendMessage(int message, int arg, Object obj) { 1797 // hold a wake lock until this message is delivered 1798 // note that this assumes the message will not be removed from the queue before 1799 // it is handled (otherwise the wake lock would be leaked). 1800 mWakeLock.acquire(); 1801 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget(); 1802 } 1803 1804 private final class ProviderHandler extends Handler { 1805 public ProviderHandler(Looper looper) { 1806 super(looper, null, true /*async*/); 1807 } 1808 1809 @Override 1810 public void handleMessage(Message msg) { 1811 int message = msg.what; 1812 switch (message) { 1813 case ENABLE: 1814 if (msg.arg1 == 1) { 1815 handleEnable(); 1816 } else { 1817 handleDisable(); 1818 } 1819 break; 1820 case SET_REQUEST: 1821 GpsRequest gpsRequest = (GpsRequest) msg.obj; 1822 handleSetRequest(gpsRequest.request, gpsRequest.source); 1823 break; 1824 case UPDATE_NETWORK_STATE: 1825 handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj); 1826 break; 1827 case INJECT_NTP_TIME: 1828 handleInjectNtpTime(); 1829 break; 1830 case DOWNLOAD_XTRA_DATA: 1831 if (mSupportsXtra) { 1832 handleDownloadXtraData(); 1833 } 1834 break; 1835 case INJECT_NTP_TIME_FINISHED: 1836 mInjectNtpTimePending = STATE_IDLE; 1837 break; 1838 case DOWNLOAD_XTRA_DATA_FINISHED: 1839 mDownloadXtraDataPending = STATE_IDLE; 1840 break; 1841 case UPDATE_LOCATION: 1842 handleUpdateLocation((Location)msg.obj); 1843 break; 1844 } 1845 if (msg.arg2 == 1) { 1846 // wakelock was taken for this message, release it 1847 mWakeLock.release(); 1848 } 1849 } 1850 }; 1851 1852 private final class NetworkLocationListener implements LocationListener { 1853 @Override 1854 public void onLocationChanged(Location location) { 1855 // this callback happens on mHandler looper 1856 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { 1857 handleUpdateLocation(location); 1858 } 1859 } 1860 @Override 1861 public void onStatusChanged(String provider, int status, Bundle extras) { } 1862 @Override 1863 public void onProviderEnabled(String provider) { } 1864 @Override 1865 public void onProviderDisabled(String provider) { } 1866 } 1867 1868 private String getSelectedApn() { 1869 Uri uri = Uri.parse("content://telephony/carriers/preferapn"); 1870 Cursor cursor = null; 1871 try { 1872 cursor = mContext.getContentResolver().query( 1873 uri, 1874 new String[] { "apn" }, 1875 null /* selection */, 1876 null /* selectionArgs */, 1877 Carriers.DEFAULT_SORT_ORDER); 1878 if (cursor != null && cursor.moveToFirst()) { 1879 return cursor.getString(0); 1880 } else { 1881 Log.e(TAG, "No APN found to select."); 1882 } 1883 } catch (Exception e) { 1884 Log.e(TAG, "Error encountered on selecting the APN.", e); 1885 } finally { 1886 if (cursor != null) { 1887 cursor.close(); 1888 } 1889 } 1890 1891 return null; 1892 } 1893 1894 private int getApnIpType(String apn) { 1895 if (apn == null) { 1896 return APN_INVALID; 1897 } 1898 1899 // look for cached data to use 1900 if (apn.equals(mAGpsApn) && mApnIpType != APN_INVALID) { 1901 return mApnIpType; 1902 } 1903 1904 String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn); 1905 Cursor cursor = null; 1906 try { 1907 cursor = mContext.getContentResolver().query( 1908 Carriers.CONTENT_URI, 1909 new String[] { Carriers.PROTOCOL }, 1910 selection, 1911 null, 1912 Carriers.DEFAULT_SORT_ORDER); 1913 1914 if (null != cursor && cursor.moveToFirst()) { 1915 return translateToApnIpType(cursor.getString(0), apn); 1916 } else { 1917 Log.e(TAG, "No entry found in query for APN: " + apn); 1918 } 1919 } catch (Exception e) { 1920 Log.e(TAG, "Error encountered on APN query for: " + apn, e); 1921 } finally { 1922 if (cursor != null) { 1923 cursor.close(); 1924 } 1925 } 1926 1927 return APN_INVALID; 1928 } 1929 1930 private int translateToApnIpType(String ipProtocol, String apn) { 1931 if ("IP".equals(ipProtocol)) { 1932 return APN_IPV4; 1933 } 1934 if ("IPV6".equals(ipProtocol)) { 1935 return APN_IPV6; 1936 } 1937 if ("IPV4V6".equals(ipProtocol)) { 1938 return APN_IPV4V6; 1939 } 1940 1941 // we hit the default case so the ipProtocol is not recognized 1942 String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn); 1943 Log.e(TAG, message); 1944 return APN_INVALID; 1945 } 1946 1947 private void setRouting() { 1948 if (mAGpsDataConnectionIpAddr == null) { 1949 return; 1950 } 1951 1952 boolean result = mConnMgr.requestRouteToHostAddress( 1953 ConnectivityManager.TYPE_MOBILE_SUPL, 1954 mAGpsDataConnectionIpAddr); 1955 1956 if (!result) { 1957 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr); 1958 } else if (DEBUG) { 1959 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr); 1960 } 1961 } 1962 1963 @Override 1964 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1965 StringBuilder s = new StringBuilder(); 1966 s.append(" mFixInterval=").append(mFixInterval).append("\n"); 1967 s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append("\n"); 1968 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" ("); 1969 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED "); 1970 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB "); 1971 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA "); 1972 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT "); 1973 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME "); 1974 s.append(")\n"); 1975 1976 s.append(native_get_internal_state()); 1977 pw.append(s); 1978 } 1979 1980 // for GPS SV statistics 1981 private static final int MAX_SVS = 32; 1982 private static final int EPHEMERIS_MASK = 0; 1983 private static final int ALMANAC_MASK = 1; 1984 private static final int USED_FOR_FIX_MASK = 2; 1985 1986 // preallocated arrays, to avoid memory allocation in reportStatus() 1987 private int mSvs[] = new int[MAX_SVS]; 1988 private float mSnrs[] = new float[MAX_SVS]; 1989 private float mSvElevations[] = new float[MAX_SVS]; 1990 private float mSvAzimuths[] = new float[MAX_SVS]; 1991 private int mSvMasks[] = new int[3]; 1992 private int mSvCount; 1993 // preallocated to avoid memory allocation in reportNmea() 1994 private byte[] mNmeaBuffer = new byte[120]; 1995 1996 static { class_init_native(); } 1997 private static native void class_init_native(); 1998 private static native boolean native_is_supported(); 1999 2000 private native boolean native_init(); 2001 private native void native_cleanup(); 2002 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval, 2003 int preferred_accuracy, int preferred_time); 2004 private native boolean native_start(); 2005 private native boolean native_stop(); 2006 private native void native_delete_aiding_data(int flags); 2007 // returns number of SVs 2008 // mask[0] is ephemeris mask and mask[1] is almanac mask 2009 private native int native_read_sv_status(int[] svs, float[] snrs, 2010 float[] elevations, float[] azimuths, int[] masks); 2011 private native int native_read_nmea(byte[] buffer, int bufferSize); 2012 private native void native_inject_location(double latitude, double longitude, float accuracy); 2013 2014 // XTRA Support 2015 private native void native_inject_time(long time, long timeReference, int uncertainty); 2016 private native boolean native_supports_xtra(); 2017 private native void native_inject_xtra_data(byte[] data, int length); 2018 2019 // DEBUG Support 2020 private native String native_get_internal_state(); 2021 2022 // AGPS Support 2023 private native void native_agps_data_conn_open(String apn, int apnIpType); 2024 private native void native_agps_data_conn_closed(); 2025 private native void native_agps_data_conn_failed(); 2026 private native void native_agps_ni_message(byte [] msg, int length); 2027 private native void native_set_agps_server(int type, String hostname, int port); 2028 2029 // Network-initiated (NI) Support 2030 private native void native_send_ni_response(int notificationId, int userResponse); 2031 2032 // AGPS ril suport 2033 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, 2034 int lac, int cid); 2035 private native void native_agps_set_id(int type, String setid); 2036 2037 private native void native_update_network_state(boolean connected, int type, 2038 boolean roaming, boolean available, String extraInfo, String defaultAPN); 2039 2040 // Hardware Geofence support. 2041 private static native boolean native_is_geofence_supported(); 2042 private static native boolean native_add_geofence(int geofenceId, double latitude, 2043 double longitude, double radius, int lastTransition,int monitorTransitions, 2044 int notificationResponsivenes, int unknownTimer); 2045 private static native boolean native_remove_geofence(int geofenceId); 2046 private static native boolean native_resume_geofence(int geofenceId, int transitions); 2047 private static native boolean native_pause_geofence(int geofenceId); 2048 2049 // Gps Hal measurements support. 2050 private static native boolean native_is_measurement_supported(); 2051 private native boolean native_start_measurement_collection(); 2052 private native boolean native_stop_measurement_collection(); 2053 2054 // Gps Navigation message support. 2055 private static native boolean native_is_navigation_message_supported(); 2056 private native boolean native_start_navigation_message_collection(); 2057 private native boolean native_stop_navigation_message_collection(); 2058} 2059 2060