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