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