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