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