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