GpsLocationProvider.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.location; 18 19import java.io.File; 20import java.io.FileInputStream; 21import java.io.IOException; 22import java.util.ArrayList; 23import java.util.Properties; 24 25import android.content.Context; 26import android.content.Intent; 27import android.location.Criteria; 28import android.location.IGpsStatusListener; 29import android.location.Location; 30import android.location.LocationManager; 31import android.location.LocationProvider; 32import android.location.LocationProviderImpl; 33import android.net.SntpClient; 34import android.os.Bundle; 35import android.os.IBinder; 36import android.os.RemoteException; 37import android.os.SystemClock; 38import android.util.Config; 39import android.util.Log; 40 41/** 42 * A GPS implementation of LocationProvider used by LocationManager. 43 * 44 * {@hide} 45 */ 46public class GpsLocationProvider extends LocationProviderImpl { 47 48 private static final String TAG = "GpsLocationProvider"; 49 50 /** 51 * Broadcast intent action indicating that the GPS has either been 52 * enabled or disabled. An intent extra provides this state as a boolean, 53 * where {@code true} means enabled. 54 * @see #EXTRA_ENABLED 55 * 56 * {@hide} 57 */ 58 public static final String GPS_ENABLED_CHANGE_ACTION = 59 "android.location.GPS_ENABLED_CHANGE"; 60 61 /** 62 * Broadcast intent action indicating that the GPS has either started or 63 * stopped receiving GPS fixes. An intent extra provides this state as a 64 * boolean, where {@code true} means that the GPS is actively receiving fixes. 65 * @see #EXTRA_ENABLED 66 * 67 * {@hide} 68 */ 69 public static final String GPS_FIX_CHANGE_ACTION = 70 "android.location.GPS_FIX_CHANGE"; 71 72 /** 73 * The lookup key for a boolean that indicates whether GPS is enabled or 74 * disabled. {@code true} means GPS is enabled. Retrieve it with 75 * {@link android.content.Intent#getBooleanExtra(String,boolean)}. 76 * 77 * {@hide} 78 */ 79 public static final String EXTRA_ENABLED = "enabled"; 80 81 // these need to match GpsStatusValue defines in gps.h 82 private static final int GPS_STATUS_NONE = 0; 83 private static final int GPS_STATUS_SESSION_BEGIN = 1; 84 private static final int GPS_STATUS_SESSION_END = 2; 85 private static final int GPS_STATUS_ENGINE_ON = 3; 86 private static final int GPS_STATUS_ENGINE_OFF = 4; 87 88 // these need to match GpsLocationFlags enum in gps.h 89 private static final int LOCATION_INVALID = 0; 90 private static final int LOCATION_HAS_LAT_LONG = 1; 91 private static final int LOCATION_HAS_ALTITUDE = 2; 92 private static final int LOCATION_HAS_SPEED = 4; 93 private static final int LOCATION_HAS_BEARING = 8; 94 private static final int LOCATION_HAS_ACCURACY = 16; 95 96// IMPORTANT - the GPS_DELETE_* symbols here must match constants in GpsLocationProvider.java 97 private static final int GPS_DELETE_EPHEMERIS = 0x0001; 98 private static final int GPS_DELETE_ALMANAC = 0x0002; 99 private static final int GPS_DELETE_POSITION = 0x0004; 100 private static final int GPS_DELETE_TIME = 0x0008; 101 private static final int GPS_DELETE_IONO = 0x0010; 102 private static final int GPS_DELETE_UTC = 0x0020; 103 private static final int GPS_DELETE_HEALTH = 0x0040; 104 private static final int GPS_DELETE_SVDIR = 0x0080; 105 private static final int GPS_DELETE_SVSTEER = 0x0100; 106 private static final int GPS_DELETE_SADATA = 0x0200; 107 private static final int GPS_DELETE_RTI = 0x0400; 108 private static final int GPS_DELETE_CELLDB_INFO = 0x8000; 109 private static final int GPS_DELETE_ALL = 0xFFFF; 110 111 private static final String PROPERTIES_FILE = "/etc/gps.conf"; 112 113 private int mLocationFlags = LOCATION_INVALID; 114 115 // current status 116 private int mStatus = TEMPORARILY_UNAVAILABLE; 117 118 // time for last status update 119 private long mStatusUpdateTime = SystemClock.elapsedRealtime(); 120 121 // turn off GPS fix icon if we haven't received a fix in 10 seconds 122 private static final long RECENT_FIX_TIMEOUT = 10 * 1000; 123 124 // true if we are enabled 125 private boolean mEnabled; 126 // true if we are enabled for location updates 127 private boolean mLocationTracking; 128 129 // true if we have network connectivity 130 private boolean mNetworkAvailable; 131 132 // true if GPS is navigating 133 private boolean mNavigating; 134 135 // requested frequency of fixes, in seconds 136 private int mFixInterval = 1; 137 138 // true if we started navigation 139 private boolean mStarted; 140 141 // for calculating time to first fix 142 private long mFixRequestTime = 0; 143 // time to first fix for most recent session 144 private int mTTFF = 0; 145 // time we received our last fix 146 private long mLastFixTime; 147 148 // properties loaded from PROPERTIES_FILE 149 private Properties mProperties; 150 151 private Context mContext; 152 private Location mLocation = new Location(LocationManager.GPS_PROVIDER); 153 private Bundle mLocationExtras = new Bundle(); 154 private ArrayList<Listener> mListeners = new ArrayList<Listener>(); 155 private GpsEventThread mEventThread; 156 private GpsNetworkThread mNetworkThread; 157 158 // how often to request NTP time, in milliseconds 159 // current setting 4 hours 160 private static final long NTP_INTERVAL = 4*60*60*1000; 161 // how long to wait if we have a network error in NTP or XTRA downloading 162 // current setting - 5 minutes 163 private static final long RETRY_INTERVAL = 5*60*1000; 164 165 private LocationCollector mCollector; 166 167 public static boolean isSupported() { 168 return native_is_supported(); 169 } 170 171 public GpsLocationProvider(Context context, LocationCollector collector) { 172 super(LocationManager.GPS_PROVIDER); 173 mContext = context; 174 mCollector = collector; 175 176 mProperties = new Properties(); 177 try { 178 File file = new File(PROPERTIES_FILE); 179 FileInputStream stream = new FileInputStream(file); 180 mProperties.load(stream); 181 stream.close(); 182 } catch (IOException e) { 183 Log.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE, e); 184 } 185 } 186 187 /** 188 * Returns true if the provider requires access to a 189 * data network (e.g., the Internet), false otherwise. 190 */ 191 @Override 192 public boolean requiresNetwork() { 193 // We want updateNetworkState() to get called when the network state changes 194 // for XTRA and NTP time injection support. 195 return true; 196 } 197 198 public void updateNetworkState(int state) { 199 mNetworkAvailable = (state == LocationProvider.AVAILABLE); 200 201 if (Config.LOGD) { 202 Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable")); 203 } 204 205 if (mNetworkAvailable && mNetworkThread != null && mEnabled) { 206 // signal the network thread when the network becomes available 207 mNetworkThread.signal(); 208 } 209 } 210 211 /** 212 * Returns true if the provider requires access to a 213 * satellite-based positioning system (e.g., GPS), false 214 * otherwise. 215 */ 216 @Override 217 public boolean requiresSatellite() { 218 return true; 219 } 220 221 /** 222 * Returns true if the provider requires access to an appropriate 223 * cellular network (e.g., to make use of cell tower IDs), false 224 * otherwise. 225 */ 226 @Override 227 public boolean requiresCell() { 228 return false; 229 } 230 231 /** 232 * Returns true if the use of this provider may result in a 233 * monetary charge to the user, false if use is free. It is up to 234 * each provider to give accurate information. 235 */ 236 @Override 237 public boolean hasMonetaryCost() { 238 return false; 239 } 240 241 /** 242 * Returns true if the provider is able to provide altitude 243 * information, false otherwise. A provider that reports altitude 244 * under most circumstances but may occassionally not report it 245 * should return true. 246 */ 247 @Override 248 public boolean supportsAltitude() { 249 return true; 250 } 251 252 /** 253 * Returns true if the provider is able to provide speed 254 * information, false otherwise. A provider that reports speed 255 * under most circumstances but may occassionally not report it 256 * should return true. 257 */ 258 @Override 259 public boolean supportsSpeed() { 260 return true; 261 } 262 263 /** 264 * Returns true if the provider is able to provide bearing 265 * information, false otherwise. A provider that reports bearing 266 * under most circumstances but may occassionally not report it 267 * should return true. 268 */ 269 @Override 270 public boolean supportsBearing() { 271 return true; 272 } 273 274 /** 275 * Returns the power requirement for this provider. 276 * 277 * @return the power requirement for this provider, as one of the 278 * constants Criteria.POWER_REQUIREMENT_*. 279 */ 280 @Override 281 public int getPowerRequirement() { 282 return Criteria.POWER_HIGH; 283 } 284 285 /** 286 * Returns the horizontal accuracy of this provider 287 * 288 * @return the accuracy of location from this provider, as one 289 * of the constants Criteria.ACCURACY_*. 290 */ 291 @Override 292 public int getAccuracy() { 293 return Criteria.ACCURACY_FINE; 294 } 295 296 /** 297 * Enables this provider. When enabled, calls to getStatus() 298 * and getLocation() must be handled. Hardware may be started up 299 * when the provider is enabled. 300 */ 301 @Override 302 public void enable() { 303 if (Config.LOGD) Log.d(TAG, "enable"); 304 mEnabled = native_init(); 305 306 if (mEnabled) { 307 // run event listener thread while we are enabled 308 mEventThread = new GpsEventThread(); 309 mEventThread.start(); 310 311 // run network thread for NTP and XTRA support 312 if (mNetworkThread == null) { 313 mNetworkThread = new GpsNetworkThread(); 314 mNetworkThread.start(); 315 } else { 316 mNetworkThread.signal(); 317 } 318 } else { 319 Log.w(TAG, "Failed to enable location provider"); 320 } 321 } 322 323 /** 324 * Disables this provider. When disabled, calls to getStatus() 325 * and getLocation() need not be handled. Hardware may be shut 326 * down while the provider is disabled. 327 */ 328 @Override 329 public void disable() { 330 if (Config.LOGD) Log.d(TAG, "disable"); 331 mEnabled = false; 332 stopNavigating(); 333 native_disable(); 334 335 // make sure our event thread exits 336 if (mEventThread != null) { 337 try { 338 mEventThread.join(); 339 } catch (InterruptedException e) { 340 Log.w(TAG, "InterruptedException when joining mEventThread"); 341 } 342 mEventThread = null; 343 } 344 345 native_cleanup(); 346 } 347 348 @Override 349 public boolean isEnabled() { 350 return mEnabled; 351 } 352 353 @Override 354 public int getStatus(Bundle extras) { 355 if (extras != null) { 356 extras.putInt("satellites", mSvCount); 357 } 358 return mStatus; 359 } 360 361 private void updateStatus(int status, int svCount) { 362 if (status != mStatus || svCount != mSvCount) { 363 mStatus = status; 364 mSvCount = svCount; 365 mLocationExtras.putInt("satellites", svCount); 366 mStatusUpdateTime = SystemClock.elapsedRealtime(); 367 } 368 } 369 370 @Override 371 public long getStatusUpdateTime() { 372 return mStatusUpdateTime; 373 } 374 375 @Override 376 public boolean getLocation(Location l) { 377 synchronized (mLocation) { 378 // don't report locations without latitude and longitude 379 if ((mLocationFlags & LOCATION_HAS_LAT_LONG) == 0) { 380 return false; 381 } 382 l.set(mLocation); 383 l.setExtras(mLocationExtras); 384 return true; 385 } 386 } 387 388 @Override 389 public void enableLocationTracking(boolean enable) { 390 if (mLocationTracking == enable) { 391 return; 392 } 393 394 if (enable) { 395 mFixRequestTime = System.currentTimeMillis(); 396 mTTFF = 0; 397 mLastFixTime = 0; 398 startNavigating(); 399 } else { 400 stopNavigating(); 401 } 402 mLocationTracking = enable; 403 } 404 405 @Override 406 public boolean isLocationTracking() { 407 return mLocationTracking; 408 } 409 410 @Override 411 public void setMinTime(long minTime) { 412 super.setMinTime(minTime); 413 if (Config.LOGD) Log.d(TAG, "setMinTime " + minTime); 414 415 if (minTime >= 0) { 416 int interval = (int)(minTime/1000); 417 if (interval < 1) { 418 interval = 1; 419 } 420 mFixInterval = interval; 421 native_set_fix_frequency(mFixInterval); 422 } 423 } 424 425 private final class Listener implements IBinder.DeathRecipient { 426 final IGpsStatusListener mListener; 427 428 int mSensors = 0; 429 430 Listener(IGpsStatusListener listener) { 431 mListener = listener; 432 } 433 434 public void binderDied() { 435 if (Config.LOGD) Log.d(TAG, "GPS status listener died"); 436 437 synchronized(mListeners) { 438 mListeners.remove(this); 439 } 440 } 441 } 442 443 public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException { 444 if (listener == null) throw new NullPointerException("listener is null in addGpsStatusListener"); 445 446 synchronized(mListeners) { 447 IBinder binder = listener.asBinder(); 448 int size = mListeners.size(); 449 for (int i = 0; i < size; i++) { 450 Listener test = mListeners.get(i); 451 if (binder.equals(test.mListener.asBinder())) { 452 // listener already added 453 return; 454 } 455 } 456 457 Listener l = new Listener(listener); 458 binder.linkToDeath(l, 0); 459 mListeners.add(l); 460 } 461 } 462 463 public void removeGpsStatusListener(IGpsStatusListener listener) { 464 if (listener == null) throw new NullPointerException("listener is null in addGpsStatusListener"); 465 466 synchronized(mListeners) { 467 IBinder binder = listener.asBinder(); 468 Listener l = null; 469 int size = mListeners.size(); 470 for (int i = 0; i < size && l == null; i++) { 471 Listener test = mListeners.get(i); 472 if (binder.equals(test.mListener.asBinder())) { 473 // listener already added 474 return; 475 } 476 } 477 478 if (l != null) { 479 mListeners.remove(l); 480 binder.unlinkToDeath(l, 0); 481 } 482 } 483 } 484 485 @Override 486 public boolean sendExtraCommand(String command, Bundle extras) { 487 488 if ("delete_aiding_data".equals(command)) { 489 return deleteAidingData(extras); 490 } 491 492 Log.w(TAG, "sendExtraCommand: unknown command " + command); 493 return false; 494 } 495 496 private boolean deleteAidingData(Bundle extras) { 497 int flags; 498 499 if (extras == null) { 500 flags = GPS_DELETE_ALL; 501 } else { 502 flags = 0; 503 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS; 504 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC; 505 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION; 506 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME; 507 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO; 508 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC; 509 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH; 510 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR; 511 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER; 512 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA; 513 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI; 514 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO; 515 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL; 516 } 517 518 if (flags != 0) { 519 native_delete_aiding_data(flags); 520 return true; 521 } 522 523 return false; 524 } 525 526 public void startNavigating() { 527 if (!mStarted) { 528 if (Config.LOGV) Log.v(TAG, "startNavigating"); 529 mStarted = true; 530 if (!native_start(false, mFixInterval)) { 531 mStarted = false; 532 Log.e(TAG, "native_start failed in startNavigating()"); 533 } 534 535 // reset SV count to zero 536 updateStatus(TEMPORARILY_UNAVAILABLE, 0); 537 } 538 } 539 540 public void stopNavigating() { 541 if (Config.LOGV) Log.v(TAG, "stopNavigating"); 542 if (mStarted) { 543 mStarted = false; 544 native_stop(); 545 mTTFF = 0; 546 mLastFixTime = 0; 547 mLocationFlags = LOCATION_INVALID; 548 549 // reset SV count to zero 550 updateStatus(TEMPORARILY_UNAVAILABLE, 0); 551 } 552 } 553 554 /** 555 * called from native code to update our position. 556 */ 557 private void reportLocation(int flags, double latitude, double longitude, double altitude, 558 float speed, float bearing, float accuracy, long timestamp) { 559 if (Config.LOGV) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude + 560 " timestamp: " + timestamp); 561 562 mLastFixTime = System.currentTimeMillis(); 563 // report time to first fix 564 if (mTTFF == 0) { 565 mTTFF = (int)(mLastFixTime - mFixRequestTime); 566 if (Config.LOGD) Log.d(TAG, "TTFF: " + mTTFF); 567 568 // notify status listeners 569 synchronized(mListeners) { 570 int size = mListeners.size(); 571 for (int i = 0; i < size; i++) { 572 Listener listener = mListeners.get(i); 573 try { 574 listener.mListener.onFirstFix(mTTFF); 575 } catch (RemoteException e) { 576 Log.w(TAG, "RemoteException in stopNavigating"); 577 mListeners.remove(listener); 578 // adjust for size of list changing 579 size--; 580 } 581 } 582 } 583 } 584 585 synchronized (mLocation) { 586 mLocationFlags = flags; 587 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 588 mLocation.setLatitude(latitude); 589 mLocation.setLongitude(longitude); 590 mLocation.setTime(timestamp); 591 } 592 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { 593 mLocation.setAltitude(altitude); 594 } else { 595 mLocation.removeAltitude(); 596 } 597 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { 598 mLocation.setSpeed(speed); 599 } else { 600 mLocation.removeSpeed(); 601 } 602 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { 603 mLocation.setBearing(bearing); 604 } else { 605 mLocation.removeBearing(); 606 } 607 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { 608 mLocation.setAccuracy(accuracy); 609 } else { 610 mLocation.removeAccuracy(); 611 } 612 613 // Send to collector 614 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { 615 mCollector.updateLocation(mLocation); 616 } 617 } 618 619 if (mStarted && mStatus != AVAILABLE) { 620 // send an intent to notify that the GPS is receiving fixes. 621 Intent intent = new Intent(GPS_FIX_CHANGE_ACTION); 622 intent.putExtra(EXTRA_ENABLED, true); 623 mContext.sendBroadcast(intent); 624 updateStatus(AVAILABLE, mSvCount); 625 } 626 } 627 628 /** 629 * called from native code to update our status 630 */ 631 private void reportStatus(int status) { 632 if (Config.LOGV) Log.v(TAG, "reportStatus status: " + status); 633 634 boolean wasNavigating = mNavigating; 635 mNavigating = (status == GPS_STATUS_SESSION_BEGIN || status == GPS_STATUS_ENGINE_ON); 636 637 if (wasNavigating != mNavigating) { 638 synchronized(mListeners) { 639 int size = mListeners.size(); 640 for (int i = 0; i < size; i++) { 641 Listener listener = mListeners.get(i); 642 try { 643 if (mNavigating) { 644 listener.mListener.onGpsStarted(); 645 } else { 646 listener.mListener.onGpsStopped(); 647 } 648 } catch (RemoteException e) { 649 Log.w(TAG, "RemoteException in reportStatus"); 650 mListeners.remove(listener); 651 // adjust for size of list changing 652 size--; 653 } 654 } 655 } 656 657 // send an intent to notify that the GPS has been enabled or disabled. 658 Intent intent = new Intent(GPS_ENABLED_CHANGE_ACTION); 659 intent.putExtra(EXTRA_ENABLED, mNavigating); 660 mContext.sendBroadcast(intent); 661 } 662 } 663 664 /** 665 * called from native code to update SV info 666 */ 667 private void reportSvStatus() { 668 669 int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks); 670 671 synchronized(mListeners) { 672 int size = mListeners.size(); 673 for (int i = 0; i < size; i++) { 674 Listener listener = mListeners.get(i); 675 try { 676 listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs, 677 mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK], 678 mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]); 679 } catch (RemoteException e) { 680 Log.w(TAG, "RemoteException in reportSvInfo"); 681 mListeners.remove(listener); 682 // adjust for size of list changing 683 size--; 684 } 685 } 686 } 687 688 if (Config.LOGD) { 689 if (Config.LOGV) Log.v(TAG, "SV count: " + svCount + 690 " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) + 691 " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK])); 692 for (int i = 0; i < svCount; i++) { 693 if (Config.LOGV) Log.v(TAG, "sv: " + mSvs[i] + 694 " snr: " + (float)mSnrs[i]/10 + 695 " elev: " + mSvElevations[i] + 696 " azimuth: " + mSvAzimuths[i] + 697 ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " E") + 698 ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " A") + 699 ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U")); 700 } 701 } 702 703 updateStatus(mStatus, svCount); 704 705 if (mNavigating && mStatus == AVAILABLE && mLastFixTime > 0 && 706 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) { 707 // send an intent to notify that the GPS is no longer receiving fixes. 708 Intent intent = new Intent(GPS_FIX_CHANGE_ACTION); 709 intent.putExtra(EXTRA_ENABLED, false); 710 mContext.sendBroadcast(intent); 711 updateStatus(TEMPORARILY_UNAVAILABLE, mSvCount); 712 } 713 } 714 715 private void xtraDownloadRequest() { 716 if (Config.LOGD) Log.d(TAG, "xtraDownloadRequest"); 717 if (mNetworkThread != null) { 718 mNetworkThread.xtraDownloadRequest(); 719 } 720 } 721 722 private class GpsEventThread extends Thread { 723 724 public GpsEventThread() { 725 super("GpsEventThread"); 726 } 727 728 public void run() { 729 if (Config.LOGD) Log.d(TAG, "GpsEventThread starting"); 730 // thread exits after disable() is called and navigation has stopped 731 while (mEnabled || mNavigating) { 732 // this will wait for an event from the GPS, 733 // which will be reported via reportLocation or reportStatus 734 native_wait_for_event(); 735 } 736 if (Config.LOGD) Log.d(TAG, "GpsEventThread exiting"); 737 } 738 } 739 740 private class GpsNetworkThread extends Thread { 741 742 private long mNextNtpTime = 0; 743 private long mNextXtraTime = 0; 744 private boolean mXtraDownloadRequested = false; 745 746 public GpsNetworkThread() { 747 super("GpsNetworkThread"); 748 } 749 750 public void run() { 751 if (Config.LOGD) Log.d(TAG, "NetworkThread starting"); 752 753 SntpClient client = new SntpClient(); 754 GpsXtraDownloader xtraDownloader = null; 755 756 if (native_supports_xtra()) { 757 xtraDownloader = new GpsXtraDownloader(mContext, mProperties); 758 } 759 760 // thread exits after disable() is called 761 while (mEnabled) { 762 long waitTime = getWaitTime(); 763 do { 764 synchronized (this) { 765 try { 766 if (!mNetworkAvailable) { 767 if (Config.LOGD) Log.d(TAG, "NetworkThread wait for network"); 768 wait(); 769 } else if (waitTime > 0) { 770 if (Config.LOGD) Log.d(TAG, "NetworkThread wait for " + waitTime + "ms"); 771 wait(waitTime); 772 } 773 } catch (InterruptedException e) { 774 if (Config.LOGD) Log.d(TAG, "InterruptedException in GpsNetworkThread"); 775 } 776 } 777 waitTime = getWaitTime(); 778 } while (mEnabled && ((!mXtraDownloadRequested && waitTime > 0) || !mNetworkAvailable)); 779 if (Config.LOGD) Log.d(TAG, "NetworkThread out of wake loop"); 780 781 if (mEnabled) { 782 if (mNextNtpTime <= System.currentTimeMillis()) { 783 String ntpServer = mProperties.getProperty("NTP_SERVER", "pool.ntp.org"); 784 if (Config.LOGD) Log.d(TAG, "Requesting time from NTP server " + ntpServer); 785 if (client.requestTime(ntpServer, 10000)) { 786 long time = client.getNtpTime(); 787 long timeReference = client.getNtpTimeReference(); 788 int certainty = (int)(client.getRoundTripTime()/2); 789 790 if (Config.LOGD) Log.d(TAG, "calling native_inject_time: " + 791 time + " reference: " + timeReference 792 + " certainty: " + certainty); 793 794 native_inject_time(time, timeReference, certainty); 795 mNextNtpTime = System.currentTimeMillis() + NTP_INTERVAL; 796 } else { 797 if (Config.LOGD) Log.d(TAG, "requestTime failed"); 798 mNextNtpTime = System.currentTimeMillis() + RETRY_INTERVAL; 799 } 800 } 801 802 if ((mXtraDownloadRequested || 803 (mNextXtraTime > 0 && mNextXtraTime <= System.currentTimeMillis())) && 804 xtraDownloader != null) { 805 byte[] data = xtraDownloader.downloadXtraData(); 806 if (data != null) { 807 if (Config.LOGD) Log.d(TAG, "calling native_inject_xtra_data"); 808 native_inject_xtra_data(data, data.length); 809 mNextXtraTime = 0; 810 mXtraDownloadRequested = false; 811 } else { 812 mNextXtraTime = System.currentTimeMillis() + RETRY_INTERVAL; 813 } 814 } 815 } 816 } 817 if (Config.LOGD) Log.d(TAG, "NetworkThread exiting"); 818 } 819 820 synchronized void xtraDownloadRequest() { 821 mXtraDownloadRequested = true; 822 notify(); 823 } 824 825 synchronized void signal() { 826 notify(); 827 } 828 829 private long getWaitTime() { 830 long now = System.currentTimeMillis(); 831 long waitTime = mNextNtpTime - now; 832 if (mNextXtraTime != 0) { 833 long xtraWaitTime = mNextXtraTime - now; 834 if (xtraWaitTime < waitTime) { 835 waitTime = xtraWaitTime; 836 } 837 } 838 if (waitTime < 0) { 839 waitTime = 0; 840 } 841 return waitTime; 842 } 843 } 844 845 // for GPS SV statistics 846 private static final int MAX_SVS = 32; 847 private static final int EPHEMERIS_MASK = 0; 848 private static final int ALMANAC_MASK = 1; 849 private static final int USED_FOR_FIX_MASK = 2; 850 851 // preallocated arrays, to avoid memory allocation in reportStatus() 852 private int mSvs[] = new int[MAX_SVS]; 853 private float mSnrs[] = new float[MAX_SVS]; 854 private float mSvElevations[] = new float[MAX_SVS]; 855 private float mSvAzimuths[] = new float[MAX_SVS]; 856 private int mSvMasks[] = new int[3]; 857 private int mSvCount; 858 859 static { class_init_native(); } 860 private static native void class_init_native(); 861 private static native boolean native_is_supported(); 862 863 private native boolean native_init(); 864 private native void native_disable(); 865 private native void native_cleanup(); 866 private native boolean native_start(boolean singleFix, int fixInterval); 867 private native boolean native_stop(); 868 private native void native_set_fix_frequency(int fixFrequency); 869 private native void native_delete_aiding_data(int flags); 870 private native void native_wait_for_event(); 871 // returns number of SVs 872 // mask[0] is ephemeris mask and mask[1] is almanac mask 873 private native int native_read_sv_status(int[] svs, float[] snrs, 874 float[] elevations, float[] azimuths, int[] masks); 875 876 private native void native_inject_time(long time, long timeReference, int uncertainty); 877 private native boolean native_supports_xtra(); 878 private native void native_inject_xtra_data(byte[] data, int length); 879} 880