auto import from //depot/cupcake/@135843
This commit is contained in:
@@ -1,925 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.location;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.location.Criteria;
|
||||
import android.location.IGpsStatusListener;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationProvider;
|
||||
import android.location.LocationProviderImpl;
|
||||
import android.net.SntpClient;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* A GPS implementation of LocationProvider used by LocationManager.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public class GpsLocationProvider extends LocationProviderImpl {
|
||||
|
||||
private static final String TAG = "GpsLocationProvider";
|
||||
|
||||
/**
|
||||
* Broadcast intent action indicating that the GPS has either been
|
||||
* enabled or disabled. An intent extra provides this state as a boolean,
|
||||
* where {@code true} means enabled.
|
||||
* @see #EXTRA_ENABLED
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public static final String GPS_ENABLED_CHANGE_ACTION =
|
||||
"android.location.GPS_ENABLED_CHANGE";
|
||||
|
||||
/**
|
||||
* Broadcast intent action indicating that the GPS has either started or
|
||||
* stopped receiving GPS fixes. An intent extra provides this state as a
|
||||
* boolean, where {@code true} means that the GPS is actively receiving fixes.
|
||||
* @see #EXTRA_ENABLED
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public static final String GPS_FIX_CHANGE_ACTION =
|
||||
"android.location.GPS_FIX_CHANGE";
|
||||
|
||||
/**
|
||||
* The lookup key for a boolean that indicates whether GPS is enabled or
|
||||
* disabled. {@code true} means GPS is enabled. Retrieve it with
|
||||
* {@link android.content.Intent#getBooleanExtra(String,boolean)}.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public static final String EXTRA_ENABLED = "enabled";
|
||||
|
||||
// these need to match GpsStatusValue defines in gps.h
|
||||
private static final int GPS_STATUS_NONE = 0;
|
||||
private static final int GPS_STATUS_SESSION_BEGIN = 1;
|
||||
private static final int GPS_STATUS_SESSION_END = 2;
|
||||
private static final int GPS_STATUS_ENGINE_ON = 3;
|
||||
private static final int GPS_STATUS_ENGINE_OFF = 4;
|
||||
|
||||
// these need to match GpsLocationFlags enum in gps.h
|
||||
private static final int LOCATION_INVALID = 0;
|
||||
private static final int LOCATION_HAS_LAT_LONG = 1;
|
||||
private static final int LOCATION_HAS_ALTITUDE = 2;
|
||||
private static final int LOCATION_HAS_SPEED = 4;
|
||||
private static final int LOCATION_HAS_BEARING = 8;
|
||||
private static final int LOCATION_HAS_ACCURACY = 16;
|
||||
|
||||
// IMPORTANT - the GPS_DELETE_* symbols here must match constants in GpsLocationProvider.java
|
||||
private static final int GPS_DELETE_EPHEMERIS = 0x0001;
|
||||
private static final int GPS_DELETE_ALMANAC = 0x0002;
|
||||
private static final int GPS_DELETE_POSITION = 0x0004;
|
||||
private static final int GPS_DELETE_TIME = 0x0008;
|
||||
private static final int GPS_DELETE_IONO = 0x0010;
|
||||
private static final int GPS_DELETE_UTC = 0x0020;
|
||||
private static final int GPS_DELETE_HEALTH = 0x0040;
|
||||
private static final int GPS_DELETE_SVDIR = 0x0080;
|
||||
private static final int GPS_DELETE_SVSTEER = 0x0100;
|
||||
private static final int GPS_DELETE_SADATA = 0x0200;
|
||||
private static final int GPS_DELETE_RTI = 0x0400;
|
||||
private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
|
||||
private static final int GPS_DELETE_ALL = 0xFFFF;
|
||||
|
||||
private static final String PROPERTIES_FILE = "/etc/gps.conf";
|
||||
|
||||
private int mLocationFlags = LOCATION_INVALID;
|
||||
|
||||
// current status
|
||||
private int mStatus = TEMPORARILY_UNAVAILABLE;
|
||||
|
||||
// time for last status update
|
||||
private long mStatusUpdateTime = SystemClock.elapsedRealtime();
|
||||
|
||||
// turn off GPS fix icon if we haven't received a fix in 10 seconds
|
||||
private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
|
||||
|
||||
// true if we are enabled
|
||||
private boolean mEnabled;
|
||||
// true if we are enabled for location updates
|
||||
private boolean mLocationTracking;
|
||||
|
||||
// true if we have network connectivity
|
||||
private boolean mNetworkAvailable;
|
||||
|
||||
// true if GPS is navigating
|
||||
private boolean mNavigating;
|
||||
|
||||
// requested frequency of fixes, in seconds
|
||||
private int mFixInterval = 1;
|
||||
|
||||
// true if we started navigation
|
||||
private boolean mStarted;
|
||||
|
||||
// for calculating time to first fix
|
||||
private long mFixRequestTime = 0;
|
||||
// time to first fix for most recent session
|
||||
private int mTTFF = 0;
|
||||
// time we received our last fix
|
||||
private long mLastFixTime;
|
||||
|
||||
// properties loaded from PROPERTIES_FILE
|
||||
private Properties mProperties;
|
||||
private String mNtpServer;
|
||||
|
||||
private Context mContext;
|
||||
private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
|
||||
private Bundle mLocationExtras = new Bundle();
|
||||
private ArrayList<Listener> mListeners = new ArrayList<Listener>();
|
||||
private GpsEventThread mEventThread;
|
||||
private GpsNetworkThread mNetworkThread;
|
||||
private Object mNetworkThreadLock = new Object();
|
||||
|
||||
// how often to request NTP time, in milliseconds
|
||||
// current setting 4 hours
|
||||
private static final long NTP_INTERVAL = 4*60*60*1000;
|
||||
// how long to wait if we have a network error in NTP or XTRA downloading
|
||||
// current setting - 5 minutes
|
||||
private static final long RETRY_INTERVAL = 5*60*1000;
|
||||
|
||||
private ILocationCollector mCollector;
|
||||
|
||||
public static boolean isSupported() {
|
||||
return native_is_supported();
|
||||
}
|
||||
|
||||
public GpsLocationProvider(Context context) {
|
||||
super(LocationManager.GPS_PROVIDER);
|
||||
mContext = context;
|
||||
|
||||
mProperties = new Properties();
|
||||
try {
|
||||
File file = new File(PROPERTIES_FILE);
|
||||
FileInputStream stream = new FileInputStream(file);
|
||||
mProperties.load(stream);
|
||||
stream.close();
|
||||
mNtpServer = mProperties.getProperty("NTP_SERVER", null);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLocationCollector(ILocationCollector collector) {
|
||||
mCollector = collector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to a
|
||||
* data network (e.g., the Internet), false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean requiresNetwork() {
|
||||
// We want updateNetworkState() to get called when the network state changes
|
||||
// for XTRA and NTP time injection support.
|
||||
return (mNtpServer != null || native_supports_xtra());
|
||||
}
|
||||
|
||||
public void updateNetworkState(int state) {
|
||||
mNetworkAvailable = (state == LocationProvider.AVAILABLE);
|
||||
|
||||
if (Config.LOGD) {
|
||||
Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable"));
|
||||
}
|
||||
|
||||
if (mNetworkAvailable && mNetworkThread != null && mEnabled) {
|
||||
// signal the network thread when the network becomes available
|
||||
mNetworkThread.signal();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to a
|
||||
* satellite-based positioning system (e.g., GPS), false
|
||||
* otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean requiresSatellite() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to an appropriate
|
||||
* cellular network (e.g., to make use of cell tower IDs), false
|
||||
* otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean requiresCell() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the use of this provider may result in a
|
||||
* monetary charge to the user, false if use is free. It is up to
|
||||
* each provider to give accurate information.
|
||||
*/
|
||||
@Override
|
||||
public boolean hasMonetaryCost() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide altitude
|
||||
* information, false otherwise. A provider that reports altitude
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsAltitude() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide speed
|
||||
* information, false otherwise. A provider that reports speed
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsSpeed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide bearing
|
||||
* information, false otherwise. A provider that reports bearing
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsBearing() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the power requirement for this provider.
|
||||
*
|
||||
* @return the power requirement for this provider, as one of the
|
||||
* constants Criteria.POWER_REQUIREMENT_*.
|
||||
*/
|
||||
@Override
|
||||
public int getPowerRequirement() {
|
||||
return Criteria.POWER_HIGH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the horizontal accuracy of this provider
|
||||
*
|
||||
* @return the accuracy of location from this provider, as one
|
||||
* of the constants Criteria.ACCURACY_*.
|
||||
*/
|
||||
@Override
|
||||
public int getAccuracy() {
|
||||
return Criteria.ACCURACY_FINE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables this provider. When enabled, calls to getStatus()
|
||||
* and getLocation() must be handled. Hardware may be started up
|
||||
* when the provider is enabled.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void enable() {
|
||||
if (Config.LOGD) Log.d(TAG, "enable");
|
||||
if (mEnabled) return;
|
||||
mEnabled = native_init();
|
||||
|
||||
if (mEnabled) {
|
||||
// run event listener thread while we are enabled
|
||||
mEventThread = new GpsEventThread();
|
||||
mEventThread.start();
|
||||
|
||||
if (requiresNetwork()) {
|
||||
// run network thread for NTP and XTRA support
|
||||
if (mNetworkThread == null) {
|
||||
mNetworkThread = new GpsNetworkThread();
|
||||
mNetworkThread.start();
|
||||
} else {
|
||||
mNetworkThread.signal();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "Failed to enable location provider");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables this provider. When disabled, calls to getStatus()
|
||||
* and getLocation() need not be handled. Hardware may be shut
|
||||
* down while the provider is disabled.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void disable() {
|
||||
if (Config.LOGD) Log.d(TAG, "disable");
|
||||
if (!mEnabled) return;
|
||||
|
||||
mEnabled = false;
|
||||
stopNavigating();
|
||||
native_disable();
|
||||
|
||||
// make sure our event thread exits
|
||||
if (mEventThread != null) {
|
||||
try {
|
||||
mEventThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
Log.w(TAG, "InterruptedException when joining mEventThread");
|
||||
}
|
||||
mEventThread = null;
|
||||
}
|
||||
|
||||
if (mNetworkThread != null) {
|
||||
mNetworkThread.setDone();
|
||||
mNetworkThread = null;
|
||||
}
|
||||
|
||||
native_cleanup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus(Bundle extras) {
|
||||
if (extras != null) {
|
||||
extras.putInt("satellites", mSvCount);
|
||||
}
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
private void updateStatus(int status, int svCount) {
|
||||
if (status != mStatus || svCount != mSvCount) {
|
||||
mStatus = status;
|
||||
mSvCount = svCount;
|
||||
mLocationExtras.putInt("satellites", svCount);
|
||||
mStatusUpdateTime = SystemClock.elapsedRealtime();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStatusUpdateTime() {
|
||||
return mStatusUpdateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getLocation(Location l) {
|
||||
synchronized (mLocation) {
|
||||
// don't report locations without latitude and longitude
|
||||
if ((mLocationFlags & LOCATION_HAS_LAT_LONG) == 0) {
|
||||
return false;
|
||||
}
|
||||
l.set(mLocation);
|
||||
l.setExtras(mLocationExtras);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableLocationTracking(boolean enable) {
|
||||
if (mLocationTracking == enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
mFixRequestTime = System.currentTimeMillis();
|
||||
mTTFF = 0;
|
||||
mLastFixTime = 0;
|
||||
startNavigating();
|
||||
} else {
|
||||
stopNavigating();
|
||||
}
|
||||
mLocationTracking = enable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocationTracking() {
|
||||
return mLocationTracking;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMinTime(long minTime) {
|
||||
super.setMinTime(minTime);
|
||||
if (Config.LOGD) Log.d(TAG, "setMinTime " + minTime);
|
||||
|
||||
if (minTime >= 0) {
|
||||
int interval = (int)(minTime/1000);
|
||||
if (interval < 1) {
|
||||
interval = 1;
|
||||
}
|
||||
mFixInterval = interval;
|
||||
native_set_fix_frequency(mFixInterval);
|
||||
}
|
||||
}
|
||||
|
||||
private final class Listener implements IBinder.DeathRecipient {
|
||||
final IGpsStatusListener mListener;
|
||||
|
||||
int mSensors = 0;
|
||||
|
||||
Listener(IGpsStatusListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
public void binderDied() {
|
||||
if (Config.LOGD) Log.d(TAG, "GPS status listener died");
|
||||
|
||||
synchronized(mListeners) {
|
||||
mListeners.remove(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
|
||||
if (listener == null) throw new NullPointerException("listener is null in addGpsStatusListener");
|
||||
|
||||
synchronized(mListeners) {
|
||||
IBinder binder = listener.asBinder();
|
||||
int size = mListeners.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Listener test = mListeners.get(i);
|
||||
if (binder.equals(test.mListener.asBinder())) {
|
||||
// listener already added
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Listener l = new Listener(listener);
|
||||
binder.linkToDeath(l, 0);
|
||||
mListeners.add(l);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeGpsStatusListener(IGpsStatusListener listener) {
|
||||
if (listener == null) throw new NullPointerException("listener is null in addGpsStatusListener");
|
||||
|
||||
synchronized(mListeners) {
|
||||
IBinder binder = listener.asBinder();
|
||||
Listener l = null;
|
||||
int size = mListeners.size();
|
||||
for (int i = 0; i < size && l == null; i++) {
|
||||
Listener test = mListeners.get(i);
|
||||
if (binder.equals(test.mListener.asBinder())) {
|
||||
l = test;
|
||||
}
|
||||
}
|
||||
|
||||
if (l != null) {
|
||||
mListeners.remove(l);
|
||||
binder.unlinkToDeath(l, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendExtraCommand(String command, Bundle extras) {
|
||||
|
||||
if ("delete_aiding_data".equals(command)) {
|
||||
return deleteAidingData(extras);
|
||||
}
|
||||
|
||||
Log.w(TAG, "sendExtraCommand: unknown command " + command);
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean deleteAidingData(Bundle extras) {
|
||||
int flags;
|
||||
|
||||
if (extras == null) {
|
||||
flags = GPS_DELETE_ALL;
|
||||
} else {
|
||||
flags = 0;
|
||||
if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
|
||||
if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
|
||||
if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
|
||||
if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
|
||||
if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
|
||||
if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
|
||||
if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
|
||||
if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
|
||||
if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
|
||||
if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
|
||||
if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
|
||||
if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
|
||||
if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
|
||||
}
|
||||
|
||||
if (flags != 0) {
|
||||
native_delete_aiding_data(flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void startNavigating() {
|
||||
if (!mStarted) {
|
||||
if (Config.LOGV) Log.v(TAG, "startNavigating");
|
||||
mStarted = true;
|
||||
if (!native_start(false, mFixInterval)) {
|
||||
mStarted = false;
|
||||
Log.e(TAG, "native_start failed in startNavigating()");
|
||||
}
|
||||
|
||||
// reset SV count to zero
|
||||
updateStatus(TEMPORARILY_UNAVAILABLE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void stopNavigating() {
|
||||
if (Config.LOGV) Log.v(TAG, "stopNavigating");
|
||||
if (mStarted) {
|
||||
mStarted = false;
|
||||
native_stop();
|
||||
mTTFF = 0;
|
||||
mLastFixTime = 0;
|
||||
mLocationFlags = LOCATION_INVALID;
|
||||
|
||||
// reset SV count to zero
|
||||
updateStatus(TEMPORARILY_UNAVAILABLE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code to update our position.
|
||||
*/
|
||||
private void reportLocation(int flags, double latitude, double longitude, double altitude,
|
||||
float speed, float bearing, float accuracy, long timestamp) {
|
||||
if (Config.LOGV) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
|
||||
" timestamp: " + timestamp);
|
||||
|
||||
mLastFixTime = System.currentTimeMillis();
|
||||
// report time to first fix
|
||||
if (mTTFF == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
|
||||
mTTFF = (int)(mLastFixTime - mFixRequestTime);
|
||||
if (Config.LOGD) Log.d(TAG, "TTFF: " + mTTFF);
|
||||
|
||||
// notify status listeners
|
||||
synchronized(mListeners) {
|
||||
int size = mListeners.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Listener listener = mListeners.get(i);
|
||||
try {
|
||||
listener.mListener.onFirstFix(mTTFF);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "RemoteException in stopNavigating");
|
||||
mListeners.remove(listener);
|
||||
// adjust for size of list changing
|
||||
size--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mLocation) {
|
||||
mLocationFlags = flags;
|
||||
if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
|
||||
mLocation.setLatitude(latitude);
|
||||
mLocation.setLongitude(longitude);
|
||||
mLocation.setTime(timestamp);
|
||||
}
|
||||
if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
|
||||
mLocation.setAltitude(altitude);
|
||||
} else {
|
||||
mLocation.removeAltitude();
|
||||
}
|
||||
if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
|
||||
mLocation.setSpeed(speed);
|
||||
} else {
|
||||
mLocation.removeSpeed();
|
||||
}
|
||||
if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
|
||||
mLocation.setBearing(bearing);
|
||||
} else {
|
||||
mLocation.removeBearing();
|
||||
}
|
||||
if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
|
||||
mLocation.setAccuracy(accuracy);
|
||||
} else {
|
||||
mLocation.removeAccuracy();
|
||||
}
|
||||
|
||||
// Send to collector
|
||||
if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG
|
||||
&& mCollector != null) {
|
||||
mCollector.updateLocation(mLocation);
|
||||
}
|
||||
}
|
||||
|
||||
if (mStarted && mStatus != AVAILABLE) {
|
||||
// send an intent to notify that the GPS is receiving fixes.
|
||||
Intent intent = new Intent(GPS_FIX_CHANGE_ACTION);
|
||||
intent.putExtra(EXTRA_ENABLED, true);
|
||||
mContext.sendBroadcast(intent);
|
||||
updateStatus(AVAILABLE, mSvCount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code to update our status
|
||||
*/
|
||||
private void reportStatus(int status) {
|
||||
if (Config.LOGV) Log.v(TAG, "reportStatus status: " + status);
|
||||
|
||||
boolean wasNavigating = mNavigating;
|
||||
mNavigating = (status == GPS_STATUS_SESSION_BEGIN);
|
||||
|
||||
if (wasNavigating != mNavigating) {
|
||||
synchronized(mListeners) {
|
||||
int size = mListeners.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Listener listener = mListeners.get(i);
|
||||
try {
|
||||
if (mNavigating) {
|
||||
listener.mListener.onGpsStarted();
|
||||
} else {
|
||||
listener.mListener.onGpsStopped();
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "RemoteException in reportStatus");
|
||||
mListeners.remove(listener);
|
||||
// adjust for size of list changing
|
||||
size--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// send an intent to notify that the GPS has been enabled or disabled.
|
||||
Intent intent = new Intent(GPS_ENABLED_CHANGE_ACTION);
|
||||
intent.putExtra(EXTRA_ENABLED, mNavigating);
|
||||
mContext.sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code to update SV info
|
||||
*/
|
||||
private void reportSvStatus() {
|
||||
|
||||
int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
|
||||
|
||||
synchronized(mListeners) {
|
||||
int size = mListeners.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Listener listener = mListeners.get(i);
|
||||
try {
|
||||
listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,
|
||||
mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK],
|
||||
mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "RemoteException in reportSvInfo");
|
||||
mListeners.remove(listener);
|
||||
// adjust for size of list changing
|
||||
size--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.LOGD) {
|
||||
if (Config.LOGV) Log.v(TAG, "SV count: " + svCount +
|
||||
" ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) +
|
||||
" almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
|
||||
for (int i = 0; i < svCount; i++) {
|
||||
if (Config.LOGV) Log.v(TAG, "sv: " + mSvs[i] +
|
||||
" snr: " + (float)mSnrs[i]/10 +
|
||||
" elev: " + mSvElevations[i] +
|
||||
" azimuth: " + mSvAzimuths[i] +
|
||||
((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " E") +
|
||||
((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " A") +
|
||||
((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U"));
|
||||
}
|
||||
}
|
||||
|
||||
updateStatus(mStatus, svCount);
|
||||
|
||||
if (mNavigating && mStatus == AVAILABLE && mLastFixTime > 0 &&
|
||||
System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
|
||||
// send an intent to notify that the GPS is no longer receiving fixes.
|
||||
Intent intent = new Intent(GPS_FIX_CHANGE_ACTION);
|
||||
intent.putExtra(EXTRA_ENABLED, false);
|
||||
mContext.sendBroadcast(intent);
|
||||
updateStatus(TEMPORARILY_UNAVAILABLE, mSvCount);
|
||||
}
|
||||
}
|
||||
|
||||
private void xtraDownloadRequest() {
|
||||
if (Config.LOGD) Log.d(TAG, "xtraDownloadRequest");
|
||||
if (mNetworkThread != null) {
|
||||
mNetworkThread.xtraDownloadRequest();
|
||||
}
|
||||
}
|
||||
|
||||
private class GpsEventThread extends Thread {
|
||||
|
||||
public GpsEventThread() {
|
||||
super("GpsEventThread");
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (Config.LOGD) Log.d(TAG, "GpsEventThread starting");
|
||||
// thread exits after disable() is called and navigation has stopped
|
||||
while (mEnabled || mNavigating) {
|
||||
// this will wait for an event from the GPS,
|
||||
// which will be reported via reportLocation or reportStatus
|
||||
native_wait_for_event();
|
||||
}
|
||||
if (Config.LOGD) Log.d(TAG, "GpsEventThread exiting");
|
||||
}
|
||||
}
|
||||
|
||||
private class GpsNetworkThread extends Thread {
|
||||
|
||||
private long mNextNtpTime = 0;
|
||||
private long mNextXtraTime = 0;
|
||||
private boolean mXtraDownloadRequested = false;
|
||||
private boolean mDone = false;
|
||||
|
||||
public GpsNetworkThread() {
|
||||
super("GpsNetworkThread");
|
||||
}
|
||||
|
||||
public void run() {
|
||||
synchronized (mNetworkThreadLock) {
|
||||
if (!mDone) {
|
||||
runLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void runLocked() {
|
||||
if (Config.LOGD) Log.d(TAG, "NetworkThread starting");
|
||||
|
||||
SntpClient client = new SntpClient();
|
||||
GpsXtraDownloader xtraDownloader = null;
|
||||
|
||||
if (native_supports_xtra()) {
|
||||
xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
|
||||
}
|
||||
|
||||
// thread exits after disable() is called
|
||||
while (!mDone) {
|
||||
long waitTime = getWaitTime();
|
||||
do {
|
||||
synchronized (this) {
|
||||
try {
|
||||
if (!mNetworkAvailable) {
|
||||
if (Config.LOGD) Log.d(TAG,
|
||||
"NetworkThread wait for network");
|
||||
wait();
|
||||
} else if (waitTime > 0) {
|
||||
if (Config.LOGD) {
|
||||
Log.d(TAG, "NetworkThread wait for " +
|
||||
waitTime + "ms");
|
||||
}
|
||||
wait(waitTime);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
if (Config.LOGD) {
|
||||
Log.d(TAG, "InterruptedException in GpsNetworkThread");
|
||||
}
|
||||
}
|
||||
}
|
||||
waitTime = getWaitTime();
|
||||
} while (!mDone && ((!mXtraDownloadRequested && waitTime > 0)
|
||||
|| !mNetworkAvailable));
|
||||
if (Config.LOGD) Log.d(TAG, "NetworkThread out of wake loop");
|
||||
|
||||
if (!mDone) {
|
||||
if (mNtpServer != null &&
|
||||
mNextNtpTime <= System.currentTimeMillis()) {
|
||||
if (Config.LOGD) {
|
||||
Log.d(TAG, "Requesting time from NTP server " + mNtpServer);
|
||||
}
|
||||
if (client.requestTime(mNtpServer, 10000)) {
|
||||
long time = client.getNtpTime();
|
||||
long timeReference = client.getNtpTimeReference();
|
||||
int certainty = (int)(client.getRoundTripTime()/2);
|
||||
|
||||
if (Config.LOGD) Log.d(TAG, "calling native_inject_time: " +
|
||||
time + " reference: " + timeReference
|
||||
+ " certainty: " + certainty);
|
||||
|
||||
native_inject_time(time, timeReference, certainty);
|
||||
mNextNtpTime = System.currentTimeMillis() + NTP_INTERVAL;
|
||||
} else {
|
||||
if (Config.LOGD) Log.d(TAG, "requestTime failed");
|
||||
mNextNtpTime = System.currentTimeMillis() + RETRY_INTERVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((mXtraDownloadRequested ||
|
||||
(mNextXtraTime > 0 && mNextXtraTime <= System.currentTimeMillis()))
|
||||
&& xtraDownloader != null) {
|
||||
byte[] data = xtraDownloader.downloadXtraData();
|
||||
if (data != null) {
|
||||
if (Config.LOGD) {
|
||||
Log.d(TAG, "calling native_inject_xtra_data");
|
||||
}
|
||||
native_inject_xtra_data(data, data.length);
|
||||
mNextXtraTime = 0;
|
||||
mXtraDownloadRequested = false;
|
||||
} else {
|
||||
mNextXtraTime = System.currentTimeMillis() + RETRY_INTERVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Config.LOGD) Log.d(TAG, "NetworkThread exiting");
|
||||
}
|
||||
|
||||
synchronized void xtraDownloadRequest() {
|
||||
mXtraDownloadRequested = true;
|
||||
notify();
|
||||
}
|
||||
|
||||
synchronized void signal() {
|
||||
notify();
|
||||
}
|
||||
|
||||
synchronized void setDone() {
|
||||
if (Config.LOGD) Log.d(TAG, "stopping NetworkThread");
|
||||
mDone = true;
|
||||
notify();
|
||||
}
|
||||
|
||||
private long getWaitTime() {
|
||||
long now = System.currentTimeMillis();
|
||||
long waitTime = Long.MAX_VALUE;
|
||||
if (mNtpServer != null) {
|
||||
waitTime = mNextNtpTime - now;
|
||||
}
|
||||
if (mNextXtraTime != 0) {
|
||||
long xtraWaitTime = mNextXtraTime - now;
|
||||
if (xtraWaitTime < waitTime) {
|
||||
waitTime = xtraWaitTime;
|
||||
}
|
||||
}
|
||||
if (waitTime < 0) {
|
||||
waitTime = 0;
|
||||
}
|
||||
return waitTime;
|
||||
}
|
||||
}
|
||||
|
||||
// for GPS SV statistics
|
||||
private static final int MAX_SVS = 32;
|
||||
private static final int EPHEMERIS_MASK = 0;
|
||||
private static final int ALMANAC_MASK = 1;
|
||||
private static final int USED_FOR_FIX_MASK = 2;
|
||||
|
||||
// preallocated arrays, to avoid memory allocation in reportStatus()
|
||||
private int mSvs[] = new int[MAX_SVS];
|
||||
private float mSnrs[] = new float[MAX_SVS];
|
||||
private float mSvElevations[] = new float[MAX_SVS];
|
||||
private float mSvAzimuths[] = new float[MAX_SVS];
|
||||
private int mSvMasks[] = new int[3];
|
||||
private int mSvCount;
|
||||
|
||||
static { class_init_native(); }
|
||||
private static native void class_init_native();
|
||||
private static native boolean native_is_supported();
|
||||
|
||||
private native boolean native_init();
|
||||
private native void native_disable();
|
||||
private native void native_cleanup();
|
||||
private native boolean native_start(boolean singleFix, int fixInterval);
|
||||
private native boolean native_stop();
|
||||
private native void native_set_fix_frequency(int fixFrequency);
|
||||
private native void native_delete_aiding_data(int flags);
|
||||
private native void native_wait_for_event();
|
||||
// returns number of SVs
|
||||
// mask[0] is ephemeris mask and mask[1] is almanac mask
|
||||
private native int native_read_sv_status(int[] svs, float[] snrs,
|
||||
float[] elevations, float[] azimuths, int[] masks);
|
||||
|
||||
// XTRA Support
|
||||
private native void native_inject_time(long time, long timeReference, int uncertainty);
|
||||
private native boolean native_supports_xtra();
|
||||
private native void native_inject_xtra_data(byte[] data, int length);
|
||||
}
|
||||
Reference in New Issue
Block a user