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