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