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