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