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