GpsLocationProvider.java revision 33034b13cae1429d526722374bd39be3f9605ae4
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 } 1082 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { 1083 mLocation.setAltitude(altitude); 1084 } else { 1085 mLocation.removeAltitude(); 1086 } 1087 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { 1088 mLocation.setSpeed(speed); 1089 } else { 1090 mLocation.removeSpeed(); 1091 } 1092 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { 1093 mLocation.setBearing(bearing); 1094 } else { 1095 mLocation.removeBearing(); 1096 } 1097 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { 1098 mLocation.setAccuracy(accuracy); 1099 } else { 1100 mLocation.removeAccuracy(); 1101 } 1102 mLocation.setExtras(mLocationExtras); 1103 1104 try { 1105 mLocationManager.reportLocation(mLocation, false); 1106 } catch (RemoteException e) { 1107 Log.e(TAG, "RemoteException calling reportLocation"); 1108 } 1109 } 1110 1111 mLastFixTime = System.currentTimeMillis(); 1112 // report time to first fix 1113 if (mTTFF == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 1114 mTTFF = (int)(mLastFixTime - mFixRequestTime); 1115 if (DEBUG) Log.d(TAG, "TTFF: " + mTTFF); 1116 1117 // notify status listeners 1118 synchronized(mListeners) { 1119 int size = mListeners.size(); 1120 for (int i = 0; i < size; i++) { 1121 Listener listener = mListeners.get(i); 1122 try { 1123 listener.mListener.onFirstFix(mTTFF); 1124 } catch (RemoteException e) { 1125 Log.w(TAG, "RemoteException in stopNavigating"); 1126 mListeners.remove(listener); 1127 // adjust for size of list changing 1128 size--; 1129 } 1130 } 1131 } 1132 } 1133 1134 if (mSingleShot) { 1135 stopNavigating(); 1136 } 1137 if (mStarted && mStatus != LocationProvider.AVAILABLE) { 1138 // we want to time out if we do not receive a fix 1139 // within the time out and we are requesting infrequent fixes 1140 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) { 1141 mAlarmManager.cancel(mTimeoutIntent); 1142 } 1143 1144 // send an intent to notify that the GPS is receiving fixes. 1145 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1146 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true); 1147 mContext.sendBroadcast(intent); 1148 updateStatus(LocationProvider.AVAILABLE, mSvCount); 1149 } 1150 1151 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted && 1152 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { 1153 if (DEBUG) Log.d(TAG, "got fix, hibernating"); 1154 hibernate(); 1155 } 1156 } 1157 1158 /** 1159 * called from native code to update our status 1160 */ 1161 private void reportStatus(int status) { 1162 if (DEBUG) Log.v(TAG, "reportStatus status: " + status); 1163 1164 synchronized(mListeners) { 1165 boolean wasNavigating = mNavigating; 1166 1167 switch (status) { 1168 case GPS_STATUS_SESSION_BEGIN: 1169 mNavigating = true; 1170 mEngineOn = true; 1171 break; 1172 case GPS_STATUS_SESSION_END: 1173 mNavigating = false; 1174 break; 1175 case GPS_STATUS_ENGINE_ON: 1176 mEngineOn = true; 1177 break; 1178 case GPS_STATUS_ENGINE_OFF: 1179 mEngineOn = false; 1180 mNavigating = false; 1181 break; 1182 } 1183 1184 if (wasNavigating != mNavigating) { 1185 int size = mListeners.size(); 1186 for (int i = 0; i < size; i++) { 1187 Listener listener = mListeners.get(i); 1188 try { 1189 if (mNavigating) { 1190 listener.mListener.onGpsStarted(); 1191 } else { 1192 listener.mListener.onGpsStopped(); 1193 } 1194 } catch (RemoteException e) { 1195 Log.w(TAG, "RemoteException in reportStatus"); 1196 mListeners.remove(listener); 1197 // adjust for size of list changing 1198 size--; 1199 } 1200 } 1201 1202 try { 1203 // update battery stats 1204 for (int i=mClientUids.size() - 1; i >= 0; i--) { 1205 int uid = mClientUids.keyAt(i); 1206 if (mNavigating) { 1207 mBatteryStats.noteStartGps(uid); 1208 } else { 1209 mBatteryStats.noteStopGps(uid); 1210 } 1211 } 1212 } catch (RemoteException e) { 1213 Log.w(TAG, "RemoteException in reportStatus"); 1214 } 1215 1216 // send an intent to notify that the GPS has been enabled or disabled. 1217 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION); 1218 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating); 1219 mContext.sendBroadcast(intent); 1220 } 1221 } 1222 } 1223 1224 /** 1225 * called from native code to update SV info 1226 */ 1227 private void reportSvStatus() { 1228 1229 int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks); 1230 1231 synchronized(mListeners) { 1232 int size = mListeners.size(); 1233 for (int i = 0; i < size; i++) { 1234 Listener listener = mListeners.get(i); 1235 try { 1236 listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs, 1237 mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK], 1238 mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]); 1239 } catch (RemoteException e) { 1240 Log.w(TAG, "RemoteException in reportSvInfo"); 1241 mListeners.remove(listener); 1242 // adjust for size of list changing 1243 size--; 1244 } 1245 } 1246 } 1247 1248 if (VERBOSE) { 1249 Log.v(TAG, "SV count: " + svCount + 1250 " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) + 1251 " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK])); 1252 for (int i = 0; i < svCount; i++) { 1253 Log.v(TAG, "sv: " + mSvs[i] + 1254 " snr: " + (float)mSnrs[i]/10 + 1255 " elev: " + mSvElevations[i] + 1256 " azimuth: " + mSvAzimuths[i] + 1257 ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " E") + 1258 ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " A") + 1259 ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U")); 1260 } 1261 } 1262 1263 // return number of sets used in fix instead of total 1264 updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK])); 1265 1266 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 && 1267 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) { 1268 // send an intent to notify that the GPS is no longer receiving fixes. 1269 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1270 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false); 1271 mContext.sendBroadcast(intent); 1272 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount); 1273 } 1274 } 1275 1276 /** 1277 * called from native code to update AGPS status 1278 */ 1279 private void reportAGpsStatus(int type, int status, int ipaddr) { 1280 switch (status) { 1281 case GPS_REQUEST_AGPS_DATA_CONN: 1282 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN"); 1283 // Set mAGpsDataConnectionState before calling startUsingNetworkFeature 1284 // to avoid a race condition with handleUpdateNetworkState() 1285 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; 1286 int result = mConnMgr.startUsingNetworkFeature( 1287 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); 1288 mAGpsDataConnectionIpAddr = ipaddr; 1289 if (result == PhoneConstants.APN_ALREADY_ACTIVE) { 1290 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE"); 1291 if (mAGpsApn != null) { 1292 Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr); 1293 if (mAGpsDataConnectionIpAddr != 0xffffffff) { 1294 boolean route_result; 1295 if (DEBUG) Log.d(TAG, "call requestRouteToHost"); 1296 route_result = mConnMgr.requestRouteToHost( 1297 ConnectivityManager.TYPE_MOBILE_SUPL, 1298 mAGpsDataConnectionIpAddr); 1299 if (route_result == false) Log.d(TAG, "call requestRouteToHost failed"); 1300 } 1301 native_agps_data_conn_open(mAGpsApn); 1302 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 1303 } else { 1304 Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE"); 1305 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1306 native_agps_data_conn_failed(); 1307 } 1308 } else if (result == PhoneConstants.APN_REQUEST_STARTED) { 1309 if (DEBUG) Log.d(TAG, "PhoneConstants.APN_REQUEST_STARTED"); 1310 // Nothing to do here 1311 } else { 1312 if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed"); 1313 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1314 native_agps_data_conn_failed(); 1315 } 1316 break; 1317 case GPS_RELEASE_AGPS_DATA_CONN: 1318 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN"); 1319 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) { 1320 mConnMgr.stopUsingNetworkFeature( 1321 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); 1322 native_agps_data_conn_closed(); 1323 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 1324 } 1325 break; 1326 case GPS_AGPS_DATA_CONNECTED: 1327 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED"); 1328 break; 1329 case GPS_AGPS_DATA_CONN_DONE: 1330 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE"); 1331 break; 1332 case GPS_AGPS_DATA_CONN_FAILED: 1333 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED"); 1334 break; 1335 } 1336 } 1337 1338 /** 1339 * called from native code to report NMEA data received 1340 */ 1341 private void reportNmea(long timestamp) { 1342 synchronized(mListeners) { 1343 int size = mListeners.size(); 1344 if (size > 0) { 1345 // don't bother creating the String if we have no listeners 1346 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length); 1347 String nmea = new String(mNmeaBuffer, 0, length); 1348 1349 for (int i = 0; i < size; i++) { 1350 Listener listener = mListeners.get(i); 1351 try { 1352 listener.mListener.onNmeaReceived(timestamp, nmea); 1353 } catch (RemoteException e) { 1354 Log.w(TAG, "RemoteException in reportNmea"); 1355 mListeners.remove(listener); 1356 // adjust for size of list changing 1357 size--; 1358 } 1359 } 1360 } 1361 } 1362 } 1363 1364 /** 1365 * called from native code to inform us what the GPS engine capabilities are 1366 */ 1367 private void setEngineCapabilities(int capabilities) { 1368 mEngineCapabilities = capabilities; 1369 1370 if (!hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME) && !mPeriodicTimeInjection) { 1371 mPeriodicTimeInjection = true; 1372 requestUtcTime(); 1373 } 1374 } 1375 1376 /** 1377 * called from native code to request XTRA data 1378 */ 1379 private void xtraDownloadRequest() { 1380 if (DEBUG) Log.d(TAG, "xtraDownloadRequest"); 1381 sendMessage(DOWNLOAD_XTRA_DATA, 0, null); 1382 } 1383 1384 //============================================================= 1385 // NI Client support 1386 //============================================================= 1387 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() { 1388 // Sends a response for an NI reqeust to HAL. 1389 public boolean sendNiResponse(int notificationId, int userResponse) 1390 { 1391 // TODO Add Permission check 1392 1393 StringBuilder extrasBuf = new StringBuilder(); 1394 1395 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId + 1396 ", response: " + userResponse); 1397 native_send_ni_response(notificationId, userResponse); 1398 return true; 1399 } 1400 }; 1401 1402 public INetInitiatedListener getNetInitiatedListener() { 1403 return mNetInitiatedListener; 1404 } 1405 1406 // Called by JNI function to report an NI request. 1407 public void reportNiNotification( 1408 int notificationId, 1409 int niType, 1410 int notifyFlags, 1411 int timeout, 1412 int defaultResponse, 1413 String requestorId, 1414 String text, 1415 int requestorIdEncoding, 1416 int textEncoding, 1417 String extras // Encoded extra data 1418 ) 1419 { 1420 Log.i(TAG, "reportNiNotification: entered"); 1421 Log.i(TAG, "notificationId: " + notificationId + 1422 ", niType: " + niType + 1423 ", notifyFlags: " + notifyFlags + 1424 ", timeout: " + timeout + 1425 ", defaultResponse: " + defaultResponse); 1426 1427 Log.i(TAG, "requestorId: " + requestorId + 1428 ", text: " + text + 1429 ", requestorIdEncoding: " + requestorIdEncoding + 1430 ", textEncoding: " + textEncoding); 1431 1432 GpsNiNotification notification = new GpsNiNotification(); 1433 1434 notification.notificationId = notificationId; 1435 notification.niType = niType; 1436 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0; 1437 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0; 1438 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0; 1439 notification.timeout = timeout; 1440 notification.defaultResponse = defaultResponse; 1441 notification.requestorId = requestorId; 1442 notification.text = text; 1443 notification.requestorIdEncoding = requestorIdEncoding; 1444 notification.textEncoding = textEncoding; 1445 1446 // Process extras, assuming the format is 1447 // one of more lines of "key = value" 1448 Bundle bundle = new Bundle(); 1449 1450 if (extras == null) extras = ""; 1451 Properties extraProp = new Properties(); 1452 1453 try { 1454 extraProp.load(new StringReader(extras)); 1455 } 1456 catch (IOException e) 1457 { 1458 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras); 1459 } 1460 1461 for (Entry<Object, Object> ent : extraProp.entrySet()) 1462 { 1463 bundle.putString((String) ent.getKey(), (String) ent.getValue()); 1464 } 1465 1466 notification.extras = bundle; 1467 1468 mNIHandler.handleNiNotification(notification); 1469 } 1470 1471 /** 1472 * Called from native code to request set id info. 1473 * We should be careful about receiving null string from the TelephonyManager, 1474 * because sending null String to JNI function would cause a crash. 1475 */ 1476 1477 private void requestSetID(int flags) { 1478 TelephonyManager phone = (TelephonyManager) 1479 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1480 int type = AGPS_SETID_TYPE_NONE; 1481 String data = ""; 1482 1483 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) { 1484 String data_temp = phone.getSubscriberId(); 1485 if (data_temp == null) { 1486 // This means the framework does not have the SIM card ready. 1487 } else { 1488 // This means the framework has the SIM card. 1489 data = data_temp; 1490 type = AGPS_SETID_TYPE_IMSI; 1491 } 1492 } 1493 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) { 1494 String data_temp = phone.getLine1Number(); 1495 if (data_temp == null) { 1496 // This means the framework does not have the SIM card ready. 1497 } else { 1498 // This means the framework has the SIM card. 1499 data = data_temp; 1500 type = AGPS_SETID_TYPE_MSISDN; 1501 } 1502 } 1503 native_agps_set_id(type, data); 1504 } 1505 1506 /** 1507 * Called from native code to request utc time info 1508 */ 1509 1510 private void requestUtcTime() { 1511 sendMessage(INJECT_NTP_TIME, 0, null); 1512 } 1513 1514 /** 1515 * Called from native code to request reference location info 1516 */ 1517 1518 private void requestRefLocation(int flags) { 1519 TelephonyManager phone = (TelephonyManager) 1520 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1521 if (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) { 1522 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation(); 1523 if ((gsm_cell != null) && (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) && 1524 (phone.getNetworkOperator() != null) && 1525 (phone.getNetworkOperator().length() > 3)) { 1526 int type; 1527 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3)); 1528 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3)); 1529 int networkType = phone.getNetworkType(); 1530 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS 1531 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA 1532 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA 1533 || networkType == TelephonyManager.NETWORK_TYPE_HSPA) { 1534 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID; 1535 } else { 1536 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID; 1537 } 1538 native_agps_set_ref_location_cellid(type, mcc, mnc, 1539 gsm_cell.getLac(), gsm_cell.getCid()); 1540 } else { 1541 Log.e(TAG,"Error getting cell location info."); 1542 } 1543 } 1544 else { 1545 Log.e(TAG,"CDMA not supported."); 1546 } 1547 } 1548 1549 private void sendMessage(int message, int arg, Object obj) { 1550 // hold a wake lock while messages are pending 1551 synchronized (mWakeLock) { 1552 mPendingMessageBits |= (1 << message); 1553 mWakeLock.acquire(); 1554 mHandler.removeMessages(message); 1555 Message m = Message.obtain(mHandler, message); 1556 m.arg1 = arg; 1557 m.obj = obj; 1558 mHandler.sendMessage(m); 1559 } 1560 } 1561 1562 private final class ProviderHandler extends Handler { 1563 @Override 1564 public void handleMessage(Message msg) { 1565 int message = msg.what; 1566 switch (message) { 1567 case ENABLE: 1568 if (msg.arg1 == 1) { 1569 handleEnable(); 1570 } else { 1571 handleDisable(); 1572 } 1573 break; 1574 case ENABLE_TRACKING: 1575 handleEnableLocationTracking(msg.arg1 == 1); 1576 break; 1577 case REQUEST_SINGLE_SHOT: 1578 handleRequestSingleShot(); 1579 break; 1580 case UPDATE_NETWORK_STATE: 1581 handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj); 1582 break; 1583 case INJECT_NTP_TIME: 1584 handleInjectNtpTime(); 1585 break; 1586 case DOWNLOAD_XTRA_DATA: 1587 if (mSupportsXtra) { 1588 handleDownloadXtraData(); 1589 } 1590 break; 1591 case UPDATE_LOCATION: 1592 handleUpdateLocation((Location)msg.obj); 1593 break; 1594 case ADD_LISTENER: 1595 handleAddListener(msg.arg1); 1596 break; 1597 case REMOVE_LISTENER: 1598 handleRemoveListener(msg.arg1); 1599 break; 1600 } 1601 // release wake lock if no messages are pending 1602 synchronized (mWakeLock) { 1603 mPendingMessageBits &= ~(1 << message); 1604 if (message == ADD_LISTENER || message == REMOVE_LISTENER) { 1605 mPendingListenerMessages--; 1606 } 1607 if (mPendingMessageBits == 0 && mPendingListenerMessages == 0) { 1608 mWakeLock.release(); 1609 } 1610 } 1611 } 1612 }; 1613 1614 private final class GpsLocationProviderThread extends Thread { 1615 1616 public GpsLocationProviderThread() { 1617 super("GpsLocationProvider"); 1618 } 1619 1620 public void run() { 1621 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 1622 initialize(); 1623 Looper.prepare(); 1624 mHandler = new ProviderHandler(); 1625 // signal when we are initialized and ready to go 1626 mInitializedLatch.countDown(); 1627 Looper.loop(); 1628 } 1629 } 1630 1631 private String getSelectedApn() { 1632 Uri uri = Uri.parse("content://telephony/carriers/preferapn"); 1633 String apn = null; 1634 1635 Cursor cursor = mContext.getContentResolver().query(uri, new String[] {"apn"}, 1636 null, null, Carriers.DEFAULT_SORT_ORDER); 1637 1638 if (null != cursor) { 1639 try { 1640 if (cursor.moveToFirst()) { 1641 apn = cursor.getString(0); 1642 } 1643 } finally { 1644 cursor.close(); 1645 } 1646 } 1647 return apn; 1648 } 1649 1650 // for GPS SV statistics 1651 private static final int MAX_SVS = 32; 1652 private static final int EPHEMERIS_MASK = 0; 1653 private static final int ALMANAC_MASK = 1; 1654 private static final int USED_FOR_FIX_MASK = 2; 1655 1656 // preallocated arrays, to avoid memory allocation in reportStatus() 1657 private int mSvs[] = new int[MAX_SVS]; 1658 private float mSnrs[] = new float[MAX_SVS]; 1659 private float mSvElevations[] = new float[MAX_SVS]; 1660 private float mSvAzimuths[] = new float[MAX_SVS]; 1661 private int mSvMasks[] = new int[3]; 1662 private int mSvCount; 1663 // preallocated to avoid memory allocation in reportNmea() 1664 private byte[] mNmeaBuffer = new byte[120]; 1665 1666 static { class_init_native(); } 1667 private static native void class_init_native(); 1668 private static native boolean native_is_supported(); 1669 1670 private native boolean native_init(); 1671 private native void native_cleanup(); 1672 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval, 1673 int preferred_accuracy, int preferred_time); 1674 private native boolean native_start(); 1675 private native boolean native_stop(); 1676 private native void native_delete_aiding_data(int flags); 1677 // returns number of SVs 1678 // mask[0] is ephemeris mask and mask[1] is almanac mask 1679 private native int native_read_sv_status(int[] svs, float[] snrs, 1680 float[] elevations, float[] azimuths, int[] masks); 1681 private native int native_read_nmea(byte[] buffer, int bufferSize); 1682 private native void native_inject_location(double latitude, double longitude, float accuracy); 1683 1684 // XTRA Support 1685 private native void native_inject_time(long time, long timeReference, int uncertainty); 1686 private native boolean native_supports_xtra(); 1687 private native void native_inject_xtra_data(byte[] data, int length); 1688 1689 // DEBUG Support 1690 private native String native_get_internal_state(); 1691 1692 // AGPS Support 1693 private native void native_agps_data_conn_open(String apn); 1694 private native void native_agps_data_conn_closed(); 1695 private native void native_agps_data_conn_failed(); 1696 private native void native_agps_ni_message(byte [] msg, int length); 1697 private native void native_set_agps_server(int type, String hostname, int port); 1698 1699 // Network-initiated (NI) Support 1700 private native void native_send_ni_response(int notificationId, int userResponse); 1701 1702 // AGPS ril suport 1703 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, 1704 int lac, int cid); 1705 private native void native_agps_set_id(int type, String setid); 1706 1707 private native void native_update_network_state(boolean connected, int type, 1708 boolean roaming, boolean available, String extraInfo, String defaultAPN); 1709} 1710