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