GpsLocationProvider.java revision 5c24fd03426db58b63e1a792c2595447cb722d46
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 android.app.AlarmManager; 20import android.app.PendingIntent; 21import android.content.BroadcastReceiver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.database.Cursor; 26import android.location.Criteria; 27import android.location.IGpsStatusListener; 28import android.location.IGpsStatusProvider; 29import android.location.ILocationManager; 30import android.location.INetInitiatedListener; 31import android.location.Location; 32import android.location.LocationListener; 33import android.location.LocationManager; 34import android.location.LocationProvider; 35import android.net.ConnectivityManager; 36import android.net.NetworkInfo; 37import android.net.Uri; 38import android.os.AsyncTask; 39import android.os.Binder; 40import android.os.Bundle; 41import android.os.Handler; 42import android.os.IBinder; 43import android.os.Message; 44import android.os.PowerManager; 45import android.os.RemoteException; 46import android.os.ServiceManager; 47import android.os.SystemClock; 48import android.os.UserHandle; 49import android.os.WorkSource; 50import android.provider.Settings; 51import android.provider.Telephony.Carriers; 52import android.provider.Telephony.Sms.Intents; 53import android.telephony.SmsMessage; 54import android.telephony.TelephonyManager; 55import android.telephony.gsm.GsmCellLocation; 56import android.util.Log; 57import android.util.NtpTrustedTime; 58import com.android.internal.app.IBatteryStats; 59import com.android.internal.location.GpsNetInitiatedHandler; 60import com.android.internal.location.ProviderProperties; 61import com.android.internal.location.ProviderRequest; 62import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification; 63import com.android.internal.telephony.Phone; 64import com.android.internal.telephony.PhoneConstants; 65 66import java.io.File; 67import java.io.FileDescriptor; 68import java.io.FileInputStream; 69import java.io.IOException; 70import java.io.PrintWriter; 71import java.io.StringReader; 72import java.util.ArrayList; 73import java.util.Date; 74import java.util.Map.Entry; 75import java.util.Properties; 76 77/** 78 * A GPS implementation of LocationProvider used by LocationManager. 79 * 80 * {@hide} 81 */ 82public class GpsLocationProvider implements LocationProviderInterface { 83 84 private static final String TAG = "GpsLocationProvider"; 85 86 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 87 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 88 89 private static final ProviderProperties PROPERTIES = new ProviderProperties( 90 true, true, false, false, true, true, true, 91 Criteria.POWER_HIGH, Criteria.ACCURACY_FINE); 92 93 // these need to match GpsPositionMode enum in gps.h 94 private static final int GPS_POSITION_MODE_STANDALONE = 0; 95 private static final int GPS_POSITION_MODE_MS_BASED = 1; 96 private static final int GPS_POSITION_MODE_MS_ASSISTED = 2; 97 98 // these need to match GpsPositionRecurrence enum in gps.h 99 private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0; 100 private static final int GPS_POSITION_RECURRENCE_SINGLE = 1; 101 102 // these need to match GpsStatusValue defines in gps.h 103 private static final int GPS_STATUS_NONE = 0; 104 private static final int GPS_STATUS_SESSION_BEGIN = 1; 105 private static final int GPS_STATUS_SESSION_END = 2; 106 private static final int GPS_STATUS_ENGINE_ON = 3; 107 private static final int GPS_STATUS_ENGINE_OFF = 4; 108 109 // these need to match GpsApgsStatusValue defines in gps.h 110 /** AGPS status event values. */ 111 private static final int GPS_REQUEST_AGPS_DATA_CONN = 1; 112 private static final int GPS_RELEASE_AGPS_DATA_CONN = 2; 113 private static final int GPS_AGPS_DATA_CONNECTED = 3; 114 private static final int GPS_AGPS_DATA_CONN_DONE = 4; 115 private static final int GPS_AGPS_DATA_CONN_FAILED = 5; 116 117 // these need to match GpsLocationFlags enum in gps.h 118 private static final int LOCATION_INVALID = 0; 119 private static final int LOCATION_HAS_LAT_LONG = 1; 120 private static final int LOCATION_HAS_ALTITUDE = 2; 121 private static final int LOCATION_HAS_SPEED = 4; 122 private static final int LOCATION_HAS_BEARING = 8; 123 private static final int LOCATION_HAS_ACCURACY = 16; 124 125// IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h 126 private static final int GPS_DELETE_EPHEMERIS = 0x0001; 127 private static final int GPS_DELETE_ALMANAC = 0x0002; 128 private static final int GPS_DELETE_POSITION = 0x0004; 129 private static final int GPS_DELETE_TIME = 0x0008; 130 private static final int GPS_DELETE_IONO = 0x0010; 131 private static final int GPS_DELETE_UTC = 0x0020; 132 private static final int GPS_DELETE_HEALTH = 0x0040; 133 private static final int GPS_DELETE_SVDIR = 0x0080; 134 private static final int GPS_DELETE_SVSTEER = 0x0100; 135 private static final int GPS_DELETE_SADATA = 0x0200; 136 private static final int GPS_DELETE_RTI = 0x0400; 137 private static final int GPS_DELETE_CELLDB_INFO = 0x8000; 138 private static final int GPS_DELETE_ALL = 0xFFFF; 139 140 // The GPS_CAPABILITY_* flags must match the values in gps.h 141 private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001; 142 private static final int GPS_CAPABILITY_MSB = 0x0000002; 143 private static final int GPS_CAPABILITY_MSA = 0x0000004; 144 private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008; 145 private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010; 146 147 // these need to match AGpsType enum in gps.h 148 private static final int AGPS_TYPE_SUPL = 1; 149 private static final int AGPS_TYPE_C2K = 2; 150 151 // for mAGpsDataConnectionState 152 private static final int AGPS_DATA_CONNECTION_CLOSED = 0; 153 private static final int AGPS_DATA_CONNECTION_OPENING = 1; 154 private static final int AGPS_DATA_CONNECTION_OPEN = 2; 155 156 // Handler messages 157 private static final int CHECK_LOCATION = 1; 158 private static final int ENABLE = 2; 159 private static final int SET_REQUEST = 3; 160 private static final int UPDATE_NETWORK_STATE = 4; 161 private static final int INJECT_NTP_TIME = 5; 162 private static final int DOWNLOAD_XTRA_DATA = 6; 163 private static final int UPDATE_LOCATION = 7; 164 private static final int ADD_LISTENER = 8; 165 private static final int REMOVE_LISTENER = 9; 166 private static final int INJECT_NTP_TIME_FINISHED = 10; 167 private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11; 168 169 // Request setid 170 private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1; 171 private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2; 172 173 // Request ref location 174 private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1; 175 private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2; 176 177 // ref. location info 178 private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1; 179 private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2; 180 private static final int AGPS_REG_LOCATION_TYPE_MAC = 3; 181 182 // set id info 183 private static final int AGPS_SETID_TYPE_NONE = 0; 184 private static final int AGPS_SETID_TYPE_IMSI = 1; 185 private static final int AGPS_SETID_TYPE_MSISDN = 2; 186 187 private static final String PROPERTIES_FILE = "/etc/gps.conf"; 188 189 /** simpler wrapper for ProviderRequest + Worksource */ 190 private static class GpsRequest { 191 public ProviderRequest request; 192 public WorkSource source; 193 public GpsRequest(ProviderRequest request, WorkSource source) { 194 this.request = request; 195 this.source = source; 196 } 197 } 198 199 private Object mLock = new Object(); 200 201 private int mLocationFlags = LOCATION_INVALID; 202 203 // current status 204 private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE; 205 206 // time for last status update 207 private long mStatusUpdateTime = SystemClock.elapsedRealtime(); 208 209 // turn off GPS fix icon if we haven't received a fix in 10 seconds 210 private static final long RECENT_FIX_TIMEOUT = 10 * 1000; 211 212 // stop trying if we do not receive a fix within 60 seconds 213 private static final int NO_FIX_TIMEOUT = 60 * 1000; 214 215 // if the fix interval is below this we leave GPS on, 216 // if above then we cycle the GPS driver. 217 // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane. 218 private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000; 219 220 // how often to request NTP time, in milliseconds 221 // current setting 24 hours 222 private static final long NTP_INTERVAL = 24*60*60*1000; 223 // how long to wait if we have a network error in NTP or XTRA downloading 224 // current setting - 5 minutes 225 private static final long RETRY_INTERVAL = 5*60*1000; 226 227 // true if we are enabled, protected by this 228 private boolean mEnabled; 229 230 // true if we have network connectivity 231 private boolean mNetworkAvailable; 232 233 // states for injecting ntp and downloading xtra data 234 private static final int STATE_PENDING_NETWORK = 0; 235 private static final int STATE_DOWNLOADING = 1; 236 private static final int STATE_IDLE = 2; 237 238 // flags to trigger NTP or XTRA data download when network becomes available 239 // initialized to true so we do NTP and XTRA when the network comes up after booting 240 private int mInjectNtpTimePending = STATE_PENDING_NETWORK; 241 private int mDownloadXtraDataPending = STATE_PENDING_NETWORK; 242 243 // set to true if the GPS engine does not do on-demand NTP time requests 244 private boolean mPeriodicTimeInjection; 245 246 // true if GPS is navigating 247 private boolean mNavigating; 248 249 // true if GPS engine is on 250 private boolean mEngineOn; 251 252 // requested frequency of fixes, in milliseconds 253 private int mFixInterval = 1000; 254 255 // true if we started navigation 256 private boolean mStarted; 257 258 // capabilities of the GPS engine 259 private int mEngineCapabilities; 260 261 // true if XTRA is supported 262 private boolean mSupportsXtra; 263 264 // for calculating time to first fix 265 private long mFixRequestTime = 0; 266 // time to first fix for most recent session 267 private int mTimeToFirstFix = 0; 268 // time we received our last fix 269 private long mLastFixTime; 270 271 private int mPositionMode; 272 273 // properties loaded from PROPERTIES_FILE 274 private Properties mProperties; 275 private String mSuplServerHost; 276 private int mSuplServerPort; 277 private String mC2KServerHost; 278 private int mC2KServerPort; 279 280 private final Context mContext; 281 private final NtpTrustedTime mNtpTime; 282 private final ILocationManager mILocationManager; 283 private Location mLocation = new Location(LocationManager.GPS_PROVIDER); 284 private Bundle mLocationExtras = new Bundle(); 285 private ArrayList<Listener> mListeners = new ArrayList<Listener>(); 286 287 // Handler for processing events 288 private Handler mHandler; 289 290 private String mAGpsApn; 291 private int mAGpsDataConnectionState; 292 private int mAGpsDataConnectionIpAddr; 293 private final ConnectivityManager mConnMgr; 294 private final GpsNetInitiatedHandler mNIHandler; 295 296 // Wakelocks 297 private final static String WAKELOCK_KEY = "GpsLocationProvider"; 298 private final PowerManager.WakeLock mWakeLock; 299 300 // Alarms 301 private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP"; 302 private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT"; 303 private final AlarmManager mAlarmManager; 304 private final PendingIntent mWakeupIntent; 305 private final PendingIntent mTimeoutIntent; 306 307 private final IBatteryStats mBatteryStats; 308 309 // only modified on handler thread 310 private int[] mClientUids = new int[0]; 311 312 private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() { 313 @Override 314 public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException { 315 if (listener == null) { 316 throw new NullPointerException("listener is null in addGpsStatusListener"); 317 } 318 319 synchronized (mListeners) { 320 IBinder binder = listener.asBinder(); 321 int size = mListeners.size(); 322 for (int i = 0; i < size; i++) { 323 Listener test = mListeners.get(i); 324 if (binder.equals(test.mListener.asBinder())) { 325 // listener already added 326 return; 327 } 328 } 329 330 Listener l = new Listener(listener); 331 binder.linkToDeath(l, 0); 332 mListeners.add(l); 333 } 334 } 335 336 @Override 337 public void removeGpsStatusListener(IGpsStatusListener listener) { 338 if (listener == null) { 339 throw new NullPointerException("listener is null in addGpsStatusListener"); 340 } 341 342 synchronized (mListeners) { 343 IBinder binder = listener.asBinder(); 344 Listener l = null; 345 int size = mListeners.size(); 346 for (int i = 0; i < size && l == null; i++) { 347 Listener test = mListeners.get(i); 348 if (binder.equals(test.mListener.asBinder())) { 349 l = test; 350 } 351 } 352 353 if (l != null) { 354 mListeners.remove(l); 355 binder.unlinkToDeath(l, 0); 356 } 357 } 358 } 359 }; 360 361 public IGpsStatusProvider getGpsStatusProvider() { 362 return mGpsStatusProvider; 363 } 364 365 private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() { 366 @Override public void onReceive(Context context, Intent intent) { 367 String action = intent.getAction(); 368 369 if (action.equals(ALARM_WAKEUP)) { 370 if (DEBUG) Log.d(TAG, "ALARM_WAKEUP"); 371 startNavigating(); 372 } else if (action.equals(ALARM_TIMEOUT)) { 373 if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT"); 374 hibernate(); 375 } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) { 376 checkSmsSuplInit(intent); 377 } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) { 378 checkWapSuplInit(intent); 379 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 380 int networkState; 381 if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) { 382 networkState = LocationProvider.TEMPORARILY_UNAVAILABLE; 383 } else { 384 networkState = LocationProvider.AVAILABLE; 385 } 386 387 // retrieve NetworkInfo result for this UID 388 NetworkInfo info = 389 intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO); 390 ConnectivityManager connManager = (ConnectivityManager) 391 mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 392 info = connManager.getNetworkInfo(info.getType()); 393 394 updateNetworkState(networkState, info); 395 } 396 } 397 }; 398 399 private void checkSmsSuplInit(Intent intent) { 400 SmsMessage[] messages = Intents.getMessagesFromIntent(intent); 401 for (int i=0; i <messages.length; i++) { 402 byte[] supl_init = messages[i].getUserData(); 403 native_agps_ni_message(supl_init,supl_init.length); 404 } 405 } 406 407 private void checkWapSuplInit(Intent intent) { 408 byte[] supl_init = (byte[]) intent.getExtra("data"); 409 native_agps_ni_message(supl_init,supl_init.length); 410 } 411 412 public static boolean isSupported() { 413 return native_is_supported(); 414 } 415 416 public GpsLocationProvider(Context context, ILocationManager ilocationManager) { 417 mContext = context; 418 mNtpTime = NtpTrustedTime.getInstance(context); 419 mILocationManager = ilocationManager; 420 mNIHandler = new GpsNetInitiatedHandler(context); 421 422 mLocation.setExtras(mLocationExtras); 423 424 // Create a wake lock 425 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 426 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 427 mWakeLock.setReferenceCounted(true); 428 429 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 430 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0); 431 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0); 432 433 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); 434 435 // Battery statistics service to be notified when GPS turns on or off 436 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); 437 438 mProperties = new Properties(); 439 try { 440 File file = new File(PROPERTIES_FILE); 441 FileInputStream stream = new FileInputStream(file); 442 mProperties.load(stream); 443 stream.close(); 444 445 mSuplServerHost = mProperties.getProperty("SUPL_HOST"); 446 String portString = mProperties.getProperty("SUPL_PORT"); 447 if (mSuplServerHost != null && portString != null) { 448 try { 449 mSuplServerPort = Integer.parseInt(portString); 450 } catch (NumberFormatException e) { 451 Log.e(TAG, "unable to parse SUPL_PORT: " + portString); 452 } 453 } 454 455 mC2KServerHost = mProperties.getProperty("C2K_HOST"); 456 portString = mProperties.getProperty("C2K_PORT"); 457 if (mC2KServerHost != null && portString != null) { 458 try { 459 mC2KServerPort = Integer.parseInt(portString); 460 } catch (NumberFormatException e) { 461 Log.e(TAG, "unable to parse C2K_PORT: " + portString); 462 } 463 } 464 } catch (IOException e) { 465 Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE); 466 } 467 468 // construct handler, listen for events 469 mHandler = new ProviderHandler(); 470 listenForBroadcasts(); 471 472 // also listen for PASSIVE_PROVIDER updates 473 mHandler.post(new Runnable() { 474 @Override 475 public void run() { 476 LocationManager locManager = 477 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 478 locManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 479 0, 0, new NetworkLocationListener(), mHandler.getLooper()); 480 } 481 }); 482 } 483 484 private void listenForBroadcasts() { 485 IntentFilter intentFilter = new IntentFilter(); 486 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION); 487 intentFilter.addDataScheme("sms"); 488 intentFilter.addDataAuthority("localhost","7275"); 489 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler); 490 491 intentFilter = new IntentFilter(); 492 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION); 493 try { 494 intentFilter.addDataType("application/vnd.omaloc-supl-init"); 495 } catch (IntentFilter.MalformedMimeTypeException e) { 496 Log.w(TAG, "Malformed SUPL init mime type"); 497 } 498 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler); 499 500 intentFilter = new IntentFilter(); 501 intentFilter.addAction(ALARM_WAKEUP); 502 intentFilter.addAction(ALARM_TIMEOUT); 503 intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 504 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler); 505 } 506 507 /** 508 * Returns the name of this provider. 509 */ 510 @Override 511 public String getName() { 512 return LocationManager.GPS_PROVIDER; 513 } 514 515 @Override 516 public ProviderProperties getProperties() { 517 return PROPERTIES; 518 } 519 520 public void updateNetworkState(int state, NetworkInfo info) { 521 sendMessage(UPDATE_NETWORK_STATE, state, info); 522 } 523 524 private void handleUpdateNetworkState(int state, NetworkInfo info) { 525 mNetworkAvailable = (state == LocationProvider.AVAILABLE); 526 527 if (DEBUG) { 528 Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable") 529 + " info: " + info); 530 } 531 532 if (info != null) { 533 boolean dataEnabled = Settings.Global.getInt(mContext.getContentResolver(), 534 Settings.Global.MOBILE_DATA, 1) == 1; 535 boolean networkAvailable = info.isAvailable() && dataEnabled; 536 String defaultApn = getSelectedApn(); 537 if (defaultApn == null) { 538 defaultApn = "dummy-apn"; 539 } 540 541 native_update_network_state(info.isConnected(), info.getType(), 542 info.isRoaming(), networkAvailable, 543 info.getExtraInfo(), defaultApn); 544 } 545 546 if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL 547 && mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { 548 String apnName = info.getExtraInfo(); 549 if (mNetworkAvailable) { 550 if (apnName == null) { 551 /* Assign a dummy value in the case of C2K as otherwise we will have a runtime 552 exception in the following call to native_agps_data_conn_open*/ 553 apnName = "dummy-apn"; 554 } 555 mAGpsApn = apnName; 556 if (DEBUG) Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr); 557 if (mAGpsDataConnectionIpAddr != 0xffffffff) { 558 boolean route_result; 559 if (DEBUG) Log.d(TAG, "call requestRouteToHost"); 560 route_result = mConnMgr.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_SUPL, 561 mAGpsDataConnectionIpAddr); 562 if (route_result == false) Log.d(TAG, "call requestRouteToHost failed"); 563 } 564 if (DEBUG) Log.d(TAG, "call native_agps_data_conn_open"); 565 native_agps_data_conn_open(apnName); 566 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 567 } else { 568 if (DEBUG) Log.d(TAG, "call native_agps_data_conn_failed"); 569 mAGpsApn = null; 570 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 571 native_agps_data_conn_failed(); 572 } 573 } 574 575 if (mNetworkAvailable) { 576 if (mInjectNtpTimePending == STATE_PENDING_NETWORK) { 577 sendMessage(INJECT_NTP_TIME, 0, null); 578 } 579 if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) { 580 sendMessage(DOWNLOAD_XTRA_DATA, 0, null); 581 } 582 } 583 } 584 585 private void handleInjectNtpTime() { 586 if (mInjectNtpTimePending == STATE_DOWNLOADING) { 587 // already downloading data 588 return; 589 } 590 if (!mNetworkAvailable) { 591 // try again when network is up 592 mInjectNtpTimePending = STATE_PENDING_NETWORK; 593 return; 594 } 595 mInjectNtpTimePending = STATE_DOWNLOADING; 596 597 // hold wake lock while task runs 598 mWakeLock.acquire(); 599 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { 600 @Override 601 public void run() { 602 long delay; 603 604 // force refresh NTP cache when outdated 605 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) { 606 mNtpTime.forceRefresh(); 607 } 608 609 // only update when NTP time is fresh 610 if (mNtpTime.getCacheAge() < NTP_INTERVAL) { 611 long time = mNtpTime.getCachedNtpTime(); 612 long timeReference = mNtpTime.getCachedNtpTimeReference(); 613 long certainty = mNtpTime.getCacheCertainty(); 614 long now = System.currentTimeMillis(); 615 616 Log.d(TAG, "NTP server returned: " 617 + time + " (" + new Date(time) 618 + ") reference: " + timeReference 619 + " certainty: " + certainty 620 + " system time offset: " + (time - now)); 621 622 native_inject_time(time, timeReference, (int) certainty); 623 delay = NTP_INTERVAL; 624 } else { 625 if (DEBUG) Log.d(TAG, "requestTime failed"); 626 delay = RETRY_INTERVAL; 627 } 628 629 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null); 630 631 if (mPeriodicTimeInjection) { 632 // send delayed message for next NTP injection 633 // since this is delayed and not urgent we do not hold a wake lock here 634 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay); 635 } 636 637 // release wake lock held by task 638 mWakeLock.release(); 639 } 640 }); 641 } 642 643 private void handleDownloadXtraData() { 644 if (mDownloadXtraDataPending == STATE_DOWNLOADING) { 645 // already downloading data 646 return; 647 } 648 if (!mNetworkAvailable) { 649 // try again when network is up 650 mDownloadXtraDataPending = STATE_PENDING_NETWORK; 651 return; 652 } 653 mDownloadXtraDataPending = STATE_DOWNLOADING; 654 655 // hold wake lock while task runs 656 mWakeLock.acquire(); 657 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { 658 @Override 659 public void run() { 660 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties); 661 byte[] data = xtraDownloader.downloadXtraData(); 662 if (data != null) { 663 if (DEBUG) { 664 Log.d(TAG, "calling native_inject_xtra_data"); 665 } 666 native_inject_xtra_data(data, data.length); 667 } 668 669 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null); 670 671 if (data == null) { 672 // try again later 673 // since this is delayed and not urgent we do not hold a wake lock here 674 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA, RETRY_INTERVAL); 675 } 676 677 // release wake lock held by task 678 mWakeLock.release(); 679 } 680 }); 681 } 682 683 private void handleUpdateLocation(Location location) { 684 if (location.hasAccuracy()) { 685 native_inject_location(location.getLatitude(), location.getLongitude(), 686 location.getAccuracy()); 687 } 688 } 689 690 /** 691 * Enables this provider. When enabled, calls to getStatus() 692 * must be handled. Hardware may be started up 693 * when the provider is enabled. 694 */ 695 @Override 696 public void enable() { 697 sendMessage(ENABLE, 1, null); 698 } 699 700 private void handleEnable() { 701 if (DEBUG) Log.d(TAG, "handleEnable"); 702 703 synchronized (mLock) { 704 if (mEnabled) return; 705 mEnabled = true; 706 } 707 708 boolean enabled = native_init(); 709 710 if (enabled) { 711 mSupportsXtra = native_supports_xtra(); 712 if (mSuplServerHost != null) { 713 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); 714 } 715 if (mC2KServerHost != null) { 716 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort); 717 } 718 } else { 719 synchronized (mLock) { 720 mEnabled = false; 721 } 722 Log.w(TAG, "Failed to enable location provider"); 723 } 724 } 725 726 /** 727 * Disables this provider. When disabled, calls to getStatus() 728 * need not be handled. Hardware may be shut 729 * down while the provider is disabled. 730 */ 731 @Override 732 public void disable() { 733 sendMessage(ENABLE, 0, null); 734 } 735 736 private void handleDisable() { 737 if (DEBUG) Log.d(TAG, "handleDisable"); 738 739 synchronized (mLock) { 740 if (!mEnabled) return; 741 mEnabled = false; 742 } 743 744 stopNavigating(); 745 mAlarmManager.cancel(mWakeupIntent); 746 mAlarmManager.cancel(mTimeoutIntent); 747 748 // do this before releasing wakelock 749 native_cleanup(); 750 } 751 752 @Override 753 public boolean isEnabled() { 754 synchronized (mLock) { 755 return mEnabled; 756 } 757 } 758 759 @Override 760 public int getStatus(Bundle extras) { 761 if (extras != null) { 762 extras.putInt("satellites", mSvCount); 763 } 764 return mStatus; 765 } 766 767 private void updateStatus(int status, int svCount) { 768 if (status != mStatus || svCount != mSvCount) { 769 mStatus = status; 770 mSvCount = svCount; 771 mLocationExtras.putInt("satellites", svCount); 772 mStatusUpdateTime = SystemClock.elapsedRealtime(); 773 } 774 } 775 776 @Override 777 public long getStatusUpdateTime() { 778 return mStatusUpdateTime; 779 } 780 781 @Override 782 public void setRequest(ProviderRequest request, WorkSource source) { 783 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source)); 784 } 785 786 private void handleSetRequest(ProviderRequest request, WorkSource source) { 787 if (DEBUG) Log.d(TAG, "setRequest " + request); 788 789 790 791 if (request.reportLocation) { 792 // update client uids 793 int[] uids = new int[source.size()]; 794 for (int i=0; i < source.size(); i++) { 795 uids[i] = source.get(i); 796 } 797 updateClientUids(uids); 798 799 mFixInterval = (int) request.interval; 800 801 // check for overflow 802 if (mFixInterval != request.interval) { 803 Log.w(TAG, "interval overflow: " + request.interval); 804 mFixInterval = Integer.MAX_VALUE; 805 } 806 807 // apply request to GPS engine 808 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) { 809 // change period 810 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 811 mFixInterval, 0, 0)) { 812 Log.e(TAG, "set_position_mode failed in setMinTime()"); 813 } 814 } else if (!mStarted) { 815 // start GPS 816 startNavigating(); 817 } 818 } else { 819 updateClientUids(new int[0]); 820 821 stopNavigating(); 822 mAlarmManager.cancel(mWakeupIntent); 823 mAlarmManager.cancel(mTimeoutIntent); 824 } 825 } 826 827 private final class Listener implements IBinder.DeathRecipient { 828 final IGpsStatusListener mListener; 829 830 Listener(IGpsStatusListener listener) { 831 mListener = listener; 832 } 833 834 @Override 835 public void binderDied() { 836 if (DEBUG) Log.d(TAG, "GPS status listener died"); 837 838 synchronized (mListeners) { 839 mListeners.remove(this); 840 } 841 if (mListener != null) { 842 mListener.asBinder().unlinkToDeath(this, 0); 843 } 844 } 845 } 846 847 private void updateClientUids(int[] uids) { 848 // Find uid's that were not previously tracked 849 for (int uid1 : uids) { 850 boolean newUid = true; 851 for (int uid2 : mClientUids) { 852 if (uid1 == uid2) { 853 newUid = false; 854 break; 855 } 856 } 857 if (newUid) { 858 try { 859 mBatteryStats.noteStartGps(uid1); 860 } catch (RemoteException e) { 861 Log.w(TAG, "RemoteException", e); 862 } 863 } 864 } 865 866 // Find uid'd that were tracked but have now disappeared 867 for (int uid1 : mClientUids) { 868 boolean oldUid = true; 869 for (int uid2 : uids) { 870 if (uid1 == uid2) { 871 oldUid = false; 872 break; 873 } 874 } 875 if (oldUid) { 876 try { 877 mBatteryStats.noteStopGps(uid1); 878 } catch (RemoteException e) { 879 Log.w(TAG, "RemoteException", e); 880 } 881 } 882 } 883 884 // save current uids 885 mClientUids = uids; 886 } 887 888 @Override 889 public boolean sendExtraCommand(String command, Bundle extras) { 890 891 long identity = Binder.clearCallingIdentity(); 892 boolean result = false; 893 894 if ("delete_aiding_data".equals(command)) { 895 result = deleteAidingData(extras); 896 } else if ("force_time_injection".equals(command)) { 897 sendMessage(INJECT_NTP_TIME, 0, null); 898 result = true; 899 } else if ("force_xtra_injection".equals(command)) { 900 if (mSupportsXtra) { 901 xtraDownloadRequest(); 902 result = true; 903 } 904 } else { 905 Log.w(TAG, "sendExtraCommand: unknown command " + command); 906 } 907 908 Binder.restoreCallingIdentity(identity); 909 return result; 910 } 911 912 private boolean deleteAidingData(Bundle extras) { 913 int flags; 914 915 if (extras == null) { 916 flags = GPS_DELETE_ALL; 917 } else { 918 flags = 0; 919 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS; 920 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC; 921 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION; 922 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME; 923 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO; 924 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC; 925 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH; 926 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR; 927 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER; 928 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA; 929 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI; 930 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO; 931 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL; 932 } 933 934 if (flags != 0) { 935 native_delete_aiding_data(flags); 936 return true; 937 } 938 939 return false; 940 } 941 942 private void startNavigating() { 943 if (!mStarted) { 944 if (DEBUG) Log.d(TAG, "startNavigating"); 945 mTimeToFirstFix = 0; 946 mLastFixTime = 0; 947 mStarted = true; 948 mPositionMode = GPS_POSITION_MODE_STANDALONE; 949 950 if (Settings.Global.getInt(mContext.getContentResolver(), 951 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0) { 952 if (hasCapability(GPS_CAPABILITY_MSB)) { 953 mPositionMode = GPS_POSITION_MODE_MS_BASED; 954 } 955 } 956 957 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000); 958 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 959 interval, 0, 0)) { 960 mStarted = false; 961 Log.e(TAG, "set_position_mode failed in startNavigating()"); 962 return; 963 } 964 if (!native_start()) { 965 mStarted = false; 966 Log.e(TAG, "native_start failed in startNavigating()"); 967 return; 968 } 969 970 // reset SV count to zero 971 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); 972 mFixRequestTime = System.currentTimeMillis(); 973 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) { 974 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 975 // and our fix interval is not short 976 if (mFixInterval >= NO_FIX_TIMEOUT) { 977 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 978 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); 979 } 980 } 981 } 982 } 983 984 private void stopNavigating() { 985 if (DEBUG) Log.d(TAG, "stopNavigating"); 986 if (mStarted) { 987 mStarted = false; 988 native_stop(); 989 mTimeToFirstFix = 0; 990 mLastFixTime = 0; 991 mLocationFlags = LOCATION_INVALID; 992 993 // reset SV count to zero 994 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); 995 } 996 } 997 998 private void hibernate() { 999 // stop GPS until our next fix interval arrives 1000 stopNavigating(); 1001 mAlarmManager.cancel(mTimeoutIntent); 1002 mAlarmManager.cancel(mWakeupIntent); 1003 long now = SystemClock.elapsedRealtime(); 1004 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent); 1005 } 1006 1007 private boolean hasCapability(int capability) { 1008 return ((mEngineCapabilities & capability) != 0); 1009 } 1010 1011 /** 1012 * called from native code to update our position. 1013 */ 1014 private void reportLocation(int flags, double latitude, double longitude, double altitude, 1015 float speed, float bearing, float accuracy, long timestamp) { 1016 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude + 1017 " timestamp: " + timestamp); 1018 1019 synchronized (mLocation) { 1020 mLocationFlags = flags; 1021 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1022 mLocation.setLatitude(latitude); 1023 mLocation.setLongitude(longitude); 1024 mLocation.setTime(timestamp); 1025 // It would be nice to push the elapsed real-time timestamp 1026 // further down the stack, but this is still useful 1027 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 1028 } 1029 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { 1030 mLocation.setAltitude(altitude); 1031 } else { 1032 mLocation.removeAltitude(); 1033 } 1034 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { 1035 mLocation.setSpeed(speed); 1036 } else { 1037 mLocation.removeSpeed(); 1038 } 1039 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { 1040 mLocation.setBearing(bearing); 1041 } else { 1042 mLocation.removeBearing(); 1043 } 1044 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { 1045 mLocation.setAccuracy(accuracy); 1046 } else { 1047 mLocation.removeAccuracy(); 1048 } 1049 mLocation.setExtras(mLocationExtras); 1050 1051 try { 1052 mILocationManager.reportLocation(mLocation, false); 1053 } catch (RemoteException e) { 1054 Log.e(TAG, "RemoteException calling reportLocation"); 1055 } 1056 } 1057 1058 mLastFixTime = System.currentTimeMillis(); 1059 // report time to first fix 1060 if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1061 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime); 1062 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix); 1063 1064 // notify status listeners 1065 synchronized (mListeners) { 1066 int size = mListeners.size(); 1067 for (int i = 0; i < size; i++) { 1068 Listener listener = mListeners.get(i); 1069 try { 1070 listener.mListener.onFirstFix(mTimeToFirstFix); 1071 } catch (RemoteException e) { 1072 Log.w(TAG, "RemoteException in stopNavigating"); 1073 mListeners.remove(listener); 1074 // adjust for size of list changing 1075 size--; 1076 } 1077 } 1078 } 1079 } 1080 1081 if (mStarted && mStatus != LocationProvider.AVAILABLE) { 1082 // we want to time out if we do not receive a fix 1083 // within the time out and we are requesting infrequent fixes 1084 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) { 1085 mAlarmManager.cancel(mTimeoutIntent); 1086 } 1087 1088 // send an intent to notify that the GPS is receiving fixes. 1089 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1090 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true); 1091 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1092 updateStatus(LocationProvider.AVAILABLE, mSvCount); 1093 } 1094 1095 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted && 1096 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { 1097 if (DEBUG) Log.d(TAG, "got fix, hibernating"); 1098 hibernate(); 1099 } 1100 } 1101 1102 /** 1103 * called from native code to update our status 1104 */ 1105 private void reportStatus(int status) { 1106 if (DEBUG) Log.v(TAG, "reportStatus status: " + status); 1107 1108 synchronized (mListeners) { 1109 boolean wasNavigating = mNavigating; 1110 1111 switch (status) { 1112 case GPS_STATUS_SESSION_BEGIN: 1113 mNavigating = true; 1114 mEngineOn = true; 1115 break; 1116 case GPS_STATUS_SESSION_END: 1117 mNavigating = false; 1118 break; 1119 case GPS_STATUS_ENGINE_ON: 1120 mEngineOn = true; 1121 break; 1122 case GPS_STATUS_ENGINE_OFF: 1123 mEngineOn = false; 1124 mNavigating = false; 1125 break; 1126 } 1127 1128 if (wasNavigating != mNavigating) { 1129 int size = mListeners.size(); 1130 for (int i = 0; i < size; i++) { 1131 Listener listener = mListeners.get(i); 1132 try { 1133 if (mNavigating) { 1134 listener.mListener.onGpsStarted(); 1135 } else { 1136 listener.mListener.onGpsStopped(); 1137 } 1138 } catch (RemoteException e) { 1139 Log.w(TAG, "RemoteException in reportStatus"); 1140 mListeners.remove(listener); 1141 // adjust for size of list changing 1142 size--; 1143 } 1144 } 1145 1146 // send an intent to notify that the GPS has been enabled or disabled. 1147 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION); 1148 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating); 1149 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1150 } 1151 } 1152 } 1153 1154 /** 1155 * called from native code to update SV info 1156 */ 1157 private void reportSvStatus() { 1158 1159 int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks); 1160 1161 synchronized (mListeners) { 1162 int size = mListeners.size(); 1163 for (int i = 0; i < size; i++) { 1164 Listener listener = mListeners.get(i); 1165 try { 1166 listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs, 1167 mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK], 1168 mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]); 1169 } catch (RemoteException e) { 1170 Log.w(TAG, "RemoteException in reportSvInfo"); 1171 mListeners.remove(listener); 1172 // adjust for size of list changing 1173 size--; 1174 } 1175 } 1176 } 1177 1178 if (VERBOSE) { 1179 Log.v(TAG, "SV count: " + svCount + 1180 " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) + 1181 " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK])); 1182 for (int i = 0; i < svCount; i++) { 1183 Log.v(TAG, "sv: " + mSvs[i] + 1184 " snr: " + mSnrs[i]/10 + 1185 " elev: " + mSvElevations[i] + 1186 " azimuth: " + mSvAzimuths[i] + 1187 ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " E") + 1188 ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " A") + 1189 ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U")); 1190 } 1191 } 1192 1193 // return number of sets used in fix instead of total 1194 updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK])); 1195 1196 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 && 1197 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) { 1198 // send an intent to notify that the GPS is no longer receiving fixes. 1199 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1200 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false); 1201 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1202 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount); 1203 } 1204 } 1205 1206 /** 1207 * called from native code to update AGPS status 1208 */ 1209 private void reportAGpsStatus(int type, int status, int ipaddr) { 1210 switch (status) { 1211 case GPS_REQUEST_AGPS_DATA_CONN: 1212 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN"); 1213 // Set mAGpsDataConnectionState before calling startUsingNetworkFeature 1214 // to avoid a race condition with handleUpdateNetworkState() 1215 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; 1216 int result = mConnMgr.startUsingNetworkFeature( 1217 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); 1218 mAGpsDataConnectionIpAddr = ipaddr; 1219 if (result == PhoneConstants.APN_ALREADY_ACTIVE) { 1220 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE"); 1221 if (mAGpsApn != null) { 1222 Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr); 1223 if (mAGpsDataConnectionIpAddr != 0xffffffff) { 1224 boolean route_result; 1225 if (DEBUG) Log.d(TAG, "call requestRouteToHost"); 1226 route_result = mConnMgr.requestRouteToHost( 1227 ConnectivityManager.TYPE_MOBILE_SUPL, 1228 mAGpsDataConnectionIpAddr); 1229 if (route_result == false) Log.d(TAG, "call requestRouteToHost failed"); 1230 } 1231 native_agps_data_conn_open(mAGpsApn); 1232 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 1233 } else { 1234 Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE"); 1235 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1236 native_agps_data_conn_failed(); 1237 } 1238 } else if (result == PhoneConstants.APN_REQUEST_STARTED) { 1239 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_REQUEST_STARTED"); 1240 // Nothing to do here 1241 } else { 1242 if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed"); 1243 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1244 native_agps_data_conn_failed(); 1245 } 1246 break; 1247 case GPS_RELEASE_AGPS_DATA_CONN: 1248 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN"); 1249 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) { 1250 mConnMgr.stopUsingNetworkFeature( 1251 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); 1252 native_agps_data_conn_closed(); 1253 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1254 } 1255 break; 1256 case GPS_AGPS_DATA_CONNECTED: 1257 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED"); 1258 break; 1259 case GPS_AGPS_DATA_CONN_DONE: 1260 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE"); 1261 break; 1262 case GPS_AGPS_DATA_CONN_FAILED: 1263 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED"); 1264 break; 1265 } 1266 } 1267 1268 /** 1269 * called from native code to report NMEA data received 1270 */ 1271 private void reportNmea(long timestamp) { 1272 synchronized (mListeners) { 1273 int size = mListeners.size(); 1274 if (size > 0) { 1275 // don't bother creating the String if we have no listeners 1276 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length); 1277 String nmea = new String(mNmeaBuffer, 0, length); 1278 1279 for (int i = 0; i < size; i++) { 1280 Listener listener = mListeners.get(i); 1281 try { 1282 listener.mListener.onNmeaReceived(timestamp, nmea); 1283 } catch (RemoteException e) { 1284 Log.w(TAG, "RemoteException in reportNmea"); 1285 mListeners.remove(listener); 1286 // adjust for size of list changing 1287 size--; 1288 } 1289 } 1290 } 1291 } 1292 } 1293 1294 /** 1295 * called from native code to inform us what the GPS engine capabilities are 1296 */ 1297 private void setEngineCapabilities(int capabilities) { 1298 mEngineCapabilities = capabilities; 1299 1300 if (!hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME) && !mPeriodicTimeInjection) { 1301 mPeriodicTimeInjection = true; 1302 requestUtcTime(); 1303 } 1304 } 1305 1306 /** 1307 * called from native code to request XTRA data 1308 */ 1309 private void xtraDownloadRequest() { 1310 if (DEBUG) Log.d(TAG, "xtraDownloadRequest"); 1311 sendMessage(DOWNLOAD_XTRA_DATA, 0, null); 1312 } 1313 1314 //============================================================= 1315 // NI Client support 1316 //============================================================= 1317 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() { 1318 // Sends a response for an NI reqeust to HAL. 1319 @Override 1320 public boolean sendNiResponse(int notificationId, int userResponse) 1321 { 1322 // TODO Add Permission check 1323 1324 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId + 1325 ", response: " + userResponse); 1326 native_send_ni_response(notificationId, userResponse); 1327 return true; 1328 } 1329 }; 1330 1331 public INetInitiatedListener getNetInitiatedListener() { 1332 return mNetInitiatedListener; 1333 } 1334 1335 // Called by JNI function to report an NI request. 1336 public void reportNiNotification( 1337 int notificationId, 1338 int niType, 1339 int notifyFlags, 1340 int timeout, 1341 int defaultResponse, 1342 String requestorId, 1343 String text, 1344 int requestorIdEncoding, 1345 int textEncoding, 1346 String extras // Encoded extra data 1347 ) 1348 { 1349 Log.i(TAG, "reportNiNotification: entered"); 1350 Log.i(TAG, "notificationId: " + notificationId + 1351 ", niType: " + niType + 1352 ", notifyFlags: " + notifyFlags + 1353 ", timeout: " + timeout + 1354 ", defaultResponse: " + defaultResponse); 1355 1356 Log.i(TAG, "requestorId: " + requestorId + 1357 ", text: " + text + 1358 ", requestorIdEncoding: " + requestorIdEncoding + 1359 ", textEncoding: " + textEncoding); 1360 1361 GpsNiNotification notification = new GpsNiNotification(); 1362 1363 notification.notificationId = notificationId; 1364 notification.niType = niType; 1365 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0; 1366 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0; 1367 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0; 1368 notification.timeout = timeout; 1369 notification.defaultResponse = defaultResponse; 1370 notification.requestorId = requestorId; 1371 notification.text = text; 1372 notification.requestorIdEncoding = requestorIdEncoding; 1373 notification.textEncoding = textEncoding; 1374 1375 // Process extras, assuming the format is 1376 // one of more lines of "key = value" 1377 Bundle bundle = new Bundle(); 1378 1379 if (extras == null) extras = ""; 1380 Properties extraProp = new Properties(); 1381 1382 try { 1383 extraProp.load(new StringReader(extras)); 1384 } 1385 catch (IOException e) 1386 { 1387 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras); 1388 } 1389 1390 for (Entry<Object, Object> ent : extraProp.entrySet()) 1391 { 1392 bundle.putString((String) ent.getKey(), (String) ent.getValue()); 1393 } 1394 1395 notification.extras = bundle; 1396 1397 mNIHandler.handleNiNotification(notification); 1398 } 1399 1400 /** 1401 * Called from native code to request set id info. 1402 * We should be careful about receiving null string from the TelephonyManager, 1403 * because sending null String to JNI function would cause a crash. 1404 */ 1405 1406 private void requestSetID(int flags) { 1407 TelephonyManager phone = (TelephonyManager) 1408 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1409 int type = AGPS_SETID_TYPE_NONE; 1410 String data = ""; 1411 1412 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) { 1413 String data_temp = phone.getSubscriberId(); 1414 if (data_temp == null) { 1415 // This means the framework does not have the SIM card ready. 1416 } else { 1417 // This means the framework has the SIM card. 1418 data = data_temp; 1419 type = AGPS_SETID_TYPE_IMSI; 1420 } 1421 } 1422 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) { 1423 String data_temp = phone.getLine1Number(); 1424 if (data_temp == null) { 1425 // This means the framework does not have the SIM card ready. 1426 } else { 1427 // This means the framework has the SIM card. 1428 data = data_temp; 1429 type = AGPS_SETID_TYPE_MSISDN; 1430 } 1431 } 1432 native_agps_set_id(type, data); 1433 } 1434 1435 /** 1436 * Called from native code to request utc time info 1437 */ 1438 1439 private void requestUtcTime() { 1440 sendMessage(INJECT_NTP_TIME, 0, null); 1441 } 1442 1443 /** 1444 * Called from native code to request reference location info 1445 */ 1446 1447 private void requestRefLocation(int flags) { 1448 TelephonyManager phone = (TelephonyManager) 1449 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1450 if (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) { 1451 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation(); 1452 if ((gsm_cell != null) && (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) && 1453 (phone.getNetworkOperator() != null) && 1454 (phone.getNetworkOperator().length() > 3)) { 1455 int type; 1456 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3)); 1457 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3)); 1458 int networkType = phone.getNetworkType(); 1459 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS 1460 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA 1461 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA 1462 || networkType == TelephonyManager.NETWORK_TYPE_HSPA) { 1463 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID; 1464 } else { 1465 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID; 1466 } 1467 native_agps_set_ref_location_cellid(type, mcc, mnc, 1468 gsm_cell.getLac(), gsm_cell.getCid()); 1469 } else { 1470 Log.e(TAG,"Error getting cell location info."); 1471 } 1472 } 1473 else { 1474 Log.e(TAG,"CDMA not supported."); 1475 } 1476 } 1477 1478 private void sendMessage(int message, int arg, Object obj) { 1479 // hold a wake lock until this message is delivered 1480 // note that this assumes the message will not be removed from the queue before 1481 // it is handled (otherwise the wake lock would be leaked). 1482 mWakeLock.acquire(); 1483 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget(); 1484 } 1485 1486 private final class ProviderHandler extends Handler { 1487 public ProviderHandler() { 1488 super(true /*async*/); 1489 } 1490 1491 @Override 1492 public void handleMessage(Message msg) { 1493 int message = msg.what; 1494 switch (message) { 1495 case ENABLE: 1496 if (msg.arg1 == 1) { 1497 handleEnable(); 1498 } else { 1499 handleDisable(); 1500 } 1501 break; 1502 case SET_REQUEST: 1503 GpsRequest gpsRequest = (GpsRequest) msg.obj; 1504 handleSetRequest(gpsRequest.request, gpsRequest.source); 1505 break; 1506 case UPDATE_NETWORK_STATE: 1507 handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj); 1508 break; 1509 case INJECT_NTP_TIME: 1510 handleInjectNtpTime(); 1511 break; 1512 case DOWNLOAD_XTRA_DATA: 1513 if (mSupportsXtra) { 1514 handleDownloadXtraData(); 1515 } 1516 break; 1517 case INJECT_NTP_TIME_FINISHED: 1518 mInjectNtpTimePending = STATE_IDLE; 1519 break; 1520 case DOWNLOAD_XTRA_DATA_FINISHED: 1521 mDownloadXtraDataPending = STATE_IDLE; 1522 break; 1523 case UPDATE_LOCATION: 1524 handleUpdateLocation((Location)msg.obj); 1525 break; 1526 } 1527 if (msg.arg2 == 1) { 1528 // wakelock was taken for this message, release it 1529 mWakeLock.release(); 1530 } 1531 } 1532 }; 1533 1534 private final class NetworkLocationListener implements LocationListener { 1535 @Override 1536 public void onLocationChanged(Location location) { 1537 // this callback happens on mHandler looper 1538 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { 1539 handleUpdateLocation(location); 1540 } 1541 } 1542 @Override 1543 public void onStatusChanged(String provider, int status, Bundle extras) { } 1544 @Override 1545 public void onProviderEnabled(String provider) { } 1546 @Override 1547 public void onProviderDisabled(String provider) { } 1548 } 1549 1550 private String getSelectedApn() { 1551 Uri uri = Uri.parse("content://telephony/carriers/preferapn"); 1552 String apn = null; 1553 1554 Cursor cursor = mContext.getContentResolver().query(uri, new String[] {"apn"}, 1555 null, null, Carriers.DEFAULT_SORT_ORDER); 1556 1557 if (null != cursor) { 1558 try { 1559 if (cursor.moveToFirst()) { 1560 apn = cursor.getString(0); 1561 } 1562 } finally { 1563 cursor.close(); 1564 } 1565 } 1566 return apn; 1567 } 1568 1569 @Override 1570 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1571 StringBuilder s = new StringBuilder(); 1572 s.append(" mFixInterval=").append(mFixInterval).append("\n"); 1573 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" ("); 1574 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED "); 1575 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB "); 1576 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA "); 1577 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT "); 1578 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME "); 1579 s.append(")\n"); 1580 1581 s.append(native_get_internal_state()); 1582 pw.append(s); 1583 } 1584 1585 // for GPS SV statistics 1586 private static final int MAX_SVS = 32; 1587 private static final int EPHEMERIS_MASK = 0; 1588 private static final int ALMANAC_MASK = 1; 1589 private static final int USED_FOR_FIX_MASK = 2; 1590 1591 // preallocated arrays, to avoid memory allocation in reportStatus() 1592 private int mSvs[] = new int[MAX_SVS]; 1593 private float mSnrs[] = new float[MAX_SVS]; 1594 private float mSvElevations[] = new float[MAX_SVS]; 1595 private float mSvAzimuths[] = new float[MAX_SVS]; 1596 private int mSvMasks[] = new int[3]; 1597 private int mSvCount; 1598 // preallocated to avoid memory allocation in reportNmea() 1599 private byte[] mNmeaBuffer = new byte[120]; 1600 1601 static { class_init_native(); } 1602 private static native void class_init_native(); 1603 private static native boolean native_is_supported(); 1604 1605 private native boolean native_init(); 1606 private native void native_cleanup(); 1607 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval, 1608 int preferred_accuracy, int preferred_time); 1609 private native boolean native_start(); 1610 private native boolean native_stop(); 1611 private native void native_delete_aiding_data(int flags); 1612 // returns number of SVs 1613 // mask[0] is ephemeris mask and mask[1] is almanac mask 1614 private native int native_read_sv_status(int[] svs, float[] snrs, 1615 float[] elevations, float[] azimuths, int[] masks); 1616 private native int native_read_nmea(byte[] buffer, int bufferSize); 1617 private native void native_inject_location(double latitude, double longitude, float accuracy); 1618 1619 // XTRA Support 1620 private native void native_inject_time(long time, long timeReference, int uncertainty); 1621 private native boolean native_supports_xtra(); 1622 private native void native_inject_xtra_data(byte[] data, int length); 1623 1624 // DEBUG Support 1625 private native String native_get_internal_state(); 1626 1627 // AGPS Support 1628 private native void native_agps_data_conn_open(String apn); 1629 private native void native_agps_data_conn_closed(); 1630 private native void native_agps_data_conn_failed(); 1631 private native void native_agps_ni_message(byte [] msg, int length); 1632 private native void native_set_agps_server(int type, String hostname, int port); 1633 1634 // Network-initiated (NI) Support 1635 private native void native_send_ni_response(int notificationId, int userResponse); 1636 1637 // AGPS ril suport 1638 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, 1639 int lac, int cid); 1640 private native void native_agps_set_id(int type, String setid); 1641 1642 private native void native_update_network_state(boolean connected, int type, 1643 boolean roaming, boolean available, String extraInfo, String defaultAPN); 1644} 1645