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