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.LocationListener; 33 import android.location.LocationManager; 34 import android.location.LocationProvider; 35 import android.net.ConnectivityManager; 36 import android.net.NetworkInfo; 37 import android.net.Uri; 38 import android.os.AsyncTask; 39 import android.os.Binder; 40 import android.os.Bundle; 41 import android.os.Handler; 42 import android.os.IBinder; 43 import android.os.Message; 44 import android.os.PowerManager; 45 import android.os.RemoteException; 46 import android.os.ServiceManager; 47 import android.os.SystemClock; 48 import android.os.UserHandle; 49 import android.os.WorkSource; 50 import android.provider.Settings; 51 import android.provider.Telephony.Carriers; 52 import android.provider.Telephony.Sms.Intents; 53 import android.telephony.SmsMessage; 54 import android.telephony.TelephonyManager; 55 import android.telephony.gsm.GsmCellLocation; 56 import android.util.Log; 57 import android.util.NtpTrustedTime; 58 import com.android.internal.app.IBatteryStats; 59 import com.android.internal.location.GpsNetInitiatedHandler; 60 import com.android.internal.location.ProviderProperties; 61 import com.android.internal.location.ProviderRequest; 62 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification; 63 import com.android.internal.telephony.Phone; 64 import com.android.internal.telephony.PhoneConstants; 65 66 import java.io.File; 67 import java.io.FileDescriptor; 68 import java.io.FileInputStream; 69 import java.io.IOException; 70 import java.io.PrintWriter; 71 import java.io.StringReader; 72 import java.util.ArrayList; 73 import java.util.Date; 74 import java.util.Map.Entry; 75 import java.util.Properties; 76 77 /** 78 * A GPS implementation of LocationProvider used by LocationManager. 79 * 80 * {@hide} 81 */ 82 public class GpsLocationProvider implements LocationProviderInterface { 83 84 private static final String TAG = "GpsLocationProvider"; 85 86 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 87 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 88 89 private static final ProviderProperties PROPERTIES = new ProviderProperties( 90 true, true, false, false, true, true, true, 91 Criteria.POWER_HIGH, Criteria.ACCURACY_FINE); 92 93 // these need to match GpsPositionMode enum in gps.h 94 private static final int GPS_POSITION_MODE_STANDALONE = 0; 95 private static final int GPS_POSITION_MODE_MS_BASED = 1; 96 private static final int GPS_POSITION_MODE_MS_ASSISTED = 2; 97 98 // these need to match GpsPositionRecurrence enum in gps.h 99 private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0; 100 private static final int GPS_POSITION_RECURRENCE_SINGLE = 1; 101 102 // these need to match GpsStatusValue defines in gps.h 103 private static final int GPS_STATUS_NONE = 0; 104 private static final int GPS_STATUS_SESSION_BEGIN = 1; 105 private static final int GPS_STATUS_SESSION_END = 2; 106 private static final int GPS_STATUS_ENGINE_ON = 3; 107 private static final int GPS_STATUS_ENGINE_OFF = 4; 108 109 // these need to match GpsApgsStatusValue defines in gps.h 110 /** AGPS status event values. */ 111 private static final int GPS_REQUEST_AGPS_DATA_CONN = 1; 112 private static final int GPS_RELEASE_AGPS_DATA_CONN = 2; 113 private static final int GPS_AGPS_DATA_CONNECTED = 3; 114 private static final int GPS_AGPS_DATA_CONN_DONE = 4; 115 private static final int GPS_AGPS_DATA_CONN_FAILED = 5; 116 117 // these need to match GpsLocationFlags enum in gps.h 118 private static final int LOCATION_INVALID = 0; 119 private static final int LOCATION_HAS_LAT_LONG = 1; 120 private static final int LOCATION_HAS_ALTITUDE = 2; 121 private static final int LOCATION_HAS_SPEED = 4; 122 private static final int LOCATION_HAS_BEARING = 8; 123 private static final int LOCATION_HAS_ACCURACY = 16; 124 125 // IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h 126 private static final int GPS_DELETE_EPHEMERIS = 0x0001; 127 private static final int GPS_DELETE_ALMANAC = 0x0002; 128 private static final int GPS_DELETE_POSITION = 0x0004; 129 private static final int GPS_DELETE_TIME = 0x0008; 130 private static final int GPS_DELETE_IONO = 0x0010; 131 private static final int GPS_DELETE_UTC = 0x0020; 132 private static final int GPS_DELETE_HEALTH = 0x0040; 133 private static final int GPS_DELETE_SVDIR = 0x0080; 134 private static final int GPS_DELETE_SVSTEER = 0x0100; 135 private static final int GPS_DELETE_SADATA = 0x0200; 136 private static final int GPS_DELETE_RTI = 0x0400; 137 private static final int GPS_DELETE_CELLDB_INFO = 0x8000; 138 private static final int GPS_DELETE_ALL = 0xFFFF; 139 140 // The GPS_CAPABILITY_* flags must match the values in gps.h 141 private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001; 142 private static final int GPS_CAPABILITY_MSB = 0x0000002; 143 private static final int GPS_CAPABILITY_MSA = 0x0000004; 144 private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008; 145 private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010; 146 147 // these need to match AGpsType enum in gps.h 148 private static final int AGPS_TYPE_SUPL = 1; 149 private static final int AGPS_TYPE_C2K = 2; 150 151 // for mAGpsDataConnectionState 152 private static final int AGPS_DATA_CONNECTION_CLOSED = 0; 153 private static final int AGPS_DATA_CONNECTION_OPENING = 1; 154 private static final int AGPS_DATA_CONNECTION_OPEN = 2; 155 156 // Handler messages 157 private static final int CHECK_LOCATION = 1; 158 private static final int ENABLE = 2; 159 private static final int SET_REQUEST = 3; 160 private static final int UPDATE_NETWORK_STATE = 4; 161 private static final int INJECT_NTP_TIME = 5; 162 private static final int DOWNLOAD_XTRA_DATA = 6; 163 private static final int UPDATE_LOCATION = 7; 164 private static final int ADD_LISTENER = 8; 165 private static final int REMOVE_LISTENER = 9; 166 private static final int INJECT_NTP_TIME_FINISHED = 10; 167 private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11; 168 169 // Request setid 170 private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1; 171 private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2; 172 173 // Request ref location 174 private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1; 175 private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2; 176 177 // ref. location info 178 private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1; 179 private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2; 180 private static final int AGPS_REG_LOCATION_TYPE_MAC = 3; 181 182 // set id info 183 private static final int AGPS_SETID_TYPE_NONE = 0; 184 private static final int AGPS_SETID_TYPE_IMSI = 1; 185 private static final int AGPS_SETID_TYPE_MSISDN = 2; 186 187 private static final String PROPERTIES_FILE = "/etc/gps.conf"; 188 189 /** simpler wrapper for ProviderRequest + Worksource */ 190 private static class GpsRequest { 191 public ProviderRequest request; 192 public WorkSource source; 193 public GpsRequest(ProviderRequest request, WorkSource source) { 194 this.request = request; 195 this.source = source; 196 } 197 } 198 199 private Object mLock = new Object(); 200 201 private int mLocationFlags = LOCATION_INVALID; 202 203 // current status 204 private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE; 205 206 // time for last status update 207 private long mStatusUpdateTime = SystemClock.elapsedRealtime(); 208 209 // turn off GPS fix icon if we haven't received a fix in 10 seconds 210 private static final long RECENT_FIX_TIMEOUT = 10 * 1000; 211 212 // stop trying if we do not receive a fix within 60 seconds 213 private static final int NO_FIX_TIMEOUT = 60 * 1000; 214 215 // if the fix interval is below this we leave GPS on, 216 // if above then we cycle the GPS driver. 217 // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane. 218 private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000; 219 220 // how often to request NTP time, in milliseconds 221 // current setting 24 hours 222 private static final long NTP_INTERVAL = 24*60*60*1000; 223 // how long to wait if we have a network error in NTP or XTRA downloading 224 // current setting - 5 minutes 225 private static final long RETRY_INTERVAL = 5*60*1000; 226 227 // true if we are enabled, protected by this 228 private boolean mEnabled; 229 230 // true if we have network connectivity 231 private boolean mNetworkAvailable; 232 233 // states for injecting ntp and downloading xtra data 234 private static final int STATE_PENDING_NETWORK = 0; 235 private static final int STATE_DOWNLOADING = 1; 236 private static final int STATE_IDLE = 2; 237 238 // flags to trigger NTP or XTRA data download when network becomes available 239 // initialized to true so we do NTP and XTRA when the network comes up after booting 240 private int mInjectNtpTimePending = STATE_PENDING_NETWORK; 241 private int mDownloadXtraDataPending = STATE_PENDING_NETWORK; 242 243 // set to true if the GPS engine does not do on-demand NTP time requests 244 private boolean mPeriodicTimeInjection; 245 246 // true if GPS is navigating 247 private boolean mNavigating; 248 249 // true if GPS engine is on 250 private boolean mEngineOn; 251 252 // requested frequency of fixes, in milliseconds 253 private int mFixInterval = 1000; 254 255 // true if we started navigation 256 private boolean mStarted; 257 258 // capabilities of the GPS engine 259 private int mEngineCapabilities; 260 261 // true if XTRA is supported 262 private boolean mSupportsXtra; 263 264 // for calculating time to first fix 265 private long mFixRequestTime = 0; 266 // time to first fix for most recent session 267 private int mTimeToFirstFix = 0; 268 // time we received our last fix 269 private long mLastFixTime; 270 271 private int mPositionMode; 272 273 // properties loaded from PROPERTIES_FILE 274 private Properties mProperties; 275 private String mSuplServerHost; 276 private int mSuplServerPort; 277 private String mC2KServerHost; 278 private int mC2KServerPort; 279 280 private final Context mContext; 281 private final NtpTrustedTime mNtpTime; 282 private final ILocationManager mILocationManager; 283 private Location mLocation = new Location(LocationManager.GPS_PROVIDER); 284 private Bundle mLocationExtras = new Bundle(); 285 private ArrayList<Listener> mListeners = new ArrayList<Listener>(); 286 287 // Handler for processing events 288 private Handler mHandler; 289 290 private String mAGpsApn; 291 private int mAGpsDataConnectionState; 292 private int mAGpsDataConnectionIpAddr; 293 private final ConnectivityManager mConnMgr; 294 private final GpsNetInitiatedHandler mNIHandler; 295 296 // Wakelocks 297 private final static String WAKELOCK_KEY = "GpsLocationProvider"; 298 private final PowerManager.WakeLock mWakeLock; 299 300 // Alarms 301 private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP"; 302 private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT"; 303 private final AlarmManager mAlarmManager; 304 private final PendingIntent mWakeupIntent; 305 private final PendingIntent mTimeoutIntent; 306 307 private final IBatteryStats mBatteryStats; 308 309 // only modified on handler thread 310 private int[] mClientUids = new int[0]; 311 312 private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() { 313 @Override 314 public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException { 315 if (listener == null) { 316 throw new NullPointerException("listener is null in addGpsStatusListener"); 317 } 318 319 synchronized (mListeners) { 320 IBinder binder = listener.asBinder(); 321 int size = mListeners.size(); 322 for (int i = 0; i < size; i++) { 323 Listener test = mListeners.get(i); 324 if (binder.equals(test.mListener.asBinder())) { 325 // listener already added 326 return; 327 } 328 } 329 330 Listener l = new Listener(listener); 331 binder.linkToDeath(l, 0); 332 mListeners.add(l); 333 } 334 } 335 336 @Override 337 public void removeGpsStatusListener(IGpsStatusListener listener) { 338 if (listener == null) { 339 throw new NullPointerException("listener is null in addGpsStatusListener"); 340 } 341 342 synchronized (mListeners) { 343 IBinder binder = listener.asBinder(); 344 Listener l = null; 345 int size = mListeners.size(); 346 for (int i = 0; i < size && l == null; i++) { 347 Listener test = mListeners.get(i); 348 if (binder.equals(test.mListener.asBinder())) { 349 l = test; 350 } 351 } 352 353 if (l != null) { 354 mListeners.remove(l); 355 binder.unlinkToDeath(l, 0); 356 } 357 } 358 } 359 }; 360 361 public IGpsStatusProvider getGpsStatusProvider() { 362 return mGpsStatusProvider; 363 } 364 365 private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() { 366 @Override public void onReceive(Context context, Intent intent) { 367 String action = intent.getAction(); 368 369 if (action.equals(ALARM_WAKEUP)) { 370 if (DEBUG) Log.d(TAG, "ALARM_WAKEUP"); 371 startNavigating(); 372 } else if (action.equals(ALARM_TIMEOUT)) { 373 if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT"); 374 hibernate(); 375 } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) { 376 checkSmsSuplInit(intent); 377 } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) { 378 checkWapSuplInit(intent); 379 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 380 int networkState; 381 if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) { 382 networkState = LocationProvider.TEMPORARILY_UNAVAILABLE; 383 } else { 384 networkState = LocationProvider.AVAILABLE; 385 } 386 387 // retrieve NetworkInfo result for this UID 388 NetworkInfo info = 389 intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO); 390 ConnectivityManager connManager = (ConnectivityManager) 391 mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 392 info = connManager.getNetworkInfo(info.getType()); 393 394 updateNetworkState(networkState, info); 395 } 396 } 397 }; 398 399 private void checkSmsSuplInit(Intent intent) { 400 SmsMessage[] messages = Intents.getMessagesFromIntent(intent); 401 for (int i=0; i <messages.length; i++) { 402 byte[] supl_init = messages[i].getUserData(); 403 native_agps_ni_message(supl_init,supl_init.length); 404 } 405 } 406 407 private void checkWapSuplInit(Intent intent) { 408 byte[] supl_init = (byte[]) intent.getExtra("data"); 409 native_agps_ni_message(supl_init,supl_init.length); 410 } 411 412 public static boolean isSupported() { 413 return native_is_supported(); 414 } 415 416 public GpsLocationProvider(Context context, ILocationManager ilocationManager) { 417 mContext = context; 418 mNtpTime = NtpTrustedTime.getInstance(context); 419 mILocationManager = ilocationManager; 420 mNIHandler = new GpsNetInitiatedHandler(context); 421 422 mLocation.setExtras(mLocationExtras); 423 424 // Create a wake lock 425 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 426 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 427 mWakeLock.setReferenceCounted(true); 428 429 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 430 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0); 431 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0); 432 433 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); 434 435 // Battery statistics service to be notified when GPS turns on or off 436 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); 437 438 mProperties = new Properties(); 439 try { 440 File file = new File(PROPERTIES_FILE); 441 FileInputStream stream = new FileInputStream(file); 442 mProperties.load(stream); 443 stream.close(); 444 445 mSuplServerHost = mProperties.getProperty("SUPL_HOST"); 446 String portString = mProperties.getProperty("SUPL_PORT"); 447 if (mSuplServerHost != null && portString != null) { 448 try { 449 mSuplServerPort = Integer.parseInt(portString); 450 } catch (NumberFormatException e) { 451 Log.e(TAG, "unable to parse SUPL_PORT: " + portString); 452 } 453 } 454 455 mC2KServerHost = mProperties.getProperty("C2K_HOST"); 456 portString = mProperties.getProperty("C2K_PORT"); 457 if (mC2KServerHost != null && portString != null) { 458 try { 459 mC2KServerPort = Integer.parseInt(portString); 460 } catch (NumberFormatException e) { 461 Log.e(TAG, "unable to parse C2K_PORT: " + portString); 462 } 463 } 464 } catch (IOException e) { 465 Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE); 466 } 467 468 // construct handler, listen for events 469 mHandler = new ProviderHandler(); 470 listenForBroadcasts(); 471 472 // also listen for PASSIVE_PROVIDER updates 473 mHandler.post(new Runnable() { 474 @Override 475 public void run() { 476 LocationManager locManager = 477 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 478 locManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 479 0, 0, new NetworkLocationListener(), mHandler.getLooper()); 480 } 481 }); 482 } 483 484 private void listenForBroadcasts() { 485 IntentFilter intentFilter = new IntentFilter(); 486 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION); 487 intentFilter.addDataScheme("sms"); 488 intentFilter.addDataAuthority("localhost","7275"); 489 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler); 490 491 intentFilter = new IntentFilter(); 492 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION); 493 try { 494 intentFilter.addDataType("application/vnd.omaloc-supl-init"); 495 } catch (IntentFilter.MalformedMimeTypeException e) { 496 Log.w(TAG, "Malformed SUPL init mime type"); 497 } 498 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler); 499 500 intentFilter = new IntentFilter(); 501 intentFilter.addAction(ALARM_WAKEUP); 502 intentFilter.addAction(ALARM_TIMEOUT); 503 intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 504 mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler); 505 } 506 507 /** 508 * Returns the name of this provider. 509 */ 510 @Override 511 public String getName() { 512 return LocationManager.GPS_PROVIDER; 513 } 514 515 @Override 516 public ProviderProperties getProperties() { 517 return PROPERTIES; 518 } 519 520 public void updateNetworkState(int state, NetworkInfo info) { 521 sendMessage(UPDATE_NETWORK_STATE, state, info); 522 } 523 524 private void handleUpdateNetworkState(int state, NetworkInfo info) { 525 mNetworkAvailable = (state == LocationProvider.AVAILABLE); 526 527 if (DEBUG) { 528 Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable") 529 + " info: " + info); 530 } 531 532 if (info != null) { 533 boolean dataEnabled = Settings.Global.getInt(mContext.getContentResolver(), 534 Settings.Global.MOBILE_DATA, 1) == 1; 535 boolean networkAvailable = info.isAvailable() && dataEnabled; 536 String defaultApn = getSelectedApn(); 537 if (defaultApn == null) { 538 defaultApn = "dummy-apn"; 539 } 540 541 native_update_network_state(info.isConnected(), info.getType(), 542 info.isRoaming(), networkAvailable, 543 info.getExtraInfo(), defaultApn); 544 } 545 546 if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL 547 && mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { 548 String apnName = info.getExtraInfo(); 549 if (mNetworkAvailable) { 550 if (apnName == null) { 551 /* Assign a dummy value in the case of C2K as otherwise we will have a runtime 552 exception in the following call to native_agps_data_conn_open*/ 553 apnName = "dummy-apn"; 554 } 555 mAGpsApn = apnName; 556 if (DEBUG) Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr); 557 if (mAGpsDataConnectionIpAddr != 0xffffffff) { 558 boolean route_result; 559 if (DEBUG) Log.d(TAG, "call requestRouteToHost"); 560 route_result = mConnMgr.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_SUPL, 561 mAGpsDataConnectionIpAddr); 562 if (route_result == false) Log.d(TAG, "call requestRouteToHost failed"); 563 } 564 if (DEBUG) Log.d(TAG, "call native_agps_data_conn_open"); 565 native_agps_data_conn_open(apnName); 566 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 567 } else { 568 if (DEBUG) Log.d(TAG, "call native_agps_data_conn_failed"); 569 mAGpsApn = null; 570 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 571 native_agps_data_conn_failed(); 572 } 573 } 574 575 if (mNetworkAvailable) { 576 if (mInjectNtpTimePending == STATE_PENDING_NETWORK) { 577 sendMessage(INJECT_NTP_TIME, 0, null); 578 } 579 if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) { 580 sendMessage(DOWNLOAD_XTRA_DATA, 0, null); 581 } 582 } 583 } 584 585 private void handleInjectNtpTime() { 586 if (mInjectNtpTimePending == STATE_DOWNLOADING) { 587 // already downloading data 588 return; 589 } 590 if (!mNetworkAvailable) { 591 // try again when network is up 592 mInjectNtpTimePending = STATE_PENDING_NETWORK; 593 return; 594 } 595 mInjectNtpTimePending = STATE_DOWNLOADING; 596 597 // hold wake lock while task runs 598 mWakeLock.acquire(); 599 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { 600 @Override 601 public void run() { 602 long delay; 603 604 // force refresh NTP cache when outdated 605 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) { 606 mNtpTime.forceRefresh(); 607 } 608 609 // only update when NTP time is fresh 610 if (mNtpTime.getCacheAge() < NTP_INTERVAL) { 611 long time = mNtpTime.getCachedNtpTime(); 612 long timeReference = mNtpTime.getCachedNtpTimeReference(); 613 long certainty = mNtpTime.getCacheCertainty(); 614 long now = System.currentTimeMillis(); 615 616 Log.d(TAG, "NTP server returned: " 617 + time + " (" + new Date(time) 618 + ") reference: " + timeReference 619 + " certainty: " + certainty 620 + " system time offset: " + (time - now)); 621 622 native_inject_time(time, timeReference, (int) certainty); 623 delay = NTP_INTERVAL; 624 } else { 625 if (DEBUG) Log.d(TAG, "requestTime failed"); 626 delay = RETRY_INTERVAL; 627 } 628 629 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null); 630 631 if (mPeriodicTimeInjection) { 632 // send delayed message for next NTP injection 633 // since this is delayed and not urgent we do not hold a wake lock here 634 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay); 635 } 636 637 // release wake lock held by task 638 mWakeLock.release(); 639 } 640 }); 641 } 642 643 private void handleDownloadXtraData() { 644 if (mDownloadXtraDataPending == STATE_DOWNLOADING) { 645 // already downloading data 646 return; 647 } 648 if (!mNetworkAvailable) { 649 // try again when network is up 650 mDownloadXtraDataPending = STATE_PENDING_NETWORK; 651 return; 652 } 653 mDownloadXtraDataPending = STATE_DOWNLOADING; 654 655 // hold wake lock while task runs 656 mWakeLock.acquire(); 657 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { 658 @Override 659 public void run() { 660 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties); 661 byte[] data = xtraDownloader.downloadXtraData(); 662 if (data != null) { 663 if (DEBUG) { 664 Log.d(TAG, "calling native_inject_xtra_data"); 665 } 666 native_inject_xtra_data(data, data.length); 667 } 668 669 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null); 670 671 if (data == null) { 672 // try again later 673 // since this is delayed and not urgent we do not hold a wake lock here 674 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA, RETRY_INTERVAL); 675 } 676 677 // release wake lock held by task 678 mWakeLock.release(); 679 } 680 }); 681 } 682 683 private void handleUpdateLocation(Location location) { 684 if (location.hasAccuracy()) { 685 native_inject_location(location.getLatitude(), location.getLongitude(), 686 location.getAccuracy()); 687 } 688 } 689 690 /** 691 * Enables this provider. When enabled, calls to getStatus() 692 * must be handled. Hardware may be started up 693 * when the provider is enabled. 694 */ 695 @Override 696 public void enable() { 697 sendMessage(ENABLE, 1, null); 698 } 699 700 private void handleEnable() { 701 if (DEBUG) Log.d(TAG, "handleEnable"); 702 703 synchronized (mLock) { 704 if (mEnabled) return; 705 mEnabled = true; 706 } 707 708 boolean enabled = native_init(); 709 710 if (enabled) { 711 mSupportsXtra = native_supports_xtra(); 712 if (mSuplServerHost != null) { 713 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); 714 } 715 if (mC2KServerHost != null) { 716 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort); 717 } 718 } else { 719 synchronized (mLock) { 720 mEnabled = false; 721 } 722 Log.w(TAG, "Failed to enable location provider"); 723 } 724 } 725 726 /** 727 * Disables this provider. When disabled, calls to getStatus() 728 * need not be handled. Hardware may be shut 729 * down while the provider is disabled. 730 */ 731 @Override 732 public void disable() { 733 sendMessage(ENABLE, 0, null); 734 } 735 736 private void handleDisable() { 737 if (DEBUG) Log.d(TAG, "handleDisable"); 738 739 synchronized (mLock) { 740 if (!mEnabled) return; 741 mEnabled = false; 742 } 743 744 stopNavigating(); 745 mAlarmManager.cancel(mWakeupIntent); 746 mAlarmManager.cancel(mTimeoutIntent); 747 748 // do this before releasing wakelock 749 native_cleanup(); 750 } 751 752 @Override 753 public boolean isEnabled() { 754 synchronized (mLock) { 755 return mEnabled; 756 } 757 } 758 759 @Override 760 public int getStatus(Bundle extras) { 761 if (extras != null) { 762 extras.putInt("satellites", mSvCount); 763 } 764 return mStatus; 765 } 766 767 private void updateStatus(int status, int svCount) { 768 if (status != mStatus || svCount != mSvCount) { 769 mStatus = status; 770 mSvCount = svCount; 771 mLocationExtras.putInt("satellites", svCount); 772 mStatusUpdateTime = SystemClock.elapsedRealtime(); 773 } 774 } 775 776 @Override 777 public long getStatusUpdateTime() { 778 return mStatusUpdateTime; 779 } 780 781 @Override 782 public void setRequest(ProviderRequest request, WorkSource source) { 783 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source)); 784 } 785 786 @Override 787 public void switchUser(int userId) { 788 // nothing to do here 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.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 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 NetworkLocationListener implements LocationListener { 1540 @Override 1541 public void onLocationChanged(Location location) { 1542 // this callback happens on mHandler looper 1543 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { 1544 handleUpdateLocation(location); 1545 } 1546 } 1547 @Override 1548 public void onStatusChanged(String provider, int status, Bundle extras) { } 1549 @Override 1550 public void onProviderEnabled(String provider) { } 1551 @Override 1552 public void onProviderDisabled(String provider) { } 1553 } 1554 1555 private String getSelectedApn() { 1556 Uri uri = Uri.parse("content://telephony/carriers/preferapn"); 1557 String apn = null; 1558 1559 Cursor cursor = mContext.getContentResolver().query(uri, new String[] {"apn"}, 1560 null, null, Carriers.DEFAULT_SORT_ORDER); 1561 1562 if (null != cursor) { 1563 try { 1564 if (cursor.moveToFirst()) { 1565 apn = cursor.getString(0); 1566 } 1567 } finally { 1568 cursor.close(); 1569 } 1570 } 1571 return apn; 1572 } 1573 1574 @Override 1575 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1576 StringBuilder s = new StringBuilder(); 1577 s.append(" mFixInterval=").append(mFixInterval).append("\n"); 1578 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" ("); 1579 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED "); 1580 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB "); 1581 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA "); 1582 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT "); 1583 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME "); 1584 s.append(")\n"); 1585 1586 s.append(native_get_internal_state()); 1587 pw.append(s); 1588 } 1589 1590 // for GPS SV statistics 1591 private static final int MAX_SVS = 32; 1592 private static final int EPHEMERIS_MASK = 0; 1593 private static final int ALMANAC_MASK = 1; 1594 private static final int USED_FOR_FIX_MASK = 2; 1595 1596 // preallocated arrays, to avoid memory allocation in reportStatus() 1597 private int mSvs[] = new int[MAX_SVS]; 1598 private float mSnrs[] = new float[MAX_SVS]; 1599 private float mSvElevations[] = new float[MAX_SVS]; 1600 private float mSvAzimuths[] = new float[MAX_SVS]; 1601 private int mSvMasks[] = new int[3]; 1602 private int mSvCount; 1603 // preallocated to avoid memory allocation in reportNmea() 1604 private byte[] mNmeaBuffer = new byte[120]; 1605 1606 static { class_init_native(); } 1607 private static native void class_init_native(); 1608 private static native boolean native_is_supported(); 1609 1610 private native boolean native_init(); 1611 private native void native_cleanup(); 1612 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval, 1613 int preferred_accuracy, int preferred_time); 1614 private native boolean native_start(); 1615 private native boolean native_stop(); 1616 private native void native_delete_aiding_data(int flags); 1617 // returns number of SVs 1618 // mask[0] is ephemeris mask and mask[1] is almanac mask 1619 private native int native_read_sv_status(int[] svs, float[] snrs, 1620 float[] elevations, float[] azimuths, int[] masks); 1621 private native int native_read_nmea(byte[] buffer, int bufferSize); 1622 private native void native_inject_location(double latitude, double longitude, float accuracy); 1623 1624 // XTRA Support 1625 private native void native_inject_time(long time, long timeReference, int uncertainty); 1626 private native boolean native_supports_xtra(); 1627 private native void native_inject_xtra_data(byte[] data, int length); 1628 1629 // DEBUG Support 1630 private native String native_get_internal_state(); 1631 1632 // AGPS Support 1633 private native void native_agps_data_conn_open(String apn); 1634 private native void native_agps_data_conn_closed(); 1635 private native void native_agps_data_conn_failed(); 1636 private native void native_agps_ni_message(byte [] msg, int length); 1637 private native void native_set_agps_server(int type, String hostname, int port); 1638 1639 // Network-initiated (NI) Support 1640 private native void native_send_ni_response(int notificationId, int userResponse); 1641 1642 // AGPS ril suport 1643 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, 1644 int lac, int cid); 1645 private native void native_agps_set_id(int type, String setid); 1646 1647 private native void native_update_network_state(boolean connected, int type, 1648 boolean roaming, boolean available, String extraInfo, String defaultAPN); 1649 } 1650