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