GpsLocationProvider.java revision 3324e954127de3db2b3200fdefca8f4d0400b7bb
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.setSuplEsEnablement(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 String[] split = item.split("="); 594 if (split.length == 2) { 595 properties.setProperty(split[0].trim().toUpperCase(), split[1]); 596 } else { 597 Log.w(TAG, "malformed contents: " + item); 598 } 599 } 600 } 601 602 private boolean loadPropertiesFromFile(String filename, 603 Properties properties) { 604 try { 605 File file = new File(filename); 606 FileInputStream stream = null; 607 try { 608 stream = new FileInputStream(file); 609 properties.load(stream); 610 } finally { 611 IoUtils.closeQuietly(stream); 612 } 613 614 } catch (IOException e) { 615 Log.w(TAG, "Could not open GPS configuration file " + filename); 616 return false; 617 } 618 return true; 619 } 620 621 public GpsLocationProvider(Context context, ILocationManager ilocationManager, 622 Looper looper) { 623 mContext = context; 624 mNtpTime = NtpTrustedTime.getInstance(context); 625 mILocationManager = ilocationManager; 626 627 mLocation.setExtras(mLocationExtras); 628 629 // Create a wake lock 630 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 631 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 632 mWakeLock.setReferenceCounted(true); 633 634 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 635 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0); 636 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0); 637 638 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); 639 640 // App ops service to keep track of who is accessing the GPS 641 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService( 642 Context.APP_OPS_SERVICE)); 643 644 // Battery statistics service to be notified when GPS turns on or off 645 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 646 BatteryStats.SERVICE_NAME)); 647 648 // Load GPS configuration. 649 mProperties = new Properties(); 650 reloadGpsProperties(mContext, mProperties); 651 652 // Create a GPS net-initiated handler. 653 mNIHandler = new GpsNetInitiatedHandler(context, 654 mNetInitiatedListener, 655 mSuplEsEnabled); 656 657 // construct handler, listen for events 658 mHandler = new ProviderHandler(looper); 659 listenForBroadcasts(); 660 661 // also listen for PASSIVE_PROVIDER updates 662 mHandler.post(new Runnable() { 663 @Override 664 public void run() { 665 LocationManager locManager = 666 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 667 final long minTime = 0; 668 final float minDistance = 0; 669 final boolean oneShot = false; 670 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 671 LocationManager.PASSIVE_PROVIDER, 672 minTime, 673 minDistance, 674 oneShot); 675 // Don't keep track of this request since it's done on behalf of other clients 676 // (which are kept track of separately). 677 request.setHideFromAppOps(true); 678 locManager.requestLocationUpdates( 679 request, 680 new NetworkLocationListener(), 681 mHandler.getLooper()); 682 } 683 }); 684 } 685 686 private void listenForBroadcasts() { 687 IntentFilter intentFilter = new IntentFilter(); 688 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION); 689 intentFilter.addDataScheme("sms"); 690 intentFilter.addDataAuthority("localhost","7275"); 691 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, mHandler); 692 693 intentFilter = new IntentFilter(); 694 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION); 695 try { 696 intentFilter.addDataType("application/vnd.omaloc-supl-init"); 697 } catch (IntentFilter.MalformedMimeTypeException e) { 698 Log.w(TAG, "Malformed SUPL init mime type"); 699 } 700 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, mHandler); 701 702 intentFilter = new IntentFilter(); 703 intentFilter.addAction(ALARM_WAKEUP); 704 intentFilter.addAction(ALARM_TIMEOUT); 705 intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 706 intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); 707 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 708 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 709 intentFilter.addAction(SIM_STATE_CHANGED); 710 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, mHandler); 711 } 712 713 /** 714 * Returns the name of this provider. 715 */ 716 @Override 717 public String getName() { 718 return LocationManager.GPS_PROVIDER; 719 } 720 721 @Override 722 public ProviderProperties getProperties() { 723 return PROPERTIES; 724 } 725 726 public void updateNetworkState(int state, NetworkInfo info) { 727 sendMessage(UPDATE_NETWORK_STATE, state, info); 728 } 729 730 private void handleUpdateNetworkState(int state, NetworkInfo info) { 731 mNetworkAvailable = (state == LocationProvider.AVAILABLE); 732 733 if (DEBUG) { 734 Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable") 735 + " info: " + info); 736 } 737 738 if (info != null) { 739 boolean dataEnabled = Settings.Global.getInt(mContext.getContentResolver(), 740 Settings.Global.MOBILE_DATA, 1) == 1; 741 boolean networkAvailable = info.isAvailable() && dataEnabled; 742 String defaultApn = getSelectedApn(); 743 if (defaultApn == null) { 744 defaultApn = "dummy-apn"; 745 } 746 747 native_update_network_state(info.isConnected(), info.getType(), 748 info.isRoaming(), networkAvailable, 749 info.getExtraInfo(), defaultApn); 750 } 751 752 if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL 753 && mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { 754 if (mNetworkAvailable) { 755 String apnName = info.getExtraInfo(); 756 if (apnName == null) { 757 /* Assign a dummy value in the case of C2K as otherwise we will have a runtime 758 exception in the following call to native_agps_data_conn_open*/ 759 apnName = "dummy-apn"; 760 } 761 mAGpsApn = apnName; 762 mApnIpType = getApnIpType(apnName); 763 setRouting(); 764 if (DEBUG) { 765 String message = String.format( 766 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s", 767 mAGpsApn, mApnIpType); 768 Log.d(TAG, message); 769 } 770 native_agps_data_conn_open(mAGpsApn, mApnIpType); 771 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 772 } else { 773 Log.e(TAG, "call native_agps_data_conn_failed, info: " + info); 774 mAGpsApn = null; 775 mApnIpType = APN_INVALID; 776 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 777 native_agps_data_conn_failed(); 778 } 779 } 780 781 if (mNetworkAvailable) { 782 if (mInjectNtpTimePending == STATE_PENDING_NETWORK) { 783 sendMessage(INJECT_NTP_TIME, 0, null); 784 } 785 if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) { 786 sendMessage(DOWNLOAD_XTRA_DATA, 0, null); 787 } 788 } 789 } 790 791 private void handleInjectNtpTime() { 792 if (mInjectNtpTimePending == STATE_DOWNLOADING) { 793 // already downloading data 794 return; 795 } 796 if (!mNetworkAvailable) { 797 // try again when network is up 798 mInjectNtpTimePending = STATE_PENDING_NETWORK; 799 return; 800 } 801 mInjectNtpTimePending = STATE_DOWNLOADING; 802 803 // hold wake lock while task runs 804 mWakeLock.acquire(); 805 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { 806 @Override 807 public void run() { 808 long delay; 809 810 // force refresh NTP cache when outdated 811 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) { 812 mNtpTime.forceRefresh(); 813 } 814 815 // only update when NTP time is fresh 816 if (mNtpTime.getCacheAge() < NTP_INTERVAL) { 817 long time = mNtpTime.getCachedNtpTime(); 818 long timeReference = mNtpTime.getCachedNtpTimeReference(); 819 long certainty = mNtpTime.getCacheCertainty(); 820 long now = System.currentTimeMillis(); 821 822 Log.d(TAG, "NTP server returned: " 823 + time + " (" + new Date(time) 824 + ") reference: " + timeReference 825 + " certainty: " + certainty 826 + " system time offset: " + (time - now)); 827 828 native_inject_time(time, timeReference, (int) certainty); 829 delay = NTP_INTERVAL; 830 } else { 831 if (DEBUG) Log.d(TAG, "requestTime failed"); 832 delay = RETRY_INTERVAL; 833 } 834 835 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null); 836 837 if (mPeriodicTimeInjection) { 838 // send delayed message for next NTP injection 839 // since this is delayed and not urgent we do not hold a wake lock here 840 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay); 841 } 842 843 // release wake lock held by task 844 mWakeLock.release(); 845 } 846 }); 847 } 848 849 private void handleDownloadXtraData() { 850 if (mDownloadXtraDataPending == STATE_DOWNLOADING) { 851 // already downloading data 852 return; 853 } 854 if (!mNetworkAvailable) { 855 // try again when network is up 856 mDownloadXtraDataPending = STATE_PENDING_NETWORK; 857 return; 858 } 859 mDownloadXtraDataPending = STATE_DOWNLOADING; 860 861 // hold wake lock while task runs 862 mWakeLock.acquire(); 863 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { 864 @Override 865 public void run() { 866 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties); 867 byte[] data = xtraDownloader.downloadXtraData(); 868 if (data != null) { 869 if (DEBUG) { 870 Log.d(TAG, "calling native_inject_xtra_data"); 871 } 872 native_inject_xtra_data(data, data.length); 873 } 874 875 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null); 876 877 if (data == null) { 878 // try again later 879 // since this is delayed and not urgent we do not hold a wake lock here 880 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA, RETRY_INTERVAL); 881 } 882 883 // release wake lock held by task 884 mWakeLock.release(); 885 } 886 }); 887 } 888 889 private void handleUpdateLocation(Location location) { 890 if (location.hasAccuracy()) { 891 native_inject_location(location.getLatitude(), location.getLongitude(), 892 location.getAccuracy()); 893 } 894 } 895 896 /** 897 * Enables this provider. When enabled, calls to getStatus() 898 * must be handled. Hardware may be started up 899 * when the provider is enabled. 900 */ 901 @Override 902 public void enable() { 903 synchronized (mLock) { 904 if (mEnabled) return; 905 mEnabled = true; 906 } 907 908 sendMessage(ENABLE, 1, null); 909 } 910 911 private void setSuplHostPort(String hostString, String portString) { 912 if (hostString != null) { 913 mSuplServerHost = hostString; 914 } 915 if (portString != null) { 916 try { 917 mSuplServerPort = Integer.parseInt(portString); 918 } catch (NumberFormatException e) { 919 Log.e(TAG, "unable to parse SUPL_PORT: " + portString); 920 } 921 } 922 } 923 924 private void handleEnable() { 925 if (DEBUG) Log.d(TAG, "handleEnable"); 926 927 boolean enabled = native_init(); 928 929 if (enabled) { 930 mSupportsXtra = native_supports_xtra(); 931 if (mSuplServerHost != null) { 932 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); 933 } 934 if (mC2KServerHost != null) { 935 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort); 936 } 937 } else { 938 synchronized (mLock) { 939 mEnabled = false; 940 } 941 Log.w(TAG, "Failed to enable location provider"); 942 } 943 } 944 945 /** 946 * Disables this provider. When disabled, calls to getStatus() 947 * need not be handled. Hardware may be shut 948 * down while the provider is disabled. 949 */ 950 @Override 951 public void disable() { 952 synchronized (mLock) { 953 if (!mEnabled) return; 954 mEnabled = false; 955 } 956 957 sendMessage(ENABLE, 0, null); 958 } 959 960 private void handleDisable() { 961 if (DEBUG) Log.d(TAG, "handleDisable"); 962 963 updateClientUids(new WorkSource()); 964 stopNavigating(); 965 mAlarmManager.cancel(mWakeupIntent); 966 mAlarmManager.cancel(mTimeoutIntent); 967 968 // do this before releasing wakelock 969 native_cleanup(); 970 } 971 972 @Override 973 public boolean isEnabled() { 974 synchronized (mLock) { 975 return mEnabled; 976 } 977 } 978 979 @Override 980 public int getStatus(Bundle extras) { 981 if (extras != null) { 982 extras.putInt("satellites", mSvCount); 983 } 984 return mStatus; 985 } 986 987 private void updateStatus(int status, int svCount) { 988 if (status != mStatus || svCount != mSvCount) { 989 mStatus = status; 990 mSvCount = svCount; 991 mLocationExtras.putInt("satellites", svCount); 992 mStatusUpdateTime = SystemClock.elapsedRealtime(); 993 } 994 } 995 996 @Override 997 public long getStatusUpdateTime() { 998 return mStatusUpdateTime; 999 } 1000 1001 @Override 1002 public void setRequest(ProviderRequest request, WorkSource source) { 1003 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source)); 1004 } 1005 1006 private void handleSetRequest(ProviderRequest request, WorkSource source) { 1007 mProviderRequest = request; 1008 mWorkSource = source; 1009 updateRequirements(); 1010 } 1011 1012 // Called when the requirements for GPS may have changed 1013 private void updateRequirements() { 1014 if (mProviderRequest == null || mWorkSource == null) { 1015 return; 1016 } 1017 1018 boolean singleShot = false; 1019 1020 // see if the request is for a single update 1021 if (mProviderRequest.locationRequests != null 1022 && mProviderRequest.locationRequests.size() > 0) { 1023 // if any request has zero or more than one updates 1024 // requested, then this is not single-shot mode 1025 singleShot = true; 1026 1027 for (LocationRequest lr : mProviderRequest.locationRequests) { 1028 if (lr.getNumUpdates() != 1) { 1029 singleShot = false; 1030 } 1031 } 1032 } 1033 1034 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest); 1035 if (mProviderRequest.reportLocation && !mDisableGps) { 1036 // update client uids 1037 updateClientUids(mWorkSource); 1038 1039 mFixInterval = (int) mProviderRequest.interval; 1040 1041 // check for overflow 1042 if (mFixInterval != mProviderRequest.interval) { 1043 Log.w(TAG, "interval overflow: " + mProviderRequest.interval); 1044 mFixInterval = Integer.MAX_VALUE; 1045 } 1046 1047 // apply request to GPS engine 1048 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) { 1049 // change period 1050 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 1051 mFixInterval, 0, 0)) { 1052 Log.e(TAG, "set_position_mode failed in setMinTime()"); 1053 } 1054 } else if (!mStarted) { 1055 // start GPS 1056 startNavigating(singleShot); 1057 } 1058 } else { 1059 updateClientUids(new WorkSource()); 1060 1061 stopNavigating(); 1062 mAlarmManager.cancel(mWakeupIntent); 1063 mAlarmManager.cancel(mTimeoutIntent); 1064 } 1065 } 1066 1067 private void updateClientUids(WorkSource source) { 1068 // Update work source. 1069 WorkSource[] changes = mClientSource.setReturningDiffs(source); 1070 if (changes == null) { 1071 return; 1072 } 1073 WorkSource newWork = changes[0]; 1074 WorkSource goneWork = changes[1]; 1075 1076 // Update sources that were not previously tracked. 1077 if (newWork != null) { 1078 int lastuid = -1; 1079 for (int i=0; i<newWork.size(); i++) { 1080 try { 1081 int uid = newWork.get(i); 1082 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), 1083 AppOpsManager.OP_GPS, uid, newWork.getName(i)); 1084 if (uid != lastuid) { 1085 lastuid = uid; 1086 mBatteryStats.noteStartGps(uid); 1087 } 1088 } catch (RemoteException e) { 1089 Log.w(TAG, "RemoteException", e); 1090 } 1091 } 1092 } 1093 1094 // Update sources that are no longer tracked. 1095 if (goneWork != null) { 1096 int lastuid = -1; 1097 for (int i=0; i<goneWork.size(); i++) { 1098 try { 1099 int uid = goneWork.get(i); 1100 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), 1101 AppOpsManager.OP_GPS, uid, goneWork.getName(i)); 1102 if (uid != lastuid) { 1103 lastuid = uid; 1104 mBatteryStats.noteStopGps(uid); 1105 } 1106 } catch (RemoteException e) { 1107 Log.w(TAG, "RemoteException", e); 1108 } 1109 } 1110 } 1111 } 1112 1113 @Override 1114 public boolean sendExtraCommand(String command, Bundle extras) { 1115 1116 long identity = Binder.clearCallingIdentity(); 1117 boolean result = false; 1118 1119 if ("delete_aiding_data".equals(command)) { 1120 result = deleteAidingData(extras); 1121 } else if ("force_time_injection".equals(command)) { 1122 sendMessage(INJECT_NTP_TIME, 0, null); 1123 result = true; 1124 } else if ("force_xtra_injection".equals(command)) { 1125 if (mSupportsXtra) { 1126 xtraDownloadRequest(); 1127 result = true; 1128 } 1129 } else { 1130 Log.w(TAG, "sendExtraCommand: unknown command " + command); 1131 } 1132 1133 Binder.restoreCallingIdentity(identity); 1134 return result; 1135 } 1136 1137 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() { 1138 public boolean isHardwareGeofenceSupported() { 1139 return native_is_geofence_supported(); 1140 } 1141 1142 public boolean addCircularHardwareGeofence(int geofenceId, double latitude, 1143 double longitude, double radius, int lastTransition, int monitorTransitions, 1144 int notificationResponsiveness, int unknownTimer) { 1145 return native_add_geofence(geofenceId, latitude, longitude, radius, 1146 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer); 1147 } 1148 1149 public boolean removeHardwareGeofence(int geofenceId) { 1150 return native_remove_geofence(geofenceId); 1151 } 1152 1153 public boolean pauseHardwareGeofence(int geofenceId) { 1154 return native_pause_geofence(geofenceId); 1155 } 1156 1157 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) { 1158 return native_resume_geofence(geofenceId, monitorTransition); 1159 } 1160 }; 1161 1162 private boolean deleteAidingData(Bundle extras) { 1163 int flags; 1164 1165 if (extras == null) { 1166 flags = GPS_DELETE_ALL; 1167 } else { 1168 flags = 0; 1169 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS; 1170 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC; 1171 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION; 1172 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME; 1173 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO; 1174 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC; 1175 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH; 1176 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR; 1177 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER; 1178 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA; 1179 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI; 1180 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO; 1181 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL; 1182 } 1183 1184 if (flags != 0) { 1185 native_delete_aiding_data(flags); 1186 return true; 1187 } 1188 1189 return false; 1190 } 1191 1192 private void startNavigating(boolean singleShot) { 1193 if (!mStarted) { 1194 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot); 1195 mTimeToFirstFix = 0; 1196 mLastFixTime = 0; 1197 mStarted = true; 1198 mSingleShot = singleShot; 1199 mPositionMode = GPS_POSITION_MODE_STANDALONE; 1200 1201 if (Settings.Global.getInt(mContext.getContentResolver(), 1202 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0) { 1203 if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) { 1204 mPositionMode = GPS_POSITION_MODE_MS_ASSISTED; 1205 } else if (hasCapability(GPS_CAPABILITY_MSB)) { 1206 mPositionMode = GPS_POSITION_MODE_MS_BASED; 1207 } 1208 } 1209 1210 if (DEBUG) { 1211 String mode; 1212 1213 switch(mPositionMode) { 1214 case GPS_POSITION_MODE_STANDALONE: 1215 mode = "standalone"; 1216 break; 1217 case GPS_POSITION_MODE_MS_ASSISTED: 1218 mode = "MS_ASSISTED"; 1219 break; 1220 case GPS_POSITION_MODE_MS_BASED: 1221 mode = "MS_BASED"; 1222 break; 1223 default: 1224 mode = "unknown"; 1225 break; 1226 } 1227 Log.d(TAG, "setting position_mode to " + mode); 1228 } 1229 1230 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000); 1231 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 1232 interval, 0, 0)) { 1233 mStarted = false; 1234 Log.e(TAG, "set_position_mode failed in startNavigating()"); 1235 return; 1236 } 1237 if (!native_start()) { 1238 mStarted = false; 1239 Log.e(TAG, "native_start failed in startNavigating()"); 1240 return; 1241 } 1242 1243 // reset SV count to zero 1244 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); 1245 mFixRequestTime = System.currentTimeMillis(); 1246 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) { 1247 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 1248 // and our fix interval is not short 1249 if (mFixInterval >= NO_FIX_TIMEOUT) { 1250 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1251 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); 1252 } 1253 } 1254 } 1255 } 1256 1257 private void stopNavigating() { 1258 if (DEBUG) Log.d(TAG, "stopNavigating"); 1259 if (mStarted) { 1260 mStarted = false; 1261 mSingleShot = false; 1262 native_stop(); 1263 mTimeToFirstFix = 0; 1264 mLastFixTime = 0; 1265 mLocationFlags = LOCATION_INVALID; 1266 1267 // reset SV count to zero 1268 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); 1269 } 1270 } 1271 1272 private void hibernate() { 1273 // stop GPS until our next fix interval arrives 1274 stopNavigating(); 1275 mAlarmManager.cancel(mTimeoutIntent); 1276 mAlarmManager.cancel(mWakeupIntent); 1277 long now = SystemClock.elapsedRealtime(); 1278 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent); 1279 } 1280 1281 private boolean hasCapability(int capability) { 1282 return ((mEngineCapabilities & capability) != 0); 1283 } 1284 1285 1286 /** 1287 * called from native code to update our position. 1288 */ 1289 private void reportLocation(int flags, double latitude, double longitude, double altitude, 1290 float speed, float bearing, float accuracy, long timestamp) { 1291 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude + 1292 " timestamp: " + timestamp); 1293 1294 synchronized (mLocation) { 1295 mLocationFlags = flags; 1296 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1297 mLocation.setLatitude(latitude); 1298 mLocation.setLongitude(longitude); 1299 mLocation.setTime(timestamp); 1300 // It would be nice to push the elapsed real-time timestamp 1301 // further down the stack, but this is still useful 1302 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 1303 } 1304 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { 1305 mLocation.setAltitude(altitude); 1306 } else { 1307 mLocation.removeAltitude(); 1308 } 1309 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { 1310 mLocation.setSpeed(speed); 1311 } else { 1312 mLocation.removeSpeed(); 1313 } 1314 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { 1315 mLocation.setBearing(bearing); 1316 } else { 1317 mLocation.removeBearing(); 1318 } 1319 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { 1320 mLocation.setAccuracy(accuracy); 1321 } else { 1322 mLocation.removeAccuracy(); 1323 } 1324 mLocation.setExtras(mLocationExtras); 1325 1326 try { 1327 mILocationManager.reportLocation(mLocation, false); 1328 } catch (RemoteException e) { 1329 Log.e(TAG, "RemoteException calling reportLocation"); 1330 } 1331 } 1332 1333 mLastFixTime = System.currentTimeMillis(); 1334 // report time to first fix 1335 if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1336 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime); 1337 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix); 1338 1339 // notify status listeners 1340 mListenerHelper.onFirstFix(mTimeToFirstFix); 1341 } 1342 1343 if (mSingleShot) { 1344 stopNavigating(); 1345 } 1346 1347 if (mStarted && mStatus != LocationProvider.AVAILABLE) { 1348 // we want to time out if we do not receive a fix 1349 // within the time out and we are requesting infrequent fixes 1350 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) { 1351 mAlarmManager.cancel(mTimeoutIntent); 1352 } 1353 1354 // send an intent to notify that the GPS is receiving fixes. 1355 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1356 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true); 1357 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1358 updateStatus(LocationProvider.AVAILABLE, mSvCount); 1359 } 1360 1361 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted && 1362 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { 1363 if (DEBUG) Log.d(TAG, "got fix, hibernating"); 1364 hibernate(); 1365 } 1366 } 1367 1368 /** 1369 * called from native code to update our status 1370 */ 1371 private void reportStatus(int status) { 1372 if (DEBUG) Log.v(TAG, "reportStatus status: " + status); 1373 1374 boolean wasNavigating = mNavigating; 1375 switch (status) { 1376 case GPS_STATUS_SESSION_BEGIN: 1377 mNavigating = true; 1378 mEngineOn = true; 1379 break; 1380 case GPS_STATUS_SESSION_END: 1381 mNavigating = false; 1382 break; 1383 case GPS_STATUS_ENGINE_ON: 1384 mEngineOn = true; 1385 break; 1386 case GPS_STATUS_ENGINE_OFF: 1387 mEngineOn = false; 1388 mNavigating = false; 1389 break; 1390 } 1391 1392 if (wasNavigating != mNavigating) { 1393 mListenerHelper.onStatusChanged(mNavigating); 1394 1395 // send an intent to notify that the GPS has been enabled or disabled 1396 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION); 1397 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating); 1398 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1399 } 1400 } 1401 1402 /** 1403 * called from native code to update SV info 1404 */ 1405 private void reportSvStatus() { 1406 int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks); 1407 mListenerHelper.onSvStatusChanged( 1408 svCount, 1409 mSvs, 1410 mSnrs, 1411 mSvElevations, 1412 mSvAzimuths, 1413 mSvMasks[EPHEMERIS_MASK], 1414 mSvMasks[ALMANAC_MASK], 1415 mSvMasks[USED_FOR_FIX_MASK]); 1416 1417 if (VERBOSE) { 1418 Log.v(TAG, "SV count: " + svCount + 1419 " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) + 1420 " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK])); 1421 for (int i = 0; i < svCount; i++) { 1422 Log.v(TAG, "sv: " + mSvs[i] + 1423 " snr: " + mSnrs[i]/10 + 1424 " elev: " + mSvElevations[i] + 1425 " azimuth: " + mSvAzimuths[i] + 1426 ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " E") + 1427 ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " A") + 1428 ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U")); 1429 } 1430 } 1431 1432 // return number of sets used in fix instead of total 1433 updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK])); 1434 1435 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 && 1436 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) { 1437 // send an intent to notify that the GPS is no longer receiving fixes. 1438 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1439 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false); 1440 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1441 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount); 1442 } 1443 } 1444 1445 /** 1446 * called from native code to update AGPS status 1447 */ 1448 private void reportAGpsStatus(int type, int status, byte[] ipaddr) { 1449 switch (status) { 1450 case GPS_REQUEST_AGPS_DATA_CONN: 1451 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN"); 1452 Log.v(TAG, "Received SUPL IP addr[]: " + ipaddr); 1453 // Set mAGpsDataConnectionState before calling startUsingNetworkFeature 1454 // to avoid a race condition with handleUpdateNetworkState() 1455 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; 1456 int result = mConnMgr.startUsingNetworkFeature( 1457 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); 1458 if (ipaddr != null) { 1459 try { 1460 mAGpsDataConnectionIpAddr = InetAddress.getByAddress(ipaddr); 1461 Log.v(TAG, "IP address converted to: " + mAGpsDataConnectionIpAddr); 1462 } catch (UnknownHostException e) { 1463 Log.e(TAG, "Bad IP Address: " + ipaddr, e); 1464 mAGpsDataConnectionIpAddr = null; 1465 } 1466 } 1467 1468 if (result == PhoneConstants.APN_ALREADY_ACTIVE) { 1469 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE"); 1470 if (mAGpsApn != null) { 1471 setRouting(); 1472 native_agps_data_conn_open(mAGpsApn, mApnIpType); 1473 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 1474 } else { 1475 Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE"); 1476 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1477 native_agps_data_conn_failed(); 1478 } 1479 } else if (result == PhoneConstants.APN_REQUEST_STARTED) { 1480 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_REQUEST_STARTED"); 1481 // Nothing to do here 1482 } else { 1483 if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed, value is " + 1484 result); 1485 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1486 native_agps_data_conn_failed(); 1487 } 1488 break; 1489 case GPS_RELEASE_AGPS_DATA_CONN: 1490 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN"); 1491 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) { 1492 mConnMgr.stopUsingNetworkFeature( 1493 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); 1494 native_agps_data_conn_closed(); 1495 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1496 mAGpsDataConnectionIpAddr = null; 1497 } 1498 break; 1499 case GPS_AGPS_DATA_CONNECTED: 1500 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED"); 1501 break; 1502 case GPS_AGPS_DATA_CONN_DONE: 1503 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE"); 1504 break; 1505 case GPS_AGPS_DATA_CONN_FAILED: 1506 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED"); 1507 break; 1508 default: 1509 Log.d(TAG, "Received Unknown AGPS status: " + status); 1510 } 1511 } 1512 1513 /** 1514 * called from native code to report NMEA data received 1515 */ 1516 private void reportNmea(long timestamp) { 1517 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length); 1518 String nmea = new String(mNmeaBuffer, 0 /* offset */, length); 1519 mListenerHelper.onNmeaReceived(timestamp, nmea); 1520 } 1521 1522 /** 1523 * called from native code - Gps measurements callback 1524 */ 1525 private void reportMeasurementData(GpsMeasurementsEvent event) { 1526 mGpsMeasurementsProvider.onMeasurementsAvailable(event); 1527 } 1528 1529 /** 1530 * called from native code - GPS navigation message callback 1531 */ 1532 private void reportNavigationMessage(GpsNavigationMessageEvent event) { 1533 mGpsNavigationMessageProvider.onNavigationMessageAvailable(event); 1534 } 1535 1536 /** 1537 * called from native code to inform us what the GPS engine capabilities are 1538 */ 1539 private void setEngineCapabilities(int capabilities) { 1540 mEngineCapabilities = capabilities; 1541 1542 if (!hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME) && !mPeriodicTimeInjection) { 1543 mPeriodicTimeInjection = true; 1544 requestUtcTime(); 1545 } 1546 } 1547 1548 /** 1549 * called from native code to request XTRA data 1550 */ 1551 private void xtraDownloadRequest() { 1552 if (DEBUG) Log.d(TAG, "xtraDownloadRequest"); 1553 sendMessage(DOWNLOAD_XTRA_DATA, 0, null); 1554 } 1555 1556 /** 1557 * Helper method to construct a location object. 1558 */ 1559 private Location buildLocation( 1560 int flags, 1561 double latitude, 1562 double longitude, 1563 double altitude, 1564 float speed, 1565 float bearing, 1566 float accuracy, 1567 long timestamp) { 1568 Location location = new Location(LocationManager.GPS_PROVIDER); 1569 if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1570 location.setLatitude(latitude); 1571 location.setLongitude(longitude); 1572 location.setTime(timestamp); 1573 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 1574 } 1575 if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { 1576 location.setAltitude(altitude); 1577 } 1578 if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { 1579 location.setSpeed(speed); 1580 } 1581 if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { 1582 location.setBearing(bearing); 1583 } 1584 if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { 1585 location.setAccuracy(accuracy); 1586 } 1587 return location; 1588 } 1589 1590 /** 1591 * Converts the GPS HAL status to the internal Geofence Hardware status. 1592 */ 1593 private int getGeofenceStatus(int status) { 1594 switch(status) { 1595 case GPS_GEOFENCE_OPERATION_SUCCESS: 1596 return GeofenceHardware.GEOFENCE_SUCCESS; 1597 case GPS_GEOFENCE_ERROR_GENERIC: 1598 return GeofenceHardware.GEOFENCE_FAILURE; 1599 case GPS_GEOFENCE_ERROR_ID_EXISTS: 1600 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; 1601 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION: 1602 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; 1603 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES: 1604 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; 1605 case GPS_GEOFENCE_ERROR_ID_UNKNOWN: 1606 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; 1607 default: 1608 return -1; 1609 } 1610 } 1611 1612 /** 1613 * Called from native to report GPS Geofence transition 1614 * All geofence callbacks are called on the same thread 1615 */ 1616 private void reportGeofenceTransition(int geofenceId, int flags, double latitude, 1617 double longitude, double altitude, float speed, float bearing, float accuracy, 1618 long timestamp, int transition, long transitionTimestamp) { 1619 if (mGeofenceHardwareImpl == null) { 1620 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1621 } 1622 Location location = buildLocation( 1623 flags, 1624 latitude, 1625 longitude, 1626 altitude, 1627 speed, 1628 bearing, 1629 accuracy, 1630 timestamp); 1631 mGeofenceHardwareImpl.reportGeofenceTransition( 1632 geofenceId, 1633 location, 1634 transition, 1635 transitionTimestamp, 1636 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 1637 FusedBatchOptions.SourceTechnologies.GNSS); 1638 } 1639 1640 /** 1641 * called from native code to report GPS status change. 1642 */ 1643 private void reportGeofenceStatus(int status, int flags, double latitude, 1644 double longitude, double altitude, float speed, float bearing, float accuracy, 1645 long timestamp) { 1646 if (mGeofenceHardwareImpl == null) { 1647 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1648 } 1649 Location location = buildLocation( 1650 flags, 1651 latitude, 1652 longitude, 1653 altitude, 1654 speed, 1655 bearing, 1656 accuracy, 1657 timestamp); 1658 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; 1659 if(status == GPS_GEOFENCE_AVAILABLE) { 1660 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; 1661 } 1662 mGeofenceHardwareImpl.reportGeofenceMonitorStatus( 1663 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 1664 monitorStatus, 1665 location, 1666 FusedBatchOptions.SourceTechnologies.GNSS); 1667 } 1668 1669 /** 1670 * called from native code - Geofence Add callback 1671 */ 1672 private void reportGeofenceAddStatus(int geofenceId, int status) { 1673 if (mGeofenceHardwareImpl == null) { 1674 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1675 } 1676 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status)); 1677 } 1678 1679 /** 1680 * called from native code - Geofence Remove callback 1681 */ 1682 private void reportGeofenceRemoveStatus(int geofenceId, int status) { 1683 if (mGeofenceHardwareImpl == null) { 1684 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1685 } 1686 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status)); 1687 } 1688 1689 /** 1690 * called from native code - Geofence Pause callback 1691 */ 1692 private void reportGeofencePauseStatus(int geofenceId, int status) { 1693 if (mGeofenceHardwareImpl == null) { 1694 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1695 } 1696 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status)); 1697 } 1698 1699 /** 1700 * called from native code - Geofence Resume callback 1701 */ 1702 private void reportGeofenceResumeStatus(int geofenceId, int status) { 1703 if (mGeofenceHardwareImpl == null) { 1704 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 1705 } 1706 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status)); 1707 } 1708 1709 //============================================================= 1710 // NI Client support 1711 //============================================================= 1712 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() { 1713 // Sends a response for an NI reqeust to HAL. 1714 @Override 1715 public boolean sendNiResponse(int notificationId, int userResponse) 1716 { 1717 // TODO Add Permission check 1718 1719 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId + 1720 ", response: " + userResponse); 1721 native_send_ni_response(notificationId, userResponse); 1722 return true; 1723 } 1724 }; 1725 1726 public INetInitiatedListener getNetInitiatedListener() { 1727 return mNetInitiatedListener; 1728 } 1729 1730 // Called by JNI function to report an NI request. 1731 public void reportNiNotification( 1732 int notificationId, 1733 int niType, 1734 int notifyFlags, 1735 int timeout, 1736 int defaultResponse, 1737 String requestorId, 1738 String text, 1739 int requestorIdEncoding, 1740 int textEncoding, 1741 String extras // Encoded extra data 1742 ) 1743 { 1744 Log.i(TAG, "reportNiNotification: entered"); 1745 Log.i(TAG, "notificationId: " + notificationId + 1746 ", niType: " + niType + 1747 ", notifyFlags: " + notifyFlags + 1748 ", timeout: " + timeout + 1749 ", defaultResponse: " + defaultResponse); 1750 1751 Log.i(TAG, "requestorId: " + requestorId + 1752 ", text: " + text + 1753 ", requestorIdEncoding: " + requestorIdEncoding + 1754 ", textEncoding: " + textEncoding); 1755 1756 GpsNiNotification notification = new GpsNiNotification(); 1757 1758 notification.notificationId = notificationId; 1759 notification.niType = niType; 1760 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0; 1761 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0; 1762 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0; 1763 notification.timeout = timeout; 1764 notification.defaultResponse = defaultResponse; 1765 notification.requestorId = requestorId; 1766 notification.text = text; 1767 notification.requestorIdEncoding = requestorIdEncoding; 1768 notification.textEncoding = textEncoding; 1769 1770 // Process extras, assuming the format is 1771 // one of more lines of "key = value" 1772 Bundle bundle = new Bundle(); 1773 1774 if (extras == null) extras = ""; 1775 Properties extraProp = new Properties(); 1776 1777 try { 1778 extraProp.load(new StringReader(extras)); 1779 } 1780 catch (IOException e) 1781 { 1782 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras); 1783 } 1784 1785 for (Entry<Object, Object> ent : extraProp.entrySet()) 1786 { 1787 bundle.putString((String) ent.getKey(), (String) ent.getValue()); 1788 } 1789 1790 notification.extras = bundle; 1791 1792 mNIHandler.handleNiNotification(notification); 1793 } 1794 1795 /** 1796 * Called from native code to request set id info. 1797 * We should be careful about receiving null string from the TelephonyManager, 1798 * because sending null String to JNI function would cause a crash. 1799 */ 1800 1801 private void requestSetID(int flags) { 1802 TelephonyManager phone = (TelephonyManager) 1803 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1804 int type = AGPS_SETID_TYPE_NONE; 1805 String data = ""; 1806 1807 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) { 1808 String data_temp = phone.getSubscriberId(); 1809 if (data_temp == null) { 1810 // This means the framework does not have the SIM card ready. 1811 } else { 1812 // This means the framework has the SIM card. 1813 data = data_temp; 1814 type = AGPS_SETID_TYPE_IMSI; 1815 } 1816 } 1817 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) { 1818 String data_temp = phone.getLine1Number(); 1819 if (data_temp == null) { 1820 // This means the framework does not have the SIM card ready. 1821 } else { 1822 // This means the framework has the SIM card. 1823 data = data_temp; 1824 type = AGPS_SETID_TYPE_MSISDN; 1825 } 1826 } 1827 native_agps_set_id(type, data); 1828 } 1829 1830 /** 1831 * Called from native code to request utc time info 1832 */ 1833 1834 private void requestUtcTime() { 1835 sendMessage(INJECT_NTP_TIME, 0, null); 1836 } 1837 1838 /** 1839 * Called from native code to request reference location info 1840 */ 1841 1842 private void requestRefLocation(int flags) { 1843 TelephonyManager phone = (TelephonyManager) 1844 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1845 final int phoneType = phone.getPhoneType(); 1846 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) { 1847 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation(); 1848 if ((gsm_cell != null) && (phone.getNetworkOperator() != null) 1849 && (phone.getNetworkOperator().length() > 3)) { 1850 int type; 1851 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3)); 1852 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3)); 1853 int networkType = phone.getNetworkType(); 1854 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS 1855 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA 1856 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA 1857 || networkType == TelephonyManager.NETWORK_TYPE_HSPA 1858 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) { 1859 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID; 1860 } else { 1861 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID; 1862 } 1863 native_agps_set_ref_location_cellid(type, mcc, mnc, 1864 gsm_cell.getLac(), gsm_cell.getCid()); 1865 } else { 1866 Log.e(TAG,"Error getting cell location info."); 1867 } 1868 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { 1869 Log.e(TAG, "CDMA not supported."); 1870 } 1871 } 1872 1873 private void sendMessage(int message, int arg, Object obj) { 1874 // hold a wake lock until this message is delivered 1875 // note that this assumes the message will not be removed from the queue before 1876 // it is handled (otherwise the wake lock would be leaked). 1877 mWakeLock.acquire(); 1878 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget(); 1879 } 1880 1881 private final class ProviderHandler extends Handler { 1882 public ProviderHandler(Looper looper) { 1883 super(looper, null, true /*async*/); 1884 } 1885 1886 @Override 1887 public void handleMessage(Message msg) { 1888 int message = msg.what; 1889 switch (message) { 1890 case ENABLE: 1891 if (msg.arg1 == 1) { 1892 handleEnable(); 1893 } else { 1894 handleDisable(); 1895 } 1896 break; 1897 case SET_REQUEST: 1898 GpsRequest gpsRequest = (GpsRequest) msg.obj; 1899 handleSetRequest(gpsRequest.request, gpsRequest.source); 1900 break; 1901 case UPDATE_NETWORK_STATE: 1902 handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj); 1903 break; 1904 case INJECT_NTP_TIME: 1905 handleInjectNtpTime(); 1906 break; 1907 case DOWNLOAD_XTRA_DATA: 1908 if (mSupportsXtra) { 1909 handleDownloadXtraData(); 1910 } 1911 break; 1912 case INJECT_NTP_TIME_FINISHED: 1913 mInjectNtpTimePending = STATE_IDLE; 1914 break; 1915 case DOWNLOAD_XTRA_DATA_FINISHED: 1916 mDownloadXtraDataPending = STATE_IDLE; 1917 break; 1918 case UPDATE_LOCATION: 1919 handleUpdateLocation((Location)msg.obj); 1920 break; 1921 } 1922 if (msg.arg2 == 1) { 1923 // wakelock was taken for this message, release it 1924 mWakeLock.release(); 1925 } 1926 } 1927 }; 1928 1929 private final class NetworkLocationListener implements LocationListener { 1930 @Override 1931 public void onLocationChanged(Location location) { 1932 // this callback happens on mHandler looper 1933 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { 1934 handleUpdateLocation(location); 1935 } 1936 } 1937 @Override 1938 public void onStatusChanged(String provider, int status, Bundle extras) { } 1939 @Override 1940 public void onProviderEnabled(String provider) { } 1941 @Override 1942 public void onProviderDisabled(String provider) { } 1943 } 1944 1945 private String getSelectedApn() { 1946 Uri uri = Uri.parse("content://telephony/carriers/preferapn"); 1947 Cursor cursor = null; 1948 try { 1949 cursor = mContext.getContentResolver().query( 1950 uri, 1951 new String[] { "apn" }, 1952 null /* selection */, 1953 null /* selectionArgs */, 1954 Carriers.DEFAULT_SORT_ORDER); 1955 if (cursor != null && cursor.moveToFirst()) { 1956 return cursor.getString(0); 1957 } else { 1958 Log.e(TAG, "No APN found to select."); 1959 } 1960 } catch (Exception e) { 1961 Log.e(TAG, "Error encountered on selecting the APN.", e); 1962 } finally { 1963 if (cursor != null) { 1964 cursor.close(); 1965 } 1966 } 1967 1968 return null; 1969 } 1970 1971 private int getApnIpType(String apn) { 1972 if (apn == null) { 1973 return APN_INVALID; 1974 } 1975 1976 // look for cached data to use 1977 if (apn.equals(mAGpsApn) && mApnIpType != APN_INVALID) { 1978 return mApnIpType; 1979 } 1980 1981 String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn); 1982 Cursor cursor = null; 1983 try { 1984 cursor = mContext.getContentResolver().query( 1985 Carriers.CONTENT_URI, 1986 new String[] { Carriers.PROTOCOL }, 1987 selection, 1988 null, 1989 Carriers.DEFAULT_SORT_ORDER); 1990 1991 if (null != cursor && cursor.moveToFirst()) { 1992 return translateToApnIpType(cursor.getString(0), apn); 1993 } else { 1994 Log.e(TAG, "No entry found in query for APN: " + apn); 1995 } 1996 } catch (Exception e) { 1997 Log.e(TAG, "Error encountered on APN query for: " + apn, e); 1998 } finally { 1999 if (cursor != null) { 2000 cursor.close(); 2001 } 2002 } 2003 2004 return APN_INVALID; 2005 } 2006 2007 private int translateToApnIpType(String ipProtocol, String apn) { 2008 if ("IP".equals(ipProtocol)) { 2009 return APN_IPV4; 2010 } 2011 if ("IPV6".equals(ipProtocol)) { 2012 return APN_IPV6; 2013 } 2014 if ("IPV4V6".equals(ipProtocol)) { 2015 return APN_IPV4V6; 2016 } 2017 2018 // we hit the default case so the ipProtocol is not recognized 2019 String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn); 2020 Log.e(TAG, message); 2021 return APN_INVALID; 2022 } 2023 2024 private void setRouting() { 2025 if (mAGpsDataConnectionIpAddr == null) { 2026 return; 2027 } 2028 2029 boolean result = mConnMgr.requestRouteToHostAddress( 2030 ConnectivityManager.TYPE_MOBILE_SUPL, 2031 mAGpsDataConnectionIpAddr); 2032 2033 if (!result) { 2034 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr); 2035 } else if (DEBUG) { 2036 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr); 2037 } 2038 } 2039 2040 @Override 2041 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2042 StringBuilder s = new StringBuilder(); 2043 s.append(" mFixInterval=").append(mFixInterval).append("\n"); 2044 s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append("\n"); 2045 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" ("); 2046 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED "); 2047 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB "); 2048 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA "); 2049 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT "); 2050 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME "); 2051 s.append(")\n"); 2052 2053 s.append(native_get_internal_state()); 2054 pw.append(s); 2055 } 2056 2057 // for GPS SV statistics 2058 private static final int MAX_SVS = 32; 2059 private static final int EPHEMERIS_MASK = 0; 2060 private static final int ALMANAC_MASK = 1; 2061 private static final int USED_FOR_FIX_MASK = 2; 2062 2063 // preallocated arrays, to avoid memory allocation in reportStatus() 2064 private int mSvs[] = new int[MAX_SVS]; 2065 private float mSnrs[] = new float[MAX_SVS]; 2066 private float mSvElevations[] = new float[MAX_SVS]; 2067 private float mSvAzimuths[] = new float[MAX_SVS]; 2068 private int mSvMasks[] = new int[3]; 2069 private int mSvCount; 2070 // preallocated to avoid memory allocation in reportNmea() 2071 private byte[] mNmeaBuffer = new byte[120]; 2072 2073 static { class_init_native(); } 2074 private static native void class_init_native(); 2075 private static native boolean native_is_supported(); 2076 2077 private native boolean native_init(); 2078 private native void native_cleanup(); 2079 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval, 2080 int preferred_accuracy, int preferred_time); 2081 private native boolean native_start(); 2082 private native boolean native_stop(); 2083 private native void native_delete_aiding_data(int flags); 2084 // returns number of SVs 2085 // mask[0] is ephemeris mask and mask[1] is almanac mask 2086 private native int native_read_sv_status(int[] svs, float[] snrs, 2087 float[] elevations, float[] azimuths, int[] masks); 2088 private native int native_read_nmea(byte[] buffer, int bufferSize); 2089 private native void native_inject_location(double latitude, double longitude, float accuracy); 2090 2091 // XTRA Support 2092 private native void native_inject_time(long time, long timeReference, int uncertainty); 2093 private native boolean native_supports_xtra(); 2094 private native void native_inject_xtra_data(byte[] data, int length); 2095 2096 // DEBUG Support 2097 private native String native_get_internal_state(); 2098 2099 // AGPS Support 2100 private native void native_agps_data_conn_open(String apn, int apnIpType); 2101 private native void native_agps_data_conn_closed(); 2102 private native void native_agps_data_conn_failed(); 2103 private native void native_agps_ni_message(byte [] msg, int length); 2104 private native void native_set_agps_server(int type, String hostname, int port); 2105 2106 // Network-initiated (NI) Support 2107 private native void native_send_ni_response(int notificationId, int userResponse); 2108 2109 // AGPS ril suport 2110 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, 2111 int lac, int cid); 2112 private native void native_agps_set_id(int type, String setid); 2113 2114 private native void native_update_network_state(boolean connected, int type, 2115 boolean roaming, boolean available, String extraInfo, String defaultAPN); 2116 2117 // Hardware Geofence support. 2118 private static native boolean native_is_geofence_supported(); 2119 private static native boolean native_add_geofence(int geofenceId, double latitude, 2120 double longitude, double radius, int lastTransition,int monitorTransitions, 2121 int notificationResponsivenes, int unknownTimer); 2122 private static native boolean native_remove_geofence(int geofenceId); 2123 private static native boolean native_resume_geofence(int geofenceId, int transitions); 2124 private static native boolean native_pause_geofence(int geofenceId); 2125 2126 // Gps Hal measurements support. 2127 private static native boolean native_is_measurement_supported(); 2128 private native boolean native_start_measurement_collection(); 2129 private native boolean native_stop_measurement_collection(); 2130 2131 // Gps Navigation message support. 2132 private static native boolean native_is_navigation_message_supported(); 2133 private native boolean native_start_navigation_message_collection(); 2134 private native boolean native_stop_navigation_message_collection(); 2135 2136 // GNSS Configuration 2137 private static native void native_configuration_update(String configData); 2138} 2139 2140