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