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