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