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