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