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