GpsLocationProvider.java revision 3bc26143dc81267beba26e50965b4835cf73fdf8
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; 86 87/** 88 * A GPS implementation of LocationProvider used by LocationManager. 89 * 90 * {@hide} 91 */ 92public 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 updateClientUids(new WorkSource()); 795 stopNavigating(); 796 mAlarmManager.cancel(mWakeupIntent); 797 mAlarmManager.cancel(mTimeoutIntent); 798 799 // do this before releasing wakelock 800 native_cleanup(); 801 } 802 803 @Override 804 public boolean isEnabled() { 805 synchronized (mLock) { 806 return mEnabled; 807 } 808 } 809 810 @Override 811 public int getStatus(Bundle extras) { 812 if (extras != null) { 813 extras.putInt("satellites", mSvCount); 814 } 815 return mStatus; 816 } 817 818 private void updateStatus(int status, int svCount) { 819 if (status != mStatus || svCount != mSvCount) { 820 mStatus = status; 821 mSvCount = svCount; 822 mLocationExtras.putInt("satellites", svCount); 823 mStatusUpdateTime = SystemClock.elapsedRealtime(); 824 } 825 } 826 827 @Override 828 public long getStatusUpdateTime() { 829 return mStatusUpdateTime; 830 } 831 832 @Override 833 public void setRequest(ProviderRequest request, WorkSource source) { 834 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source)); 835 } 836 837 private void handleSetRequest(ProviderRequest request, WorkSource source) { 838 boolean singleShot = false; 839 840 // see if the request is for a single update 841 if (request.locationRequests != null && request.locationRequests.size() > 0) { 842 // if any request has zero or more than one updates 843 // requested, then this is not single-shot mode 844 singleShot = true; 845 846 for (LocationRequest lr : request.locationRequests) { 847 if (lr.getNumUpdates() != 1) { 848 singleShot = false; 849 } 850 } 851 } 852 853 if (DEBUG) Log.d(TAG, "setRequest " + request); 854 if (request.reportLocation) { 855 // update client uids 856 updateClientUids(source); 857 858 mFixInterval = (int) request.interval; 859 860 // check for overflow 861 if (mFixInterval != request.interval) { 862 Log.w(TAG, "interval overflow: " + request.interval); 863 mFixInterval = Integer.MAX_VALUE; 864 } 865 866 // apply request to GPS engine 867 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) { 868 // change period 869 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 870 mFixInterval, 0, 0)) { 871 Log.e(TAG, "set_position_mode failed in setMinTime()"); 872 } 873 } else if (!mStarted) { 874 // start GPS 875 startNavigating(singleShot); 876 } 877 } else { 878 updateClientUids(new WorkSource()); 879 880 stopNavigating(); 881 mAlarmManager.cancel(mWakeupIntent); 882 mAlarmManager.cancel(mTimeoutIntent); 883 } 884 } 885 886 private final class Listener implements IBinder.DeathRecipient { 887 final IGpsStatusListener mListener; 888 889 Listener(IGpsStatusListener listener) { 890 mListener = listener; 891 } 892 893 @Override 894 public void binderDied() { 895 if (DEBUG) Log.d(TAG, "GPS status listener died"); 896 897 synchronized (mListeners) { 898 mListeners.remove(this); 899 } 900 if (mListener != null) { 901 mListener.asBinder().unlinkToDeath(this, 0); 902 } 903 } 904 } 905 906 private void updateClientUids(WorkSource source) { 907 // Update work source. 908 WorkSource[] changes = mClientSource.setReturningDiffs(source); 909 if (changes == null) { 910 return; 911 } 912 WorkSource newWork = changes[0]; 913 WorkSource goneWork = changes[1]; 914 915 // Update sources that were not previously tracked. 916 if (newWork != null) { 917 int lastuid = -1; 918 for (int i=0; i<newWork.size(); i++) { 919 try { 920 int uid = newWork.get(i); 921 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), 922 AppOpsManager.OP_GPS, uid, newWork.getName(i)); 923 if (uid != lastuid) { 924 lastuid = uid; 925 mBatteryStats.noteStartGps(uid); 926 } 927 } catch (RemoteException e) { 928 Log.w(TAG, "RemoteException", e); 929 } 930 } 931 } 932 933 // Update sources that are no longer tracked. 934 if (goneWork != null) { 935 int lastuid = -1; 936 for (int i=0; i<goneWork.size(); i++) { 937 try { 938 int uid = goneWork.get(i); 939 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), 940 AppOpsManager.OP_GPS, uid, goneWork.getName(i)); 941 if (uid != lastuid) { 942 lastuid = uid; 943 mBatteryStats.noteStopGps(uid); 944 } 945 } catch (RemoteException e) { 946 Log.w(TAG, "RemoteException", e); 947 } 948 } 949 } 950 } 951 952 @Override 953 public boolean sendExtraCommand(String command, Bundle extras) { 954 955 long identity = Binder.clearCallingIdentity(); 956 boolean result = false; 957 958 if ("delete_aiding_data".equals(command)) { 959 result = deleteAidingData(extras); 960 } else if ("force_time_injection".equals(command)) { 961 sendMessage(INJECT_NTP_TIME, 0, null); 962 result = true; 963 } else if ("force_xtra_injection".equals(command)) { 964 if (mSupportsXtra) { 965 xtraDownloadRequest(); 966 result = true; 967 } 968 } else { 969 Log.w(TAG, "sendExtraCommand: unknown command " + command); 970 } 971 972 Binder.restoreCallingIdentity(identity); 973 return result; 974 } 975 976 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() { 977 public boolean isHardwareGeofenceSupported() { 978 return native_is_geofence_supported(); 979 } 980 981 public boolean addCircularHardwareGeofence(int geofenceId, double latitude, 982 double longitude, double radius, int lastTransition, int monitorTransitions, 983 int notificationResponsiveness, int unknownTimer) { 984 return native_add_geofence(geofenceId, latitude, longitude, radius, 985 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer); 986 } 987 988 public boolean removeHardwareGeofence(int geofenceId) { 989 return native_remove_geofence(geofenceId); 990 } 991 992 public boolean pauseHardwareGeofence(int geofenceId) { 993 return native_pause_geofence(geofenceId); 994 } 995 996 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) { 997 return native_resume_geofence(geofenceId, monitorTransition); 998 } 999 }; 1000 1001 private boolean deleteAidingData(Bundle extras) { 1002 int flags; 1003 1004 if (extras == null) { 1005 flags = GPS_DELETE_ALL; 1006 } else { 1007 flags = 0; 1008 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS; 1009 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC; 1010 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION; 1011 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME; 1012 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO; 1013 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC; 1014 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH; 1015 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR; 1016 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER; 1017 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA; 1018 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI; 1019 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO; 1020 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL; 1021 } 1022 1023 if (flags != 0) { 1024 native_delete_aiding_data(flags); 1025 return true; 1026 } 1027 1028 return false; 1029 } 1030 1031 private void startNavigating(boolean singleShot) { 1032 if (!mStarted) { 1033 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot); 1034 mTimeToFirstFix = 0; 1035 mLastFixTime = 0; 1036 mStarted = true; 1037 mSingleShot = singleShot; 1038 mPositionMode = GPS_POSITION_MODE_STANDALONE; 1039 1040 if (Settings.Global.getInt(mContext.getContentResolver(), 1041 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0) { 1042 if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) { 1043 mPositionMode = GPS_POSITION_MODE_MS_ASSISTED; 1044 } else if (hasCapability(GPS_CAPABILITY_MSB)) { 1045 mPositionMode = GPS_POSITION_MODE_MS_BASED; 1046 } 1047 } 1048 1049 if (DEBUG) { 1050 String mode; 1051 1052 switch(mPositionMode) { 1053 case GPS_POSITION_MODE_STANDALONE: 1054 mode = "standalone"; 1055 break; 1056 case GPS_POSITION_MODE_MS_ASSISTED: 1057 mode = "MS_ASSISTED"; 1058 break; 1059 case GPS_POSITION_MODE_MS_BASED: 1060 mode = "MS_BASED"; 1061 break; 1062 default: 1063 mode = "unknown"; 1064 break; 1065 } 1066 Log.d(TAG, "setting position_mode to " + mode); 1067 } 1068 1069 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000); 1070 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 1071 interval, 0, 0)) { 1072 mStarted = false; 1073 Log.e(TAG, "set_position_mode failed in startNavigating()"); 1074 return; 1075 } 1076 if (!native_start()) { 1077 mStarted = false; 1078 Log.e(TAG, "native_start failed in startNavigating()"); 1079 return; 1080 } 1081 1082 // reset SV count to zero 1083 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); 1084 mFixRequestTime = System.currentTimeMillis(); 1085 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) { 1086 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 1087 // and our fix interval is not short 1088 if (mFixInterval >= NO_FIX_TIMEOUT) { 1089 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1090 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); 1091 } 1092 } 1093 } 1094 } 1095 1096 private void stopNavigating() { 1097 if (DEBUG) Log.d(TAG, "stopNavigating"); 1098 if (mStarted) { 1099 mStarted = false; 1100 mSingleShot = false; 1101 native_stop(); 1102 mTimeToFirstFix = 0; 1103 mLastFixTime = 0; 1104 mLocationFlags = LOCATION_INVALID; 1105 1106 // reset SV count to zero 1107 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); 1108 } 1109 } 1110 1111 private void hibernate() { 1112 // stop GPS until our next fix interval arrives 1113 stopNavigating(); 1114 mAlarmManager.cancel(mTimeoutIntent); 1115 mAlarmManager.cancel(mWakeupIntent); 1116 long now = SystemClock.elapsedRealtime(); 1117 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent); 1118 } 1119 1120 private boolean hasCapability(int capability) { 1121 return ((mEngineCapabilities & capability) != 0); 1122 } 1123 1124 1125 /** 1126 * called from native code to update our position. 1127 */ 1128 private void reportLocation(int flags, double latitude, double longitude, double altitude, 1129 float speed, float bearing, float accuracy, long timestamp) { 1130 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude + 1131 " timestamp: " + timestamp); 1132 1133 synchronized (mLocation) { 1134 mLocationFlags = flags; 1135 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1136 mLocation.setLatitude(latitude); 1137 mLocation.setLongitude(longitude); 1138 mLocation.setTime(timestamp); 1139 // It would be nice to push the elapsed real-time timestamp 1140 // further down the stack, but this is still useful 1141 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 1142 } 1143 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { 1144 mLocation.setAltitude(altitude); 1145 } else { 1146 mLocation.removeAltitude(); 1147 } 1148 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { 1149 mLocation.setSpeed(speed); 1150 } else { 1151 mLocation.removeSpeed(); 1152 } 1153 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { 1154 mLocation.setBearing(bearing); 1155 } else { 1156 mLocation.removeBearing(); 1157 } 1158 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { 1159 mLocation.setAccuracy(accuracy); 1160 } else { 1161 mLocation.removeAccuracy(); 1162 } 1163 mLocation.setExtras(mLocationExtras); 1164 1165 try { 1166 mILocationManager.reportLocation(mLocation, false); 1167 } catch (RemoteException e) { 1168 Log.e(TAG, "RemoteException calling reportLocation"); 1169 } 1170 } 1171 1172 mLastFixTime = System.currentTimeMillis(); 1173 // report time to first fix 1174 if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1175 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime); 1176 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix); 1177 1178 // notify status listeners 1179 synchronized (mListeners) { 1180 int size = mListeners.size(); 1181 for (int i = 0; i < size; i++) { 1182 Listener listener = mListeners.get(i); 1183 try { 1184 listener.mListener.onFirstFix(mTimeToFirstFix); 1185 } catch (RemoteException e) { 1186 Log.w(TAG, "RemoteException in stopNavigating"); 1187 mListeners.remove(listener); 1188 // adjust for size of list changing 1189 size--; 1190 } 1191 } 1192 } 1193 } 1194 1195 if (mSingleShot) { 1196 stopNavigating(); 1197 } 1198 1199 if (mStarted && mStatus != LocationProvider.AVAILABLE) { 1200 // we want to time out if we do not receive a fix 1201 // within the time out and we are requesting infrequent fixes 1202 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) { 1203 mAlarmManager.cancel(mTimeoutIntent); 1204 } 1205 1206 // send an intent to notify that the GPS is receiving fixes. 1207 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1208 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true); 1209 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1210 updateStatus(LocationProvider.AVAILABLE, mSvCount); 1211 } 1212 1213 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted && 1214 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { 1215 if (DEBUG) Log.d(TAG, "got fix, hibernating"); 1216 hibernate(); 1217 } 1218 } 1219 1220 /** 1221 * called from native code to update our status 1222 */ 1223 private void reportStatus(int status) { 1224 if (DEBUG) Log.v(TAG, "reportStatus status: " + status); 1225 1226 synchronized (mListeners) { 1227 boolean wasNavigating = mNavigating; 1228 1229 switch (status) { 1230 case GPS_STATUS_SESSION_BEGIN: 1231 mNavigating = true; 1232 mEngineOn = true; 1233 break; 1234 case GPS_STATUS_SESSION_END: 1235 mNavigating = false; 1236 break; 1237 case GPS_STATUS_ENGINE_ON: 1238 mEngineOn = true; 1239 break; 1240 case GPS_STATUS_ENGINE_OFF: 1241 mEngineOn = false; 1242 mNavigating = false; 1243 break; 1244 } 1245 1246 if (wasNavigating != mNavigating) { 1247 int size = mListeners.size(); 1248 for (int i = 0; i < size; i++) { 1249 Listener listener = mListeners.get(i); 1250 try { 1251 if (mNavigating) { 1252 listener.mListener.onGpsStarted(); 1253 } else { 1254 listener.mListener.onGpsStopped(); 1255 } 1256 } catch (RemoteException e) { 1257 Log.w(TAG, "RemoteException in reportStatus"); 1258 mListeners.remove(listener); 1259 // adjust for size of list changing 1260 size--; 1261 } 1262 } 1263 1264 // send an intent to notify that the GPS has been enabled or disabled. 1265 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION); 1266 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating); 1267 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1268 } 1269 } 1270 } 1271 1272 /** 1273 * called from native code to update SV info 1274 */ 1275 private void reportSvStatus() { 1276 1277 int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks); 1278 1279 synchronized (mListeners) { 1280 int size = mListeners.size(); 1281 for (int i = 0; i < size; i++) { 1282 Listener listener = mListeners.get(i); 1283 try { 1284 listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs, 1285 mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK], 1286 mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]); 1287 } catch (RemoteException e) { 1288 Log.w(TAG, "RemoteException in reportSvInfo"); 1289 mListeners.remove(listener); 1290 // adjust for size of list changing 1291 size--; 1292 } 1293 } 1294 } 1295 1296 if (VERBOSE) { 1297 Log.v(TAG, "SV count: " + svCount + 1298 " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) + 1299 " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK])); 1300 for (int i = 0; i < svCount; i++) { 1301 Log.v(TAG, "sv: " + mSvs[i] + 1302 " snr: " + mSnrs[i]/10 + 1303 " elev: " + mSvElevations[i] + 1304 " azimuth: " + mSvAzimuths[i] + 1305 ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " E") + 1306 ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " A") + 1307 ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U")); 1308 } 1309 } 1310 1311 // return number of sets used in fix instead of total 1312 updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK])); 1313 1314 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 && 1315 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) { 1316 // send an intent to notify that the GPS is no longer receiving fixes. 1317 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1318 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false); 1319 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1320 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount); 1321 } 1322 } 1323 1324 /** 1325 * called from native code to update AGPS status 1326 */ 1327 private void reportAGpsStatus(int type, int status, int ipaddr) { 1328 switch (status) { 1329 case GPS_REQUEST_AGPS_DATA_CONN: 1330 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN"); 1331 // Set mAGpsDataConnectionState before calling startUsingNetworkFeature 1332 // to avoid a race condition with handleUpdateNetworkState() 1333 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; 1334 int result = mConnMgr.startUsingNetworkFeature( 1335 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); 1336 mAGpsDataConnectionIpAddr = ipaddr; 1337 if (result == PhoneConstants.APN_ALREADY_ACTIVE) { 1338 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE"); 1339 if (mAGpsApn != null) { 1340 Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr); 1341 if (mAGpsDataConnectionIpAddr != 0xffffffff) { 1342 boolean route_result; 1343 if (DEBUG) Log.d(TAG, "call requestRouteToHost"); 1344 route_result = mConnMgr.requestRouteToHost( 1345 ConnectivityManager.TYPE_MOBILE_SUPL, 1346 mAGpsDataConnectionIpAddr); 1347 if (route_result == false) Log.d(TAG, "call requestRouteToHost failed"); 1348 } 1349 native_agps_data_conn_open(mAGpsApn); 1350 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 1351 } else { 1352 Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE"); 1353 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1354 native_agps_data_conn_failed(); 1355 } 1356 } else if (result == PhoneConstants.APN_REQUEST_STARTED) { 1357 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_REQUEST_STARTED"); 1358 // Nothing to do here 1359 } else { 1360 if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed, value is " + 1361 result); 1362 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1363 native_agps_data_conn_failed(); 1364 } 1365 break; 1366 case GPS_RELEASE_AGPS_DATA_CONN: 1367 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN"); 1368 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) { 1369 mConnMgr.stopUsingNetworkFeature( 1370 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); 1371 native_agps_data_conn_closed(); 1372 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1373 } 1374 break; 1375 case GPS_AGPS_DATA_CONNECTED: 1376 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED"); 1377 break; 1378 case GPS_AGPS_DATA_CONN_DONE: 1379 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE"); 1380 break; 1381 case GPS_AGPS_DATA_CONN_FAILED: 1382 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED"); 1383 break; 1384 } 1385 } 1386 1387 /** 1388 * called from native code to report NMEA data received 1389 */ 1390 private void reportNmea(long timestamp) { 1391 synchronized (mListeners) { 1392 int size = mListeners.size(); 1393 if (size > 0) { 1394 // don't bother creating the String if we have no listeners 1395 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length); 1396 String nmea = new String(mNmeaBuffer, 0, length); 1397 1398 for (int i = 0; i < size; i++) { 1399 Listener listener = mListeners.get(i); 1400 try { 1401 listener.mListener.onNmeaReceived(timestamp, nmea); 1402 } catch (RemoteException e) { 1403 Log.w(TAG, "RemoteException in reportNmea"); 1404 mListeners.remove(listener); 1405 // adjust for size of list changing 1406 size--; 1407 } 1408 } 1409 } 1410 } 1411 } 1412 1413 /** 1414 * called from native code to inform us what the GPS engine capabilities are 1415 */ 1416 private void setEngineCapabilities(int capabilities) { 1417 mEngineCapabilities = capabilities; 1418 1419 if (!hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME) && !mPeriodicTimeInjection) { 1420 mPeriodicTimeInjection = true; 1421 requestUtcTime(); 1422 } 1423 } 1424 1425 /** 1426 * called from native code to request XTRA data 1427 */ 1428 private void xtraDownloadRequest() { 1429 if (DEBUG) Log.d(TAG, "xtraDownloadRequest"); 1430 sendMessage(DOWNLOAD_XTRA_DATA, 0, null); 1431 } 1432 1433 /** 1434 * Helper method to construct a location object. 1435 */ 1436 private Location buildLocation( 1437 int flags, 1438 double latitude, 1439 double longitude, 1440 double altitude, 1441 float speed, 1442 float bearing, 1443 float accuracy, 1444 long timestamp) { 1445 Location location = new Location(LocationManager.GPS_PROVIDER); 1446 if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1447 location.setLatitude(latitude); 1448 location.setLongitude(longitude); 1449 location.setTime(timestamp); 1450 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 1451 } 1452 if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { 1453 location.setAltitude(altitude); 1454 } 1455 if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { 1456 location.setSpeed(speed); 1457 } 1458 if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { 1459 location.setBearing(bearing); 1460 } 1461 if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { 1462 location.setAccuracy(accuracy); 1463 } 1464 return location; 1465 } 1466 1467 /** 1468 * Converts the GPS HAL status to the internal Geofence Hardware status. 1469 */ 1470 private int getGeofenceStatus(int status) { 1471 switch(status) { 1472 case GPS_GEOFENCE_OPERATION_SUCCESS: 1473 return GeofenceHardware.GEOFENCE_SUCCESS; 1474 case GPS_GEOFENCE_ERROR_GENERIC: 1475 return GeofenceHardware.GEOFENCE_FAILURE; 1476 case GPS_GEOFENCE_ERROR_ID_EXISTS: 1477 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; 1478 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION: 1479 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; 1480 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES: 1481 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; 1482 case GPS_GEOFENCE_ERROR_ID_UNKNOWN: 1483 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; 1484 default: 1485 return -1; 1486 } 1487 } 1488 1489 /** 1490 * Called from native to report GPS Geofence transition 1491 * All geofence callbacks are called on the same thread 1492 */ 1493 private void reportGeofenceTransition(int geofenceId, int flags, double latitude, 1494 double longitude, double altitude, float speed, float bearing, float accuracy, 1495 long timestamp, int transition, long transitionTimestamp) { 1496 if (mGeofenceHardwareImpl == null) { 1497 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1498 } 1499 Location location = buildLocation( 1500 flags, 1501 latitude, 1502 longitude, 1503 altitude, 1504 speed, 1505 bearing, 1506 accuracy, 1507 timestamp); 1508 mGeofenceHardwareImpl.reportGeofenceTransition( 1509 geofenceId, 1510 location, 1511 transition, 1512 transitionTimestamp, 1513 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 1514 FusedBatchOptions.SourceTechnologies.GNSS); 1515 } 1516 1517 /** 1518 * called from native code to report GPS status change. 1519 */ 1520 private void reportGeofenceStatus(int status, int flags, double latitude, 1521 double longitude, double altitude, float speed, float bearing, float accuracy, 1522 long timestamp) { 1523 if (mGeofenceHardwareImpl == null) { 1524 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1525 } 1526 Location location = buildLocation( 1527 flags, 1528 latitude, 1529 longitude, 1530 altitude, 1531 speed, 1532 bearing, 1533 accuracy, 1534 timestamp); 1535 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; 1536 if(status == GPS_GEOFENCE_AVAILABLE) { 1537 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; 1538 } 1539 mGeofenceHardwareImpl.reportGeofenceMonitorStatus( 1540 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 1541 monitorStatus, 1542 location, 1543 FusedBatchOptions.SourceTechnologies.GNSS); 1544 } 1545 1546 /** 1547 * called from native code - Geofence Add callback 1548 */ 1549 private void reportGeofenceAddStatus(int geofenceId, int status) { 1550 if (mGeofenceHardwareImpl == null) { 1551 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1552 } 1553 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status)); 1554 } 1555 1556 /** 1557 * called from native code - Geofence Remove callback 1558 */ 1559 private void reportGeofenceRemoveStatus(int geofenceId, int status) { 1560 if (mGeofenceHardwareImpl == null) { 1561 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1562 } 1563 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status)); 1564 } 1565 1566 /** 1567 * called from native code - Geofence Pause callback 1568 */ 1569 private void reportGeofencePauseStatus(int geofenceId, int status) { 1570 if (mGeofenceHardwareImpl == null) { 1571 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1572 } 1573 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status)); 1574 } 1575 1576 /** 1577 * called from native code - Geofence Resume callback 1578 */ 1579 private void reportGeofenceResumeStatus(int geofenceId, int status) { 1580 if (mGeofenceHardwareImpl == null) { 1581 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1582 } 1583 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status)); 1584 } 1585 1586 //============================================================= 1587 // NI Client support 1588 //============================================================= 1589 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() { 1590 // Sends a response for an NI reqeust to HAL. 1591 @Override 1592 public boolean sendNiResponse(int notificationId, int userResponse) 1593 { 1594 // TODO Add Permission check 1595 1596 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId + 1597 ", response: " + userResponse); 1598 native_send_ni_response(notificationId, userResponse); 1599 return true; 1600 } 1601 }; 1602 1603 public INetInitiatedListener getNetInitiatedListener() { 1604 return mNetInitiatedListener; 1605 } 1606 1607 // Called by JNI function to report an NI request. 1608 public void reportNiNotification( 1609 int notificationId, 1610 int niType, 1611 int notifyFlags, 1612 int timeout, 1613 int defaultResponse, 1614 String requestorId, 1615 String text, 1616 int requestorIdEncoding, 1617 int textEncoding, 1618 String extras // Encoded extra data 1619 ) 1620 { 1621 Log.i(TAG, "reportNiNotification: entered"); 1622 Log.i(TAG, "notificationId: " + notificationId + 1623 ", niType: " + niType + 1624 ", notifyFlags: " + notifyFlags + 1625 ", timeout: " + timeout + 1626 ", defaultResponse: " + defaultResponse); 1627 1628 Log.i(TAG, "requestorId: " + requestorId + 1629 ", text: " + text + 1630 ", requestorIdEncoding: " + requestorIdEncoding + 1631 ", textEncoding: " + textEncoding); 1632 1633 GpsNiNotification notification = new GpsNiNotification(); 1634 1635 notification.notificationId = notificationId; 1636 notification.niType = niType; 1637 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0; 1638 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0; 1639 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0; 1640 notification.timeout = timeout; 1641 notification.defaultResponse = defaultResponse; 1642 notification.requestorId = requestorId; 1643 notification.text = text; 1644 notification.requestorIdEncoding = requestorIdEncoding; 1645 notification.textEncoding = textEncoding; 1646 1647 // Process extras, assuming the format is 1648 // one of more lines of "key = value" 1649 Bundle bundle = new Bundle(); 1650 1651 if (extras == null) extras = ""; 1652 Properties extraProp = new Properties(); 1653 1654 try { 1655 extraProp.load(new StringReader(extras)); 1656 } 1657 catch (IOException e) 1658 { 1659 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras); 1660 } 1661 1662 for (Entry<Object, Object> ent : extraProp.entrySet()) 1663 { 1664 bundle.putString((String) ent.getKey(), (String) ent.getValue()); 1665 } 1666 1667 notification.extras = bundle; 1668 1669 mNIHandler.handleNiNotification(notification); 1670 } 1671 1672 /** 1673 * Called from native code to request set id info. 1674 * We should be careful about receiving null string from the TelephonyManager, 1675 * because sending null String to JNI function would cause a crash. 1676 */ 1677 1678 private void requestSetID(int flags) { 1679 TelephonyManager phone = (TelephonyManager) 1680 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1681 int type = AGPS_SETID_TYPE_NONE; 1682 String data = ""; 1683 1684 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) { 1685 String data_temp = phone.getSubscriberId(); 1686 if (data_temp == null) { 1687 // This means the framework does not have the SIM card ready. 1688 } else { 1689 // This means the framework has the SIM card. 1690 data = data_temp; 1691 type = AGPS_SETID_TYPE_IMSI; 1692 } 1693 } 1694 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) { 1695 String data_temp = phone.getLine1Number(); 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_MSISDN; 1702 } 1703 } 1704 native_agps_set_id(type, data); 1705 } 1706 1707 /** 1708 * Called from native code to request utc time info 1709 */ 1710 1711 private void requestUtcTime() { 1712 sendMessage(INJECT_NTP_TIME, 0, null); 1713 } 1714 1715 /** 1716 * Called from native code to request reference location info 1717 */ 1718 1719 private void requestRefLocation(int flags) { 1720 TelephonyManager phone = (TelephonyManager) 1721 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1722 final int phoneType = phone.getPhoneType(); 1723 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) { 1724 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation(); 1725 if ((gsm_cell != null) && (phone.getNetworkOperator() != null) 1726 && (phone.getNetworkOperator().length() > 3)) { 1727 int type; 1728 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3)); 1729 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3)); 1730 int networkType = phone.getNetworkType(); 1731 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS 1732 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA 1733 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA 1734 || networkType == TelephonyManager.NETWORK_TYPE_HSPA 1735 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) { 1736 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID; 1737 } else { 1738 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID; 1739 } 1740 native_agps_set_ref_location_cellid(type, mcc, mnc, 1741 gsm_cell.getLac(), gsm_cell.getCid()); 1742 } else { 1743 Log.e(TAG,"Error getting cell location info."); 1744 } 1745 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { 1746 Log.e(TAG, "CDMA not supported."); 1747 } 1748 } 1749 1750 private void sendMessage(int message, int arg, Object obj) { 1751 // hold a wake lock until this message is delivered 1752 // note that this assumes the message will not be removed from the queue before 1753 // it is handled (otherwise the wake lock would be leaked). 1754 mWakeLock.acquire(); 1755 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget(); 1756 } 1757 1758 private final class ProviderHandler extends Handler { 1759 public ProviderHandler(Looper looper) { 1760 super(looper, null, true /*async*/); 1761 } 1762 1763 @Override 1764 public void handleMessage(Message msg) { 1765 int message = msg.what; 1766 switch (message) { 1767 case ENABLE: 1768 if (msg.arg1 == 1) { 1769 handleEnable(); 1770 } else { 1771 handleDisable(); 1772 } 1773 break; 1774 case SET_REQUEST: 1775 GpsRequest gpsRequest = (GpsRequest) msg.obj; 1776 handleSetRequest(gpsRequest.request, gpsRequest.source); 1777 break; 1778 case UPDATE_NETWORK_STATE: 1779 handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj); 1780 break; 1781 case INJECT_NTP_TIME: 1782 handleInjectNtpTime(); 1783 break; 1784 case DOWNLOAD_XTRA_DATA: 1785 if (mSupportsXtra) { 1786 handleDownloadXtraData(); 1787 } 1788 break; 1789 case INJECT_NTP_TIME_FINISHED: 1790 mInjectNtpTimePending = STATE_IDLE; 1791 break; 1792 case DOWNLOAD_XTRA_DATA_FINISHED: 1793 mDownloadXtraDataPending = STATE_IDLE; 1794 break; 1795 case UPDATE_LOCATION: 1796 handleUpdateLocation((Location)msg.obj); 1797 break; 1798 } 1799 if (msg.arg2 == 1) { 1800 // wakelock was taken for this message, release it 1801 mWakeLock.release(); 1802 } 1803 } 1804 }; 1805 1806 private final class NetworkLocationListener implements LocationListener { 1807 @Override 1808 public void onLocationChanged(Location location) { 1809 // this callback happens on mHandler looper 1810 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { 1811 handleUpdateLocation(location); 1812 } 1813 } 1814 @Override 1815 public void onStatusChanged(String provider, int status, Bundle extras) { } 1816 @Override 1817 public void onProviderEnabled(String provider) { } 1818 @Override 1819 public void onProviderDisabled(String provider) { } 1820 } 1821 1822 private String getSelectedApn() { 1823 Uri uri = Uri.parse("content://telephony/carriers/preferapn"); 1824 String apn = null; 1825 1826 Cursor cursor = mContext.getContentResolver().query(uri, new String[] {"apn"}, 1827 null, null, Carriers.DEFAULT_SORT_ORDER); 1828 1829 if (null != cursor) { 1830 try { 1831 if (cursor.moveToFirst()) { 1832 apn = cursor.getString(0); 1833 } 1834 } finally { 1835 cursor.close(); 1836 } 1837 } 1838 return apn; 1839 } 1840 1841 @Override 1842 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1843 StringBuilder s = new StringBuilder(); 1844 s.append(" mFixInterval=").append(mFixInterval).append("\n"); 1845 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" ("); 1846 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED "); 1847 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB "); 1848 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA "); 1849 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT "); 1850 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME "); 1851 s.append(")\n"); 1852 1853 s.append(native_get_internal_state()); 1854 pw.append(s); 1855 } 1856 1857 // for GPS SV statistics 1858 private static final int MAX_SVS = 32; 1859 private static final int EPHEMERIS_MASK = 0; 1860 private static final int ALMANAC_MASK = 1; 1861 private static final int USED_FOR_FIX_MASK = 2; 1862 1863 // preallocated arrays, to avoid memory allocation in reportStatus() 1864 private int mSvs[] = new int[MAX_SVS]; 1865 private float mSnrs[] = new float[MAX_SVS]; 1866 private float mSvElevations[] = new float[MAX_SVS]; 1867 private float mSvAzimuths[] = new float[MAX_SVS]; 1868 private int mSvMasks[] = new int[3]; 1869 private int mSvCount; 1870 // preallocated to avoid memory allocation in reportNmea() 1871 private byte[] mNmeaBuffer = new byte[120]; 1872 1873 static { class_init_native(); } 1874 private static native void class_init_native(); 1875 private static native boolean native_is_supported(); 1876 1877 private native boolean native_init(); 1878 private native void native_cleanup(); 1879 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval, 1880 int preferred_accuracy, int preferred_time); 1881 private native boolean native_start(); 1882 private native boolean native_stop(); 1883 private native void native_delete_aiding_data(int flags); 1884 // returns number of SVs 1885 // mask[0] is ephemeris mask and mask[1] is almanac mask 1886 private native int native_read_sv_status(int[] svs, float[] snrs, 1887 float[] elevations, float[] azimuths, int[] masks); 1888 private native int native_read_nmea(byte[] buffer, int bufferSize); 1889 private native void native_inject_location(double latitude, double longitude, float accuracy); 1890 1891 // XTRA Support 1892 private native void native_inject_time(long time, long timeReference, int uncertainty); 1893 private native boolean native_supports_xtra(); 1894 private native void native_inject_xtra_data(byte[] data, int length); 1895 1896 // DEBUG Support 1897 private native String native_get_internal_state(); 1898 1899 // AGPS Support 1900 private native void native_agps_data_conn_open(String apn); 1901 private native void native_agps_data_conn_closed(); 1902 private native void native_agps_data_conn_failed(); 1903 private native void native_agps_ni_message(byte [] msg, int length); 1904 private native void native_set_agps_server(int type, String hostname, int port); 1905 1906 // Network-initiated (NI) Support 1907 private native void native_send_ni_response(int notificationId, int userResponse); 1908 1909 // AGPS ril suport 1910 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, 1911 int lac, int cid); 1912 private native void native_agps_set_id(int type, String setid); 1913 1914 private native void native_update_network_state(boolean connected, int type, 1915 boolean roaming, boolean available, String extraInfo, String defaultAPN); 1916 1917 // Hardware Geofence support. 1918 private static native boolean native_is_geofence_supported(); 1919 private static native boolean native_add_geofence(int geofenceId, double latitude, 1920 double longitude, double radius, int lastTransition,int monitorTransitions, 1921 int notificationResponsivenes, int unknownTimer); 1922 private static native boolean native_remove_geofence(int geofenceId); 1923 private static native boolean native_resume_geofence(int geofenceId, int transitions); 1924 private static native boolean native_pause_geofence(int geofenceId); 1925} 1926