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