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