Update location framework to accept raw data from GPS HAL.

Change-Id: Ib4feca004b53fa89dcece4299974ab08913455a0
This commit is contained in:
destradaa
2014-06-23 18:19:03 -07:00
parent 34257d8544
commit ea8a8a6076
15 changed files with 2834 additions and 211 deletions

View File

@@ -288,6 +288,7 @@ LOCAL_SRC_FILES += \
location/java/android/location/IFusedProvider.aidl \
location/java/android/location/IGeocodeProvider.aidl \
location/java/android/location/IGeofenceProvider.aidl \
location/java/android/location/IGpsMeasurementsListener.aidl \
location/java/android/location/IGpsStatusListener.aidl \
location/java/android/location/IGpsStatusProvider.aidl \
location/java/android/location/ILocationListener.aidl \

View File

@@ -0,0 +1,382 @@
/*
* Copyright (C) 2014 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 android.location;
import android.os.Parcel;
import android.os.Parcelable;
/**
* A class containing a GPS clock timestamp.
* It represents a measurement of the GPS receiver's clock.
*
* @hide
*/
public class GpsClock implements Parcelable {
// mandatory parameters
private long mTimeInNs;
// optional parameters
private boolean mHasLeapSecond;
private short mLeapSecond;
private boolean mHasTimeUncertaintyInNs;
private double mTimeUncertaintyInNs;
private boolean mHasBiasInNs;
private double mBiasInNs;
private boolean mHasBiasUncertaintyInNs;
private double mBiasUncertaintyInNs;
private boolean mHasDriftInNsPerSec;
private double mDriftInNsPerSec;
private boolean mHasDriftUncertaintyInNsPerSec;
private double mDriftUncertaintyInNsPerSec;
GpsClock() {
reset();
}
/**
* Sets all contents to the values stored in the provided object.
*/
public void set(GpsClock clock) {
mTimeInNs = clock.mTimeInNs;
mHasLeapSecond = clock.mHasLeapSecond;
mLeapSecond = clock.mLeapSecond;
mHasTimeUncertaintyInNs = clock.mHasTimeUncertaintyInNs;
mTimeUncertaintyInNs = clock.mTimeUncertaintyInNs;
mHasBiasInNs = clock.mHasBiasInNs;
mBiasInNs = clock.mBiasInNs;
mHasBiasUncertaintyInNs = clock.mHasBiasUncertaintyInNs;
mBiasUncertaintyInNs = clock.mBiasUncertaintyInNs;
mHasDriftInNsPerSec = clock.mHasDriftInNsPerSec;
mDriftInNsPerSec = clock.mDriftInNsPerSec;
mHasDriftUncertaintyInNsPerSec = clock.mHasDriftUncertaintyInNsPerSec;
mDriftUncertaintyInNsPerSec = clock.mDriftUncertaintyInNsPerSec;
}
/**
* Resets all the contents to its original state.
*/
public void reset() {
mTimeInNs = Long.MIN_VALUE;
resetLeapSecond();
resetTimeUncertaintyInNs();
resetBiasInNs();
resetBiasUncertaintyInNs();
resetDriftInNsPerSec();
resetDriftUncertaintyInNsPerSec();
}
/**
* Returns true if {@link #getLeapSecond()} is available, false otherwise.
*/
public boolean hasLeapSecond() {
return mHasLeapSecond;
}
/**
* Gets the leap second associated with the clock's time.
*
* The value is only available if {@link #hasLeapSecond()} is true.
*/
public short getLeapSecond() {
return mLeapSecond;
}
/**
* Sets the leap second associated with the clock's time.
*/
public void setLeapSecond(short leapSecond) {
mHasLeapSecond = true;
mLeapSecond = leapSecond;
}
/**
* Resets the leap second associated with the clock's time.
*/
public void resetLeapSecond() {
mHasLeapSecond = false;
mLeapSecond = Short.MIN_VALUE;
}
/**
* Gets the GPS clock Time in nanoseconds; it represents the uncorrected receiver's GPS time
* since 0000Z, January 6, 1980; this is, including {@link #getBiasInNs()}.
* The reported time includes {@link #getTimeUncertaintyInNs()}.
*/
public long getTimeInNs() {
return mTimeInNs;
}
/**
* Sets the GPS clock Time in nanoseconds.
*/
public void setTimeInNs(long timeInNs) {
mTimeInNs = timeInNs;
}
/**
* Returns true if {@link #getTimeUncertaintyInNs()} is available, false otherwise.
*/
public boolean hasTimeUncertaintyInNs() {
return mHasTimeUncertaintyInNs;
}
/**
* Gets the clock's time Uncertainty (1-Sigma) in nanoseconds.
*
* The value is only available if {@link #hasTimeUncertaintyInNs()} is true.
*/
public double getTimeUncertaintyInNs() {
return mTimeUncertaintyInNs;
}
/**
* Sets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
*/
public void setTimeUncertaintyInNs(double timeUncertaintyInNs) {
mHasTimeUncertaintyInNs = true;
mTimeUncertaintyInNs = timeUncertaintyInNs;
}
/**
* Resets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
*/
public void resetTimeUncertaintyInNs() {
mHasTimeUncertaintyInNs = false;
mTimeUncertaintyInNs = Double.NaN;
}
/**
* Returns true if {@link #getBiasInNs()} is available, false otherwise.
*/
public boolean hasBiasInNs() {
return mHasBiasInNs;
}
/**
* Gets the clock's Bias in nanoseconds.
* The sign of the value (if available), is defined by the following equation:
* true time = time - bias.
* The reported bias includes {@link #getBiasUncertaintyInNs()}.
*
* The value is only available if {@link #hasBiasInNs()} is true.
*/
public Double getBiasInNs() {
return mBiasInNs;
}
/**
* Sets the clock's Bias in nanoseconds.
*/
public void setBiasInNs(double biasInNs) {
mHasBiasInNs = true;
mBiasInNs = biasInNs;
}
/**
* Resets the clock's Bias in nanoseconds.
*/
public void resetBiasInNs() {
mHasBiasInNs = false;
mBiasInNs = Double.NaN;
}
/**
* Returns true if {@link #getBiasUncertaintyInNs()} is available, false otherwise.
*/
public boolean hasBiasUncertaintyInNs() {
return mHasBiasUncertaintyInNs;
}
/**
* Gets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
*
* The value is only available if {@link #hasBiasUncertaintyInNs()} is true.
*/
public double getBiasUncertaintyInNs() {
return mBiasUncertaintyInNs;
}
/**
* Sets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
*/
public void setBiasUncertaintyInNs(double biasUncertaintyInNs) {
mHasBiasUncertaintyInNs = true;
mBiasUncertaintyInNs = biasUncertaintyInNs;
}
/**
* Resets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
*/
public void resetBiasUncertaintyInNs() {
mHasBiasUncertaintyInNs = false;
mBiasUncertaintyInNs = Double.NaN;
}
/**
* Returns true if {@link #getDriftInNsPerSec()} is available, false otherwise.
*/
public boolean hasDriftInNsPerSec() {
return mHasDriftInNsPerSec;
}
/**
* Gets the clock's Drift in nanoseconds per second.
* A positive value indicates that the frequency is higher than the nominal frequency.
* The reported drift includes {@link #getDriftUncertaintyInNsPerSec()}.
*
* The value is only available if {@link #hasDriftInNsPerSec()} is true.
*/
public double getDriftInNsPerSec() {
return mDriftInNsPerSec;
}
/**
* Sets the clock's Drift in nanoseconds per second.
*/
public void setDriftInNsPerSec(double driftInNsPerSec) {
mHasDriftInNsPerSec = true;
mDriftInNsPerSec = driftInNsPerSec;
}
/**
* Resets the clock's Drift in nanoseconds per second.
*/
public void resetDriftInNsPerSec() {
mHasDriftInNsPerSec = false;
mDriftInNsPerSec = Double.NaN;
}
/**
* Returns true if {@link #getDriftUncertaintyInNsPerSec()} is available, false otherwise.
*/
public boolean hasDriftUncertaintyInNsPerSec() {
return mHasDriftUncertaintyInNsPerSec;
}
/**
* Gets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
*
* The value is only available if {@link #hasDriftUncertaintyInNsPerSec()} is true.
*/
public double getDriftUncertaintyInNsPerSec() {
return mDriftUncertaintyInNsPerSec;
}
/**
* Sets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
*/
public void setDriftUncertaintyInNsPerSec(double driftUncertaintyInNsPerSec) {
mHasDriftUncertaintyInNsPerSec = true;
mDriftUncertaintyInNsPerSec = driftUncertaintyInNsPerSec;
}
/**
* Resets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
*/
public void resetDriftUncertaintyInNsPerSec() {
mHasDriftUncertaintyInNsPerSec = false;
mDriftUncertaintyInNsPerSec = Double.NaN;
}
public static final Creator<GpsClock> CREATOR = new Creator<GpsClock>() {
@Override
public GpsClock createFromParcel(Parcel parcel) {
GpsClock gpsClock = new GpsClock();
gpsClock.mTimeInNs = parcel.readLong();
gpsClock.mHasLeapSecond = parcel.readInt() != 0;
gpsClock.mLeapSecond = (short) parcel.readInt();
gpsClock.mHasTimeUncertaintyInNs = parcel.readInt() != 0;
gpsClock.mTimeUncertaintyInNs = parcel.readDouble();
gpsClock.mHasBiasInNs = parcel.readInt() != 0;
gpsClock.mBiasInNs = parcel.readDouble();
gpsClock.mHasBiasUncertaintyInNs = parcel.readInt() != 0;
gpsClock.mBiasUncertaintyInNs = parcel.readDouble();
gpsClock.mHasDriftInNsPerSec = parcel.readInt() != 0;
gpsClock.mDriftInNsPerSec = parcel.readDouble();
gpsClock.mHasDriftUncertaintyInNsPerSec = parcel.readInt() != 0;
gpsClock.mDriftUncertaintyInNsPerSec = parcel.readDouble();
return gpsClock;
}
@Override
public GpsClock[] newArray(int size) {
return new GpsClock[size];
}
};
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeLong(mTimeInNs);
parcel.writeInt(mHasLeapSecond ? 1 : 0);
parcel.writeInt(mLeapSecond);
parcel.writeInt(mHasTimeUncertaintyInNs ? 1 : 0);
parcel.writeDouble(mTimeUncertaintyInNs);
parcel.writeInt(mHasBiasInNs ? 1 : 0);
parcel.writeDouble(mBiasInNs);
parcel.writeInt(mHasBiasUncertaintyInNs ? 1 : 0);
parcel.writeDouble(mBiasUncertaintyInNs);
parcel.writeInt(mHasDriftInNsPerSec ? 1 : 0);
parcel.writeDouble(mDriftInNsPerSec);
parcel.writeInt(mHasDriftUncertaintyInNsPerSec ? 1 : 0);
parcel.writeDouble(mDriftUncertaintyInNsPerSec);
}
@Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
final String format = " %-15s = %-25s %-26s = %s\n";
StringBuilder builder = new StringBuilder("GpsClock:\n");
builder.append(String.format(
format,
"LeapSecond",
mHasLeapSecond ? mLeapSecond : null,
"",
""));
builder.append(String.format(
format,
"TimeInNs",
mTimeInNs,
"TimeUncertaintyInNs",
mHasTimeUncertaintyInNs ? mTimeUncertaintyInNs : null));
builder.append(String.format(
format,
"BiasInNs",
mHasBiasInNs ? mBiasInNs : null,
"BiasUncertaintyInNs",
mHasBiasUncertaintyInNs ? mBiasUncertaintyInNs : null));
builder.append(String.format(
format,
"DriftInNsPerSec",
mHasDriftInNsPerSec ? mDriftInNsPerSec : null,
"DriftUncertaintyInNsPerSec",
mHasDriftUncertaintyInNsPerSec ? mDriftUncertaintyInNsPerSec : null));
return builder.toString();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2014 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 android.location;
import com.android.internal.util.Preconditions;
import android.annotation.NonNull;
import android.content.Context;
import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
/**
* A handler class to manage transport listeners for {@link GpsMeasurementsEvent.Listener},
* and post the events in a handler.
*
* @hide
*/
class GpsMeasurementListenerTransport {
private static final String TAG = "GpsMeasurementListenerTransport";
private final Context mContext;
private final ILocationManager mLocationManager;
private final IGpsMeasurementsListener mListenerTransport = new ListenerTransport();
private final HashSet<GpsMeasurementsEvent.Listener> mListeners =
new HashSet<GpsMeasurementsEvent.Listener>();
public GpsMeasurementListenerTransport(Context context, ILocationManager locationManager) {
mContext = context;
mLocationManager = locationManager;
}
public boolean add(@NonNull GpsMeasurementsEvent.Listener listener) {
Preconditions.checkNotNull(listener);
synchronized (mListeners) {
// we need to register with the service first, because we need to find out if the
// service will actually support the request before we attempt anything
if (mListeners.isEmpty()) {
boolean registeredWithServer;
try {
registeredWithServer = mLocationManager.addGpsMeasurementsListener(
mListenerTransport,
mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error handling first listener.", e);
return false;
}
if (!registeredWithServer) {
Log.e(TAG, "Unable to register listener transport.");
return false;
}
}
if (mListeners.contains(listener)) {
return true;
}
mListeners.add(listener);
}
return true;
}
public void remove(@NonNull GpsMeasurementsEvent.Listener listener) {
Preconditions.checkNotNull(listener);
synchronized (mListeners) {
boolean removed = mListeners.remove(listener);
boolean isLastListener = removed && mListeners.isEmpty();
if (isLastListener) {
try {
mLocationManager.removeGpsMeasurementsListener(mListenerTransport);
} catch (RemoteException e) {
Log.e(TAG, "Error handling last listener.", e);
}
}
}
}
private class ListenerTransport extends IGpsMeasurementsListener.Stub {
@Override
public void onGpsMeasurementsReceived(final GpsMeasurementsEvent eventArgs) {
Collection<GpsMeasurementsEvent.Listener> listeners;
synchronized (mListeners) {
listeners = new ArrayList<GpsMeasurementsEvent.Listener>(mListeners);
}
for (final GpsMeasurementsEvent.Listener listener : listeners) {
listener.onGpsMeasurementsReceived(eventArgs);
}
}
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2014, 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 android.location;
parcelable GpsMeasurementsEvent;

View File

@@ -0,0 +1,127 @@
/*
* Copyright (C) 2014 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 android.location;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import java.security.InvalidParameterException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
/**
* A class implementing a container for data associated with a measurement event.
* Events are delivered to registered instances of {@link Listener}.
*
* @hide
*/
public class GpsMeasurementsEvent implements Parcelable {
private final GpsClock mClock;
private final Collection<GpsMeasurement> mReadOnlyMeasurements;
/**
* Used for receiving GPS satellite measurements from the GPS engine.
* Each measurement contains raw and computed data identifying a satellite.
* You can implement this interface and call {@link LocationManager#addGpsMeasurementListener}.
*
* @hide
*/
public interface Listener {
void onGpsMeasurementsReceived(GpsMeasurementsEvent eventArgs);
}
public GpsMeasurementsEvent(GpsClock clock, GpsMeasurement[] measurements) {
if (clock == null) {
throw new InvalidParameterException("Parameter 'clock' must not be null.");
}
if (measurements == null || measurements.length == 0) {
throw new InvalidParameterException(
"Parameter 'measurements' must not be null or empty.");
}
mClock = clock;
Collection<GpsMeasurement> measurementCollection = Arrays.asList(measurements);
mReadOnlyMeasurements = Collections.unmodifiableCollection(measurementCollection);
}
@NonNull
public GpsClock getClock() {
return mClock;
}
/**
* Gets a read-only collection of measurements associated with the current event.
*/
@NonNull
public Collection<GpsMeasurement> getMeasurements() {
return mReadOnlyMeasurements;
}
public static final Creator<GpsMeasurementsEvent> CREATOR =
new Creator<GpsMeasurementsEvent>() {
@Override
public GpsMeasurementsEvent createFromParcel(Parcel in) {
ClassLoader classLoader = getClass().getClassLoader();
GpsClock clock = in.readParcelable(classLoader);
int measurementsLength = in.readInt();
GpsMeasurement[] measurementsArray = new GpsMeasurement[measurementsLength];
in.readTypedArray(measurementsArray, GpsMeasurement.CREATOR);
return new GpsMeasurementsEvent(clock, measurementsArray);
}
@Override
public GpsMeasurementsEvent[] newArray(int size) {
return new GpsMeasurementsEvent[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeParcelable(mClock, flags);
GpsMeasurement[] measurementsArray = mReadOnlyMeasurements.toArray(new GpsMeasurement[0]);
parcel.writeInt(measurementsArray.length);
parcel.writeTypedArray(measurementsArray, flags);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder("[ GpsMeasurementsEvent:\n\n");
builder.append(mClock.toString());
builder.append("\n");
for (GpsMeasurement measurement : mReadOnlyMeasurements) {
builder.append(measurement.toString());
builder.append("\n");
}
builder.append("]");
return builder.toString();
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2014, 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 android.location;
import android.location.GpsMeasurementsEvent;
/**
* {@hide}
*/
oneway interface IGpsMeasurementsListener {
void onGpsMeasurementsReceived(in GpsMeasurementsEvent event);
}

View File

@@ -21,7 +21,7 @@ import android.location.Address;
import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
import android.location.IGeocodeProvider;
import android.location.IGpsMeasurementsListener;
import android.location.IGpsStatusListener;
import android.location.ILocationListener;
import android.location.Location;
@@ -60,6 +60,9 @@ interface ILocationManager
boolean sendNiResponse(int notifId, int userResponse);
boolean addGpsMeasurementsListener(in IGpsMeasurementsListener listener, in String packageName);
boolean removeGpsMeasurementsListener(in IGpsMeasurementsListener listener);
// --- deprecated ---
List<String> getAllProviders();
List<String> getProviders(in Criteria criteria, boolean enabledOnly);

View File

@@ -16,25 +16,23 @@
package android.location;
import com.android.internal.location.ProviderProperties;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
import android.os.RemoteException;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import java.lang.SecurityException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.android.internal.location.ProviderProperties;
/**
* This class provides access to the system location services. These
* services allow applications to obtain periodic updates of the
@@ -60,6 +58,7 @@ public class LocationManager {
private final Context mContext;
private final ILocationManager mService;
private final GpsMeasurementListenerTransport mGpsMeasurementListenerTransport;
private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners =
new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>();
private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
@@ -310,6 +309,7 @@ public class LocationManager {
public LocationManager(Context context, ILocationManager service) {
mService = service;
mContext = context;
mGpsMeasurementListenerTransport = new GpsMeasurementListenerTransport(mContext, mService);
}
private LocationProvider createProvider(String name, ProviderProperties properties) {
@@ -1570,6 +1570,29 @@ public class LocationManager {
}
}
/**
* Adds a GPS Measurement listener.
*
* @param listener a {@link android.location.GpsMeasurementsEvent.Listener} object to register.
* @return {@code true} if the listener was successfully registered, {@code false} otherwise.
*
* @hide
*/
public boolean addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
return mGpsMeasurementListenerTransport.add(listener);
}
/**
* Removes a GPS Measurement listener.
*
* @param listener a {@link GpsMeasurementsEvent.Listener} object to remove.
*
* @hide
*/
public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
mGpsMeasurementListenerTransport.remove(listener);
}
/**
* Retrieves information about the current status of the GPS engine.
* This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}

View File

@@ -16,6 +16,27 @@
package com.android.server;
import com.android.internal.content.PackageMonitor;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.os.BackgroundThread;
import com.android.server.location.FlpHardwareProvider;
import com.android.server.location.FusedProxy;
import com.android.server.location.GeocoderProxy;
import com.android.server.location.GeofenceManager;
import com.android.server.location.GeofenceProxy;
import com.android.server.location.GpsLocationProvider;
import com.android.server.location.GpsMeasurementsProvider;
import com.android.server.location.LocationBlacklist;
import com.android.server.location.LocationFudger;
import com.android.server.location.LocationProviderInterface;
import com.android.server.location.LocationProviderProxy;
import com.android.server.location.LocationRequestStatistics;
import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
import com.android.server.location.LocationRequestStatistics.PackageStatistics;
import com.android.server.location.MockProvider;
import com.android.server.location.PassiveProvider;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -36,6 +57,7 @@ import android.location.Address;
import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
import android.location.IGpsMeasurementsListener;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
import android.location.ILocationListener;
@@ -62,26 +84,6 @@ import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
import com.android.internal.content.PackageMonitor;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.os.BackgroundThread;
import com.android.server.location.FlpHardwareProvider;
import com.android.server.location.FusedProxy;
import com.android.server.location.GeocoderProxy;
import com.android.server.location.GeofenceProxy;
import com.android.server.location.GeofenceManager;
import com.android.server.location.GpsLocationProvider;
import com.android.server.location.LocationBlacklist;
import com.android.server.location.LocationFudger;
import com.android.server.location.LocationProviderInterface;
import com.android.server.location.LocationProviderProxy;
import com.android.server.location.LocationRequestStatistics;
import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
import com.android.server.location.LocationRequestStatistics.PackageStatistics;
import com.android.server.location.MockProvider;
import com.android.server.location.PassiveProvider;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -154,6 +156,7 @@ public class LocationManagerService extends ILocationManager.Stub {
private LocationWorkerHandler mLocationHandler;
private PassiveProvider mPassiveProvider; // track passive provider for special cases
private LocationBlacklist mBlacklist;
private GpsMeasurementsProvider mGpsMeasurementsProvider;
// --- fields below are protected by mLock ---
// Set of providers that are explicitly enabled
@@ -403,6 +406,7 @@ public class LocationManagerService extends ILocationManager.Stub {
addProviderLocked(gpsProvider);
mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
}
mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
/*
Load package name(s) containing location provider support.
@@ -1803,6 +1807,36 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
@Override
public boolean addGpsMeasurementsListener(
IGpsMeasurementsListener listener,
String packageName) {
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkResolutionLevelIsSufficientForProviderUse(
allowedResolutionLevel,
LocationManager.GPS_PROVIDER);
int uid = Binder.getCallingUid();
long identity = Binder.clearCallingIdentity();
boolean hasLocationAccess;
try {
hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel);
} finally {
Binder.restoreCallingIdentity(identity);
}
if (!hasLocationAccess) {
return false;
}
return mGpsMeasurementsProvider.addListener(listener);
}
@Override
public boolean removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
return mGpsMeasurementsProvider.removeListener(listener);
}
@Override
public boolean sendExtraCommand(String provider, String command, Bundle extras) {
if (provider == null) {

View File

@@ -16,6 +16,15 @@
package com.android.server.location;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.location.GpsNetInitiatedHandler;
import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
@@ -28,6 +37,7 @@ import android.hardware.location.GeofenceHardware;
import android.hardware.location.GeofenceHardwareImpl;
import android.location.Criteria;
import android.location.FusedBatchOptions;
import android.location.GpsMeasurementsEvent;
import android.location.IGpsGeofenceHardware;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
@@ -46,7 +56,6 @@ import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
@@ -64,27 +73,17 @@ import android.telephony.gsm.GsmCellLocation;
import android.util.Log;
import android.util.NtpTrustedTime;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.location.GpsNetInitiatedHandler;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.ArrayList;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.Map.Entry;
import java.util.Properties;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* A GPS implementation of LocationProvider used by LocationManager.
@@ -314,7 +313,12 @@ public class GpsLocationProvider implements LocationProviderInterface {
private final ILocationManager mILocationManager;
private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
private Bundle mLocationExtras = new Bundle();
private ArrayList<Listener> mListeners = new ArrayList<Listener>();
private GpsStatusListenerHelper mListenerHelper = new GpsStatusListenerHelper() {
@Override
protected boolean isSupported() {
return native_is_measurement_supported();
}
};
// Handler for processing events
private Handler mHandler;
@@ -348,49 +352,29 @@ public class GpsLocationProvider implements LocationProviderInterface {
private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
@Override
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);
}
mListenerHelper.addListener(listener);
}
@Override
public void removeGpsStatusListener(IGpsStatusListener listener) {
if (listener == null) {
throw new NullPointerException("listener is null in addGpsStatusListener");
}
mListenerHelper.removeListener(listener);
}
};
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;
}
}
private final GpsMeasurementsProvider mGpsMeasurementsProvider = new GpsMeasurementsProvider() {
@Override
public boolean isSupported() {
return native_is_measurement_supported();
}
if (l != null) {
mListeners.remove(l);
binder.unlinkToDeath(l, 0);
}
}
@Override
protected void onFirstListenerAdded() {
native_start_measurement_collection();
}
@Override
protected void onLastListenerRemoved() {
native_stop_measurement_collection();
}
};
@@ -402,6 +386,10 @@ public class GpsLocationProvider implements LocationProviderInterface {
return mGpsGeofenceBinder;
}
public GpsMeasurementsProvider getGpsMeasurementsProvider() {
return mGpsMeasurementsProvider;
}
private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -892,26 +880,6 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
}
private final class Listener implements IBinder.DeathRecipient {
final IGpsStatusListener mListener;
Listener(IGpsStatusListener listener) {
mListener = listener;
}
@Override
public void binderDied() {
if (DEBUG) Log.d(TAG, "GPS status listener died");
synchronized (mListeners) {
mListeners.remove(this);
}
if (mListener != null) {
mListener.asBinder().unlinkToDeath(this, 0);
}
}
}
private void updateClientUids(WorkSource source) {
// Update work source.
WorkSource[] changes = mClientSource.setReturningDiffs(source);
@@ -1185,20 +1153,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
// 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(mTimeToFirstFix);
} catch (RemoteException e) {
Log.w(TAG, "RemoteException in stopNavigating");
mListeners.remove(listener);
// adjust for size of list changing
size--;
}
}
}
mListenerHelper.onFirstFix(mTimeToFirstFix);
}
if (mSingleShot) {
@@ -1232,49 +1187,31 @@ public class GpsLocationProvider implements LocationProviderInterface {
private void reportStatus(int status) {
if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
synchronized (mListeners) {
boolean wasNavigating = mNavigating;
boolean wasNavigating = mNavigating;
switch (status) {
case GPS_STATUS_SESSION_BEGIN:
mNavigating = true;
mEngineOn = true;
break;
case GPS_STATUS_SESSION_END:
mNavigating = false;
break;
case GPS_STATUS_ENGINE_ON:
mEngineOn = true;
break;
case GPS_STATUS_ENGINE_OFF:
mEngineOn = false;
mNavigating = false;
break;
}
switch (status) {
case GPS_STATUS_SESSION_BEGIN:
mNavigating = true;
mEngineOn = true;
break;
case GPS_STATUS_SESSION_END:
mNavigating = false;
break;
case GPS_STATUS_ENGINE_ON:
mEngineOn = true;
break;
case GPS_STATUS_ENGINE_OFF:
mEngineOn = false;
mNavigating = false;
break;
}
if (wasNavigating != mNavigating) {
mListenerHelper.onStatusChanged(mNavigating);
if (wasNavigating != mNavigating) {
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(LocationManager.GPS_ENABLED_CHANGE_ACTION);
intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
}
// send an intent to notify that the GPS has been enabled or disabled
Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
}
}
@@ -1282,25 +1219,16 @@ public class GpsLocationProvider implements LocationProviderInterface {
* 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--;
}
}
}
mListenerHelper.onSvStatusChanged(
svCount,
mSvs,
mSnrs,
mSvElevations,
mSvAzimuths,
mSvMasks[EPHEMERIS_MASK],
mSvMasks[ALMANAC_MASK],
mSvMasks[USED_FOR_FIX_MASK]);
if (VERBOSE) {
Log.v(TAG, "SV count: " + svCount +
@@ -1398,26 +1326,16 @@ public class GpsLocationProvider implements LocationProviderInterface {
* called from native code to report NMEA data received
*/
private void reportNmea(long timestamp) {
synchronized (mListeners) {
int size = mListeners.size();
if (size > 0) {
// don't bother creating the String if we have no listeners
int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
String nmea = new String(mNmeaBuffer, 0, length);
int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
mListenerHelper.onNmeaReceived(timestamp, nmea);
}
for (int i = 0; i < size; i++) {
Listener listener = mListeners.get(i);
try {
listener.mListener.onNmeaReceived(timestamp, nmea);
} catch (RemoteException e) {
Log.w(TAG, "RemoteException in reportNmea");
mListeners.remove(listener);
// adjust for size of list changing
size--;
}
}
}
}
/**
* called from native code - Gps Data callback
*/
private void reportMeasurementData(GpsMeasurementsEvent event) {
mGpsMeasurementsProvider.onMeasurementsAvailable(event);
}
/**
@@ -1845,7 +1763,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
Log.e(TAG, "No APN found to select.");
}
} catch (Exception e) {
Log.e(TAG, "Error encountered on selectiong the APN.", e);
Log.e(TAG, "Error encountered on selecting the APN.", e);
} finally {
if (cursor != null) {
cursor.close();
@@ -2008,4 +1926,9 @@ public class GpsLocationProvider implements LocationProviderInterface {
private static native boolean native_remove_geofence(int geofenceId);
private static native boolean native_resume_geofence(int geofenceId, int transitions);
private static native boolean native_pause_geofence(int geofenceId);
// Gps Hal measurements support.
private static native boolean native_is_measurement_supported();
private static native boolean native_start_measurement_collection();
private static native boolean native_stop_measurement_collection();
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2014 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.server.location;
import android.location.GpsMeasurementsEvent;
import android.location.IGpsMeasurementsListener;
import android.os.RemoteException;
/**
* An base implementation for GPS measurements provider.
* It abstracts out the responsibility of handling listeners, while still allowing technology
* specific implementations to be built.
*
* @hide
*/
public abstract class GpsMeasurementsProvider
extends RemoteListenerHelper<IGpsMeasurementsListener> {
public void onMeasurementsAvailable(final GpsMeasurementsEvent event) {
ListenerOperation<IGpsMeasurementsListener> operation =
new ListenerOperation<IGpsMeasurementsListener>() {
@Override
public void execute(IGpsMeasurementsListener listener) throws RemoteException {
listener.onGpsMeasurementsReceived(event);
}
};
foreach(operation);
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2014 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.server.location;
import android.location.IGpsStatusListener;
import android.os.RemoteException;
/**
* Implementation of a handler for {@link IGpsStatusListener}.
*/
abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusListener> {
public void onFirstFix(final int timeToFirstFix) {
Operation operation = new Operation() {
@Override
public void execute(IGpsStatusListener listener) throws RemoteException {
listener.onFirstFix(timeToFirstFix);
}
};
foreach(operation);
}
public void onStatusChanged(final boolean isNavigating) {
Operation operation = new Operation() {
@Override
public void execute(IGpsStatusListener listener) throws RemoteException {
if (isNavigating) {
listener.onGpsStarted();
} else {
listener.onGpsStopped();
}
}
};
foreach(operation);
}
public void onSvStatusChanged(
final int svCount,
final int[] prns,
final float[] snrs,
final float[] elevations,
final float[] azimuths,
final int ephemerisMask,
final int almanacMask,
final int usedInFixMask) {
Operation operation = new Operation() {
@Override
public void execute(IGpsStatusListener listener) throws RemoteException {
listener.onSvStatusChanged(
svCount,
prns,
snrs,
elevations,
azimuths,
ephemerisMask,
almanacMask,
usedInFixMask);
}
};
foreach(operation);
}
public void onNmeaReceived(final long timestamp, final String nmea) {
Operation operation = new Operation() {
@Override
public void execute(IGpsStatusListener listener) throws RemoteException {
listener.onNmeaReceived(timestamp, nmea);
}
};
foreach(operation);
}
private abstract class Operation implements ListenerOperation<IGpsStatusListener> { }
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (C) 2014 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.server.location;
import com.android.internal.util.Preconditions;
import android.annotation.NonNull;
import android.os.IBinder;
import android.os.IInterface;
import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
/**
* A helper class, that handles operations in remote listeners, and tracks for remote process death.
*/
abstract class RemoteListenerHelper<TListener extends IInterface> {
private static final String TAG = "RemoteListenerHelper";
private final HashMap<IBinder, LinkedListener> mListenerMap =
new HashMap<IBinder, LinkedListener>();
public boolean addListener(@NonNull TListener listener) {
Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener.");
if (!isSupported()) {
Log.e(TAG, "Refused to add listener, the feature is not supported.");
return false;
}
IBinder binder = listener.asBinder();
LinkedListener deathListener = new LinkedListener(listener);
synchronized (mListenerMap) {
if (mListenerMap.containsKey(binder)) {
// listener already added
return true;
}
try {
binder.linkToDeath(deathListener, 0 /* flags */);
} catch (RemoteException e) {
// if the remote process registering the listener is already death, just swallow the
// exception and continue
Log.e(TAG, "Remote listener already died.", e);
return false;
}
mListenerMap.put(binder, deathListener);
if (mListenerMap.size() == 1) {
onFirstListenerAdded();
}
}
return true;
}
public boolean removeListener(@NonNull TListener listener) {
Preconditions.checkNotNull(listener, "Attempted to remove a 'null' listener.");
if (!isSupported()) {
Log.e(TAG, "Refused to remove listener, the feature is not supported.");
return false;
}
IBinder binder = listener.asBinder();
LinkedListener linkedListener;
synchronized (mListenerMap) {
linkedListener = mListenerMap.remove(binder);
if (mListenerMap.isEmpty() && linkedListener != null) {
onLastListenerRemoved();
}
}
if (linkedListener != null) {
binder.unlinkToDeath(linkedListener, 0 /* flags */);
}
return true;
}
protected abstract boolean isSupported();
protected void onFirstListenerAdded() {
// event triggered when the first listener has been added
}
protected void onLastListenerRemoved() {
// event triggered when the last listener has bee removed
}
protected interface ListenerOperation<TListener extends IInterface> {
void execute(TListener listener) throws RemoteException;
}
protected void foreach(ListenerOperation operation) {
Collection<LinkedListener> linkedListeners;
synchronized (mListenerMap) {
Collection<LinkedListener> values = mListenerMap.values();
linkedListeners = new ArrayList<LinkedListener>(values);
}
for (LinkedListener linkedListener : linkedListeners) {
TListener listener = linkedListener.getUnderlyingListener();
try {
operation.execute(listener);
} catch (RemoteException e) {
Log.e(TAG, "Error in monitored listener.", e);
removeListener(listener);
}
}
}
private class LinkedListener implements IBinder.DeathRecipient {
private final TListener mListener;
public LinkedListener(@NonNull TListener listener) {
mListener = listener;
}
@NonNull
public TListener getUnderlyingListener() {
return mListener;
}
@Override
public void binderDied() {
Log.d(TAG, "Remote Listener died: " + mListener);
removeListener(mListener);
}
}
}

View File

@@ -52,6 +52,7 @@ static jmethodID method_reportGeofenceAddStatus;
static jmethodID method_reportGeofenceRemoveStatus;
static jmethodID method_reportGeofencePauseStatus;
static jmethodID method_reportGeofenceResumeStatus;
static jmethodID method_reportMeasurementData;
static const GpsInterface* sGpsInterface = NULL;
static const GpsXtraInterface* sGpsXtraInterface = NULL;
@@ -60,6 +61,7 @@ static const GpsNiInterface* sGpsNiInterface = NULL;
static const GpsDebugInterface* sGpsDebugInterface = NULL;
static const AGpsRilInterface* sAGpsRilInterface = NULL;
static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
static const GpsMeasurementInterface* sGpsMeasurementInterface = NULL;
// temporary storage for GPS callbacks
static GpsSvStatus sGpsSvStatus;
@@ -441,6 +443,10 @@ static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env,
"(II)V");
method_reportGeofencePauseStatus = env->GetMethodID(clazz,"reportGeofencePauseStatus",
"(II)V");
method_reportMeasurementData = env->GetMethodID(
clazz,
"reportMeasurementData",
"(Landroid/location/GpsMeasurementsEvent;)V");
err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {
@@ -464,6 +470,8 @@ static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env,
(const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
sGpsGeofencingInterface =
(const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE);
sGpsMeasurementInterface =
(const GpsMeasurementInterface*)sGpsInterface->get_extension(GPS_MEASUREMENT_INTERFACE);
}
}
@@ -851,42 +859,500 @@ static jboolean android_location_GpsLocationProvider_resume_geofence(JNIEnv* env
return JNI_FALSE;
}
static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
const char* doubleSignature = "(D)V";
jclass gpsClockClass = env->FindClass("android/location/GpsClock");
jmethodID gpsClockCtor = env->GetMethodID(gpsClockClass, "<init>", "()V");
jobject gpsClockObject = env->NewObject(gpsClockClass, gpsClockCtor);
GpsClockFlags flags = clock->flags;
if (flags & GPS_CLOCK_HAS_LEAP_SECOND) {
jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setLeapSecond", "(S)V");
env->CallObjectMethod(gpsClockObject, setterMethod, clock->leap_second);
}
jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setTimeInNs", "(J)V");
env->CallObjectMethod(gpsClockObject, setterMethod, clock->time_ns);
if (flags & GPS_CLOCK_HAS_TIME_UNCERTAINTY) {
jmethodID setterMethod = env->GetMethodID(
gpsClockClass,
"setTimeUncertaintyInNs",
doubleSignature);
env->CallObjectMethod(gpsClockObject, setterMethod, clock->time_uncertainty_ns);
}
if (flags & GPS_CLOCK_HAS_BIAS) {
jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setBiasInNs", doubleSignature);
env->CallObjectMethod(gpsClockObject, setterMethod, clock->bias_ns);
}
if (flags & GPS_CLOCK_HAS_BIAS_UNCERTAINTY) {
jmethodID setterMethod = env->GetMethodID(
gpsClockClass,
"setBiasUncertaintyInNs",
doubleSignature);
env->CallObjectMethod(gpsClockObject, setterMethod, clock->bias_uncertainty_ns);
}
if (flags & GPS_CLOCK_HAS_DRIFT) {
jmethodID setterMethod = env->GetMethodID(
gpsClockClass,
"setDriftInNsPerSec",
doubleSignature);
env->CallObjectMethod(gpsClockObject, setterMethod, clock->drift_nsps);
}
if (flags & GPS_CLOCK_HAS_DRIFT_UNCERTAINTY) {
jmethodID setterMethod = env->GetMethodID(
gpsClockClass,
"setDriftUncertaintyInNsPerSec",
doubleSignature);
env->CallObjectMethod(gpsClockObject, setterMethod, clock->drift_uncertainty_nsps);
}
return gpsClockObject;
}
static jobject translate_gps_measurement(
JNIEnv* env,
GpsMeasurement* measurement,
uint32_t time_ns) {
const char* shortSignature = "(S)V";
const char* longSignature = "(J)V";
const char* floatSignature = "(F)V";
const char* doubleSignature = "(D)V";
jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
jmethodID gpsMeasurementCtor = env->GetMethodID(gpsMeasurementClass, "<init>", "()V");
jobject gpsMeasurementObject = env->NewObject(gpsMeasurementClass, gpsMeasurementCtor);
GpsMeasurementFlags flags = measurement->flags;
jmethodID prnSetterMethod = env->GetMethodID(gpsMeasurementClass, "setPrn", "(B)V");
env->CallObjectMethod(gpsMeasurementObject, prnSetterMethod, measurement->prn);
jmethodID localTimeSetterMethod =
env->GetMethodID(gpsMeasurementClass, "setLocalTimeInNs", longSignature);
env->CallObjectMethod(
gpsMeasurementObject,
localTimeSetterMethod,
time_ns + measurement->time_offset_ns);
jmethodID receivedGpsTowSetterMethod =
env->GetMethodID(gpsMeasurementClass, "setReceivedGpsTowInNs", longSignature);
env->CallObjectMethod(
gpsMeasurementObject,
receivedGpsTowSetterMethod,
measurement->received_gps_tow_ns);
jmethodID cn0SetterMethod = env->GetMethodID(
gpsMeasurementClass,
"setCn0InDbHz",
doubleSignature);
env->CallObjectMethod(gpsMeasurementObject, cn0SetterMethod, measurement->c_n0_dbhz);
jmethodID pseudorangeRateSetterMethod = env->GetMethodID(
gpsMeasurementClass,
"setPseudorangeRateInMetersPerSec",
doubleSignature);
env->CallObjectMethod(
gpsMeasurementObject,
pseudorangeRateSetterMethod,
measurement->pseudorange_rate_mpersec);
jmethodID pseudorangeRateUncertaintySetterMethod = env->GetMethodID(
gpsMeasurementClass,
"setPseudorangeRateUncertaintyInMetersPerSec",
doubleSignature);
env->CallObjectMethod(
gpsMeasurementObject,
pseudorangeRateUncertaintySetterMethod,
measurement->pseudorange_rate_uncertainty_mpersec);
jmethodID accumulatedDeltaRangeSetterMethod = env->GetMethodID(
gpsMeasurementClass,
"setAccumulatedDeltaRangeInMeters",
doubleSignature);
env->CallVoidMethod(
gpsMeasurementObject,
accumulatedDeltaRangeSetterMethod,
measurement->accumulated_delta_range_m);
jmethodID accumulatedDeltaRangeUncertaintySetterMethod = env->GetMethodID(
gpsMeasurementClass,
"setAccumulatedDeltaRangeUncertaintyInMeters",
doubleSignature);
env->CallVoidMethod(
gpsMeasurementObject,
accumulatedDeltaRangeUncertaintySetterMethod,
measurement->accumulated_delta_range_uncertainty_m);
if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE) {
jmethodID setterMethod = env->GetMethodID(
gpsMeasurementClass,
"setPseudorangeInMeters",
doubleSignature);
env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->pseudorange_m);
}
if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY) {
jmethodID setterMethod = env->GetMethodID(
gpsMeasurementClass,
"setPseudorangeUncertaintyInMeters",
doubleSignature);
env->CallObjectMethod(
gpsMeasurementObject,
setterMethod,
measurement->pseudorange_uncertainty_m);
}
if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE) {
jmethodID setterMethod = env->GetMethodID(
gpsMeasurementClass,
"setCodePhaseInChips",
doubleSignature);
env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->code_phase_chips);
}
if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY) {
jmethodID setterMethod = env->GetMethodID(
gpsMeasurementClass,
"setCodePhaseUncertaintyInChips",
doubleSignature);
env->CallObjectMethod(
gpsMeasurementObject,
setterMethod,
measurement->code_phase_uncertainty_chips);
}
if (flags & GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY) {
jmethodID setterMethod = env->GetMethodID(
gpsMeasurementClass,
"setCarrierFrequencyInHz",
floatSignature);
env->CallObjectMethod(
gpsMeasurementObject,
setterMethod,
measurement->carrier_frequency_hz);
}
if (flags & GPS_MEASUREMENT_HAS_CARRIER_CYCLES) {
jmethodID setterMethod =
env->GetMethodID(gpsMeasurementClass, "setCarrierCycles", longSignature);
env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->carrier_cycles);
}
if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE) {
jmethodID setterMethod =
env->GetMethodID(gpsMeasurementClass, "setCarrierPhase", doubleSignature);
env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->carrier_phase);
}
if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY) {
jmethodID setterMethod = env->GetMethodID(
gpsMeasurementClass,
"setCarrierPhaseUncertainty",
doubleSignature);
env->CallObjectMethod(
gpsMeasurementObject,
setterMethod,
measurement->carrier_phase_uncertainty);
}
jmethodID lossOfLockSetterMethod =
env->GetMethodID(gpsMeasurementClass, "setLossOfLock", shortSignature);
env->CallObjectMethod(gpsMeasurementObject, lossOfLockSetterMethod, measurement->loss_of_lock);
if (flags & GPS_MEASUREMENT_HAS_BIT_NUMBER) {
jmethodID setterMethod = env->GetMethodID(
gpsMeasurementClass,
"setBitNumber",
shortSignature);
env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->bit_number);
}
if (flags & GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT) {
jmethodID setterMethod = env->GetMethodID(
gpsMeasurementClass,
"setTimeFromLastBitInNs",
longSignature);
env->CallObjectMethod(
gpsMeasurementObject,
setterMethod,
measurement->time_from_last_bit_ns);
}
if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT) {
jmethodID setterMethod = env->GetMethodID(
gpsMeasurementClass,
"setDopplerShiftInHz",
doubleSignature);
env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->doppler_shift_hz);
}
if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY) {
jmethodID setterMethod = env->GetMethodID(
gpsMeasurementClass,
"setDopplerShiftUncertaintyInHz",
doubleSignature);
env->CallObjectMethod(
gpsMeasurementObject,
setterMethod,
measurement->doppler_shift_uncertainty_hz);
}
jmethodID multipathIndicatorSetterMethod = env->GetMethodID(
gpsMeasurementClass,
"setMultipathIndicator",
shortSignature);
env->CallObjectMethod(
gpsMeasurementObject,
multipathIndicatorSetterMethod,
measurement->multipath_indicator);
if (flags & GPS_MEASUREMENT_HAS_SNR) {
jmethodID setterMethod =
env->GetMethodID(gpsMeasurementClass, "setSnrInDb", doubleSignature);
env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->snr_db);
}
if (flags & GPS_MEASUREMENT_HAS_ELEVATION) {
jmethodID setterMethod = env->GetMethodID(
gpsMeasurementClass,
"setElevationInDeg",
doubleSignature);
env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->elevation_deg);
}
if (flags & GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY) {
jmethodID setterMethod = env->GetMethodID(
gpsMeasurementClass,
"setElevationUncertaintyInDeg",
doubleSignature);
env->CallObjectMethod(
gpsMeasurementObject,
setterMethod,
measurement->elevation_uncertainty_deg);
}
if (flags & GPS_MEASUREMENT_HAS_AZIMUTH) {
jmethodID setterMethod =
env->GetMethodID(gpsMeasurementClass, "setAzimuthInDeg", doubleSignature);
env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->azimuth_deg);
}
if (flags & GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY) {
jmethodID setterMethod = env->GetMethodID(
gpsMeasurementClass,
"setAzimuthUncertaintyInDeg",
doubleSignature);
env->CallObjectMethod(
gpsMeasurementObject,
setterMethod,
measurement->azimuth_uncertainty_deg);
}
jmethodID usedInFixSetterMethod = env->GetMethodID(gpsMeasurementClass, "setUsedInFix", "(Z)V");
env->CallObjectMethod(
gpsMeasurementObject,
usedInFixSetterMethod,
(flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
return gpsMeasurementObject;
}
static jobjectArray translate_gps_measurements(JNIEnv* env, GpsData* data) {
size_t measurementCount = data->measurement_count;
if (measurementCount == 0) {
return NULL;
}
jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
jobjectArray gpsMeasurementArray = env->NewObjectArray(
measurementCount,
gpsMeasurementClass,
NULL /* initialElement */);
GpsMeasurement* gpsMeasurements = data->measurements;
for (uint16_t i = 0; i < measurementCount; ++i) {
jobject gpsMeasurement = translate_gps_measurement(
env,
&gpsMeasurements[i],
data->clock.time_ns);
env->SetObjectArrayElement(gpsMeasurementArray, i, gpsMeasurement);
env->DeleteLocalRef(gpsMeasurement);
}
env->DeleteLocalRef(gpsMeasurementClass);
return gpsMeasurementArray;
}
static void measurement_callback(GpsData* data) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
if (data == NULL) {
ALOGE("Invalid data provided to gps_measurement_callback");
return;
}
if (data->size == sizeof(GpsData)) {
jobject gpsClock = translate_gps_clock(env, &data->clock);
jobjectArray measurementArray = translate_gps_measurements(env, data);
jclass gpsMeasurementsEventClass = env->FindClass("android/location/GpsMeasurementsEvent");
jmethodID gpsMeasurementsEventCtor = env->GetMethodID(
gpsMeasurementsEventClass,
"<init>",
"(Landroid/location/GpsClock;[Landroid/location/GpsMeasurement;)V");
jobject gpsMeasurementsEvent = env->NewObject(
gpsMeasurementsEventClass,
gpsMeasurementsEventCtor,
gpsClock,
measurementArray);
env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, gpsMeasurementsEvent);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
} else {
ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%d", data->size);
return;
}
}
GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
sizeof(GpsMeasurementCallbacks),
measurement_callback,
};
static jboolean android_location_GpsLocationProvider_is_measurement_supported(
JNIEnv* env,
jobject obj) {
if (sGpsMeasurementInterface != NULL) {
return JNI_TRUE;
}
return JNI_FALSE;
}
static jboolean android_location_GpsLocationProvider_start_measurement_collection(
JNIEnv* env,
jobject obj) {
if (sGpsMeasurementInterface == NULL) {
ALOGE("Measurement interface is not available.");
return JNI_FALSE;
}
int result = sGpsMeasurementInterface->init(&sGpsMeasurementCallbacks);
if (result != GPS_GEOFENCE_OPERATION_SUCCESS) {
ALOGE("An error has been found on GpsMeasurementInterface::init, status=%d", result);
return JNI_FALSE;
}
return JNI_TRUE;
}
static jboolean android_location_GpsLocationProvider_stop_measurement_collection(
JNIEnv* env,
jobject obj) {
if (sGpsMeasurementInterface == NULL) {
ALOGE("Measurement interface not available");
return JNI_FALSE;
}
sGpsMeasurementInterface->close();
return JNI_TRUE;
}
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
{"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
{"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
{"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
{"native_set_position_mode", "(IIIII)Z", (void*)android_location_GpsLocationProvider_set_position_mode},
{"native_set_position_mode",
"(IIIII)Z",
(void*)android_location_GpsLocationProvider_set_position_mode},
{"native_start", "()Z", (void*)android_location_GpsLocationProvider_start},
{"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
{"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
{"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
{"native_delete_aiding_data",
"(I)V",
(void*)android_location_GpsLocationProvider_delete_aiding_data},
{"native_read_sv_status",
"([I[F[F[F[I)I",
(void*)android_location_GpsLocationProvider_read_sv_status},
{"native_read_nmea", "([BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
{"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
{"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location},
{"native_inject_location",
"(DDF)V",
(void*)android_location_GpsLocationProvider_inject_location},
{"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
{"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data},
{"native_agps_data_conn_open", "(Ljava/lang/String;I)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open},
{"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
{"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
{"native_agps_set_id","(ILjava/lang/String;)V",(void*)android_location_GpsLocationProvider_agps_set_id},
{"native_agps_set_ref_location_cellid","(IIIII)V",(void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
{"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server},
{"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
{"native_agps_ni_message", "([BI)V", (void *)android_location_GpsLocationProvider_agps_send_ni_message},
{"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state},
{"native_update_network_state", "(ZIZZLjava/lang/String;Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_update_network_state },
{"native_is_geofence_supported", "()Z", (void*) android_location_GpsLocationProvider_is_geofence_supported},
{"native_add_geofence", "(IDDDIIII)Z", (void *)android_location_GpsLocationProvider_add_geofence},
{"native_remove_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_remove_geofence},
{"native_inject_xtra_data",
"([BI)V",
(void*)android_location_GpsLocationProvider_inject_xtra_data},
{"native_agps_data_conn_open",
"(Ljava/lang/String;I)V",
(void*)android_location_GpsLocationProvider_agps_data_conn_open},
{"native_agps_data_conn_closed",
"()V",
(void*)android_location_GpsLocationProvider_agps_data_conn_closed},
{"native_agps_data_conn_failed",
"()V",
(void*)android_location_GpsLocationProvider_agps_data_conn_failed},
{"native_agps_set_id",
"(ILjava/lang/String;)V",
(void*)android_location_GpsLocationProvider_agps_set_id},
{"native_agps_set_ref_location_cellid",
"(IIIII)V",
(void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
{"native_set_agps_server",
"(ILjava/lang/String;I)V",
(void*)android_location_GpsLocationProvider_set_agps_server},
{"native_send_ni_response",
"(II)V",
(void*)android_location_GpsLocationProvider_send_ni_response},
{"native_agps_ni_message",
"([BI)V",
(void *)android_location_GpsLocationProvider_agps_send_ni_message},
{"native_get_internal_state",
"()Ljava/lang/String;",
(void*)android_location_GpsLocationProvider_get_internal_state},
{"native_update_network_state",
"(ZIZZLjava/lang/String;Ljava/lang/String;)V",
(void*)android_location_GpsLocationProvider_update_network_state },
{"native_is_geofence_supported",
"()Z",
(void*) android_location_GpsLocationProvider_is_geofence_supported},
{"native_add_geofence",
"(IDDDIIII)Z",
(void *)android_location_GpsLocationProvider_add_geofence},
{"native_remove_geofence",
"(I)Z",
(void *)android_location_GpsLocationProvider_remove_geofence},
{"native_pause_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_pause_geofence},
{"native_resume_geofence", "(II)Z", (void *)android_location_GpsLocationProvider_resume_geofence}
{"native_resume_geofence",
"(II)Z",
(void *)android_location_GpsLocationProvider_resume_geofence},
{"native_is_measurement_supported",
"()Z",
(void*) android_location_GpsLocationProvider_is_measurement_supported},
{"native_start_measurement_collection",
"()Z",
(void*) android_location_GpsLocationProvider_start_measurement_collection},
{"native_stop_measurement_collection",
"()Z",
(void*) android_location_GpsLocationProvider_stop_measurement_collection}
};
int register_android_server_location_GpsLocationProvider(JNIEnv* env)
{
return jniRegisterNativeMethods(env, "com/android/server/location/GpsLocationProvider", sMethods, NELEM(sMethods));
return jniRegisterNativeMethods(
env,
"com/android/server/location/GpsLocationProvider",
sMethods,
NELEM(sMethods));
}
} /* namespace android */