summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--location/java/android/location/GpsMeasurementListenerTransport.java90
-rw-r--r--location/java/android/location/GpsNavigationMessage.java276
-rw-r--r--location/java/android/location/GpsNavigationMessageEvent.aidl19
-rw-r--r--location/java/android/location/GpsNavigationMessageEvent.java92
-rw-r--r--location/java/android/location/GpsNavigationMessageListenerTransport.java69
-rw-r--r--location/java/android/location/IGpsNavigationMessageListener.aidl26
-rw-r--r--location/java/android/location/ILocationManager.aidl6
-rw-r--r--location/java/android/location/LocalListenerHelper.java109
-rw-r--r--location/java/android/location/LocationManager.java29
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java34
-rw-r--r--services/core/java/com/android/server/location/GpsLocationProvider.java55
-rw-r--r--services/core/java/com/android/server/location/GpsMeasurementsProvider.java3
-rw-r--r--services/core/java/com/android/server/location/GpsNavigationMessageProvider.java48
-rw-r--r--services/core/java/com/android/server/location/GpsStatusListenerHelper.java4
-rw-r--r--services/core/java/com/android/server/location/RemoteListenerHelper.java39
-rw-r--r--services/core/jni/com_android_server_location_GpsLocationProvider.cpp127
17 files changed, 927 insertions, 100 deletions
diff --git a/Android.mk b/Android.mk
index 7dfa6a0..278e67f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -297,6 +297,7 @@ LOCAL_SRC_FILES += \
location/java/android/location/IGeocodeProvider.aidl \
location/java/android/location/IGeofenceProvider.aidl \
location/java/android/location/IGpsMeasurementsListener.aidl \
+ location/java/android/location/IGpsNavigationMessageListener.aidl \
location/java/android/location/IGpsStatusListener.aidl \
location/java/android/location/IGpsStatusProvider.aidl \
location/java/android/location/ILocationListener.aidl \
diff --git a/location/java/android/location/GpsMeasurementListenerTransport.java b/location/java/android/location/GpsMeasurementListenerTransport.java
index 48a4b44..2d9a372 100644
--- a/location/java/android/location/GpsMeasurementListenerTransport.java
+++ b/location/java/android/location/GpsMeasurementListenerTransport.java
@@ -16,99 +16,51 @@
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.
+ * A handler class to manage transport listeners for {@link GpsMeasurementsEvent.Listener}.
*
* @hide
*/
-class GpsMeasurementListenerTransport {
- private static final String TAG = "GpsMeasurementListenerTransport";
-
+class GpsMeasurementListenerTransport
+ extends LocalListenerHelper<GpsMeasurementsEvent.Listener> {
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) {
+ super("GpsMeasurementListenerTransport");
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;
+ @Override
+ protected boolean registerWithServer() throws RemoteException {
+ return mLocationManager.addGpsMeasurementsListener(
+ mListenerTransport,
+ mContext.getPackageName());
}
- 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);
- }
- }
- }
+ @Override
+ protected void unregisterFromServer() throws RemoteException {
+ mLocationManager.removeGpsMeasurementsListener(mListenerTransport);
}
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);
- }
+ public void onGpsMeasurementsReceived(final GpsMeasurementsEvent event) {
+ ListenerOperation<GpsMeasurementsEvent.Listener> operation =
+ new ListenerOperation<GpsMeasurementsEvent.Listener>() {
+ @Override
+ public void execute(GpsMeasurementsEvent.Listener listener) throws RemoteException {
+ listener.onGpsMeasurementsReceived(event);
+ }
+ };
- for (final GpsMeasurementsEvent.Listener listener : listeners) {
- listener.onGpsMeasurementsReceived(eventArgs);
- }
+ foreach(operation);
}
}
}
diff --git a/location/java/android/location/GpsNavigationMessage.java b/location/java/android/location/GpsNavigationMessage.java
new file mode 100644
index 0000000..2eb4708
--- /dev/null
+++ b/location/java/android/location/GpsNavigationMessage.java
@@ -0,0 +1,276 @@
+/*
+ * 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 android.util.Log;
+
+import java.security.InvalidParameterException;
+
+/**
+ * A class containing a GPS satellite Navigation Message.
+ *
+ * @hide
+ */
+public class GpsNavigationMessage implements Parcelable {
+ private static final String TAG = "GpsNavigationMessage";
+ private static final byte[] EMPTY_ARRAY = new byte[0];
+
+ // The following enumerations must be in sync with the values declared in gps.h
+
+ /**
+ * The type of the navigation message is not available or unknown.
+ */
+ public static final byte TYPE_UNKNOWN = 0;
+
+ /**
+ * The Navigation Message is of type L1 C/A.
+ */
+ public static final byte TYPE_L1CA = 1;
+
+ /**
+ * The Navigation Message is of type L1-CNAV.
+ */
+ public static final byte TYPE_L2CNAV = 2;
+
+ /**
+ * The Navigation Message is of type L5-CNAV.
+ */
+ public static final byte TYPE_L5CNAV = 3;
+
+ /**
+ * The Navigation Message is of type CNAV-2.
+ */
+ public static final byte TYPE_CNAV2 = 4;
+
+ // End enumerations in sync with gps.h
+
+ private byte mType;
+ private byte mPrn;
+ private short mMessageId;
+ private short mSubmessageId;
+ private byte[] mData;
+
+ GpsNavigationMessage() {
+ initialize();
+ }
+
+ /**
+ * Sets all contents to the values stored in the provided object.
+ */
+ public void set(GpsNavigationMessage navigationMessage) {
+ mType = navigationMessage.mType;
+ mPrn = navigationMessage.mPrn;
+ mMessageId = navigationMessage.mMessageId;
+ mSubmessageId = navigationMessage.mSubmessageId;
+ mData = navigationMessage.mData;
+ }
+
+ /**
+ * Resets all the contents to its original state.
+ */
+ public void reset() {
+ initialize();
+ }
+
+ /**
+ * Gets the type of the navigation message contained in the object.
+ */
+ public byte getType() {
+ return mType;
+ }
+
+ /**
+ * Sets the type of the navigation message.
+ */
+ public void setType(byte value) {
+ switch (value) {
+ case TYPE_UNKNOWN:
+ case TYPE_L1CA:
+ case TYPE_L2CNAV:
+ case TYPE_L5CNAV:
+ case TYPE_CNAV2:
+ mType = value;
+ break;
+ default:
+ Log.d(TAG, "Sanitizing invalid 'type': " + value);
+ mType = TYPE_UNKNOWN;
+ break;
+ }
+ }
+
+ /**
+ * Gets a string representation of the 'type'.
+ * For internal and logging use only.
+ */
+ private String getTypeString() {
+ switch (mType) {
+ case TYPE_UNKNOWN:
+ return "Unknown";
+ case TYPE_L1CA:
+ return "L1 C/A";
+ case TYPE_L2CNAV:
+ return "L2-CNAV";
+ case TYPE_L5CNAV:
+ return "L5-CNAV";
+ case TYPE_CNAV2:
+ return "CNAV-2";
+ default:
+ return "<Invalid>";
+ }
+ }
+
+ /**
+ * Gets the Pseudo-random number.
+ * Range: [1, 32].
+ */
+ public byte getPrn() {
+ return mPrn;
+ }
+
+ /**
+ * Sets the Pseud-random number.
+ */
+ public void setPrn(byte value) {
+ mPrn = value;
+ }
+
+ /**
+ * Gets the Message Identifier.
+ * It provides an index so the complete Navigation Message can be assembled. i.e. for L1 C/A
+ * subframe 4 and 5, this value corresponds to the 'frame id' of the navigation message.
+ * Subframe 1, 2, 3 does not contain a 'frame id' and this might be reported as -1.
+ */
+ public short getMessageId() {
+ return mMessageId;
+ }
+
+ /**
+ * Sets the Message Identifier.
+ */
+ public void setMessageId(short value) {
+ mMessageId = value;
+ }
+
+ /**
+ * Gets the Sub-message Identifier.
+ * If required by {@link #getType()}, this value contains a sub-index within the current message
+ * (or frame) that is being transmitted. i.e. for L1 C/A the sub-message identifier corresponds
+ * to the sub-frame Id of the navigation message.
+ */
+ public short getSubmessageId() {
+ return mSubmessageId;
+ }
+
+ /**
+ * Sets the Sub-message identifier.
+ */
+ public void setSubmessageId(short value) {
+ mSubmessageId = value;
+ }
+
+ /**
+ * Gets the data associated with the Navigation Message.
+ * The bytes (or words) specified using big endian format (MSB first).
+ */
+ @NonNull
+ public byte[] getData() {
+ return mData;
+ }
+
+ /**
+ * Sets the data associated with the Navigation Message.
+ */
+ public void setData(byte[] value) {
+ if (value == null) {
+ throw new InvalidParameterException("Data must be a non-null array");
+ }
+
+ mData = value;
+ }
+
+ public static final Creator<GpsNavigationMessage> CREATOR =
+ new Creator<GpsNavigationMessage>() {
+ @Override
+ public GpsNavigationMessage createFromParcel(Parcel parcel) {
+ GpsNavigationMessage navigationMessage = new GpsNavigationMessage();
+
+ navigationMessage.setType(parcel.readByte());
+ navigationMessage.setPrn(parcel.readByte());
+ navigationMessage.setMessageId((short) parcel.readInt());
+ navigationMessage.setSubmessageId((short) parcel.readInt());
+
+ int dataLength = parcel.readInt();
+ byte[] data = new byte[dataLength];
+ parcel.readByteArray(data);
+ navigationMessage.setData(data);
+
+ return navigationMessage;
+ }
+
+ @Override
+ public GpsNavigationMessage[] newArray(int size) {
+ return new GpsNavigationMessage[size];
+ }
+ };
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeByte(mType);
+ parcel.writeByte(mPrn);
+ parcel.writeInt(mMessageId);
+ parcel.writeInt(mSubmessageId);
+ parcel.writeInt(mData.length);
+ parcel.writeByteArray(mData);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ final String format = " %-15s = %s\n";
+ StringBuilder builder = new StringBuilder("GpsNavigationMessage:\n");
+
+ builder.append(String.format(format, "Type", getTypeString()));
+ builder.append(String.format(format, "Prn", mPrn));
+ builder.append(String.format(format, "MessageId", mMessageId));
+ builder.append(String.format(format, "SubmessageId", mSubmessageId));
+
+ builder.append(String.format(format, "Data", "{"));
+ String prefix = " ";
+ for(byte value : mData) {
+ builder.append(prefix);
+ builder.append(value);
+ prefix = ", ";
+ }
+ builder.append(" }");
+
+ return builder.toString();
+ }
+
+ private void initialize() {
+ mType = TYPE_UNKNOWN;
+ mPrn = 0;
+ mMessageId = -1;
+ mSubmessageId = -1;
+ mData = EMPTY_ARRAY;
+ }
+}
diff --git a/location/java/android/location/GpsNavigationMessageEvent.aidl b/location/java/android/location/GpsNavigationMessageEvent.aidl
new file mode 100644
index 0000000..f84c2f7
--- /dev/null
+++ b/location/java/android/location/GpsNavigationMessageEvent.aidl
@@ -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 GpsNavigationMessageEvent;
diff --git a/location/java/android/location/GpsNavigationMessageEvent.java b/location/java/android/location/GpsNavigationMessageEvent.java
new file mode 100644
index 0000000..50ffa75
--- /dev/null
+++ b/location/java/android/location/GpsNavigationMessageEvent.java
@@ -0,0 +1,92 @@
+/*
+ * 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 navigation message event.
+ * Events are delivered to registered instances of {@link Listener}.
+ *
+ * @hide
+ */
+public class GpsNavigationMessageEvent implements Parcelable {
+ private final GpsNavigationMessage mNavigationMessage;
+
+ /**
+ * Used for receiving GPS satellite Navigation Messages from the GPS engine.
+ * You can implement this interface and call
+ * {@link LocationManager#addGpsNavigationMessageListener}.
+ *
+ * @hide
+ */
+ public interface Listener {
+ void onGpsNavigationMessageReceived(GpsNavigationMessageEvent event);
+ }
+
+ public GpsNavigationMessageEvent(GpsNavigationMessage message) {
+ if (message == null) {
+ throw new InvalidParameterException("Parameter 'message' must not be null.");
+ }
+ mNavigationMessage = message;
+ }
+
+ @NonNull
+ public GpsNavigationMessage getNavigationMessage() {
+ return mNavigationMessage;
+ }
+
+ public static final Creator<GpsNavigationMessageEvent> CREATOR =
+ new Creator<GpsNavigationMessageEvent>() {
+ @Override
+ public GpsNavigationMessageEvent createFromParcel(Parcel in) {
+ ClassLoader classLoader = getClass().getClassLoader();
+ GpsNavigationMessage navigationMessage = in.readParcelable(classLoader);
+ return new GpsNavigationMessageEvent(navigationMessage);
+ }
+
+ @Override
+ public GpsNavigationMessageEvent[] newArray(int size) {
+ return new GpsNavigationMessageEvent[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelable(mNavigationMessage, flags);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("[ GpsNavigationMessageEvent:\n\n");
+ builder.append(mNavigationMessage.toString());
+ builder.append("\n]");
+ return builder.toString();
+ }
+}
diff --git a/location/java/android/location/GpsNavigationMessageListenerTransport.java b/location/java/android/location/GpsNavigationMessageListenerTransport.java
new file mode 100644
index 0000000..ec4812b
--- /dev/null
+++ b/location/java/android/location/GpsNavigationMessageListenerTransport.java
@@ -0,0 +1,69 @@
+/*
+ * 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.content.Context;
+import android.os.RemoteException;
+
+/**
+ * A handler class to manage transport listeners for {@link GpsNavigationMessageEvent.Listener}.
+ *
+ * @hide
+ */
+class GpsNavigationMessageListenerTransport
+ extends LocalListenerHelper<GpsNavigationMessageEvent.Listener> {
+ private final Context mContext;
+ private final ILocationManager mLocationManager;
+
+ private final IGpsNavigationMessageListener mListenerTransport = new ListenerTransport();
+
+ public GpsNavigationMessageListenerTransport(
+ Context context,
+ ILocationManager locationManager) {
+ super("GpsNavigationMessageListenerTransport");
+ mContext = context;
+ mLocationManager = locationManager;
+ }
+
+ @Override
+ protected boolean registerWithServer() throws RemoteException {
+ return mLocationManager.addGpsNavigationMessageListener(
+ mListenerTransport,
+ mContext.getPackageName());
+ }
+
+ @Override
+ protected void unregisterFromServer() throws RemoteException {
+ mLocationManager.removeGpsNavigationMessageListener(mListenerTransport);
+ }
+
+ private class ListenerTransport extends IGpsNavigationMessageListener.Stub {
+ @Override
+ public void onGpsNavigationMessageReceived(final GpsNavigationMessageEvent event) {
+ ListenerOperation<GpsNavigationMessageEvent.Listener> operation =
+ new ListenerOperation<GpsNavigationMessageEvent.Listener>() {
+ @Override
+ public void execute(GpsNavigationMessageEvent.Listener listener)
+ throws RemoteException {
+ listener.onGpsNavigationMessageReceived(event);
+ }
+ };
+
+ foreach(operation);
+ }
+ }
+}
diff --git a/location/java/android/location/IGpsNavigationMessageListener.aidl b/location/java/android/location/IGpsNavigationMessageListener.aidl
new file mode 100644
index 0000000..18603fe
--- /dev/null
+++ b/location/java/android/location/IGpsNavigationMessageListener.aidl
@@ -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.GpsNavigationMessageEvent;
+
+/**
+ * {@hide}
+ */
+oneway interface IGpsNavigationMessageListener {
+ void onGpsNavigationMessageReceived(in GpsNavigationMessageEvent event);
+}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index a1acaf1..1501710 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -22,6 +22,7 @@ import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
import android.location.IGpsMeasurementsListener;
+import android.location.IGpsNavigationMessageListener;
import android.location.IGpsStatusListener;
import android.location.ILocationListener;
import android.location.Location;
@@ -63,6 +64,11 @@ interface ILocationManager
boolean addGpsMeasurementsListener(in IGpsMeasurementsListener listener, in String packageName);
boolean removeGpsMeasurementsListener(in IGpsMeasurementsListener listener);
+ boolean addGpsNavigationMessageListener(
+ in IGpsNavigationMessageListener listener,
+ in String packageName);
+ boolean removeGpsNavigationMessageListener(in IGpsNavigationMessageListener listener);
+
// --- deprecated ---
List<String> getAllProviders();
List<String> getProviders(in Criteria criteria, boolean enabledOnly);
diff --git a/location/java/android/location/LocalListenerHelper.java b/location/java/android/location/LocalListenerHelper.java
new file mode 100644
index 0000000..1f3bf67
--- /dev/null
+++ b/location/java/android/location/LocalListenerHelper.java
@@ -0,0 +1,109 @@
+/*
+ * 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.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * A base handler class to manage transport and local listeners.
+ *
+ * @hide
+ */
+abstract class LocalListenerHelper<TListener> {
+ private final HashSet<TListener> mListeners = new HashSet<TListener>();
+ private final String mTag;
+
+ protected LocalListenerHelper(String name) {
+ Preconditions.checkNotNull(name);
+ mTag = name;
+ }
+
+ public boolean add(@NonNull TListener 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 registeredWithService;
+ try {
+ registeredWithService = registerWithServer();
+ } catch (RemoteException e) {
+ Log.e(mTag, "Error handling first listener.", e);
+ return false;
+ }
+ if (!registeredWithService) {
+ Log.e(mTag, "Unable to register listener transport.");
+ return false;
+ }
+ }
+
+ if (mListeners.contains(listener)) {
+ return true;
+ }
+ mListeners.add(listener);
+ }
+ return true;
+ }
+
+ public void remove(@NonNull TListener listener) {
+ Preconditions.checkNotNull(listener);
+
+ synchronized (mListeners) {
+ boolean removed = mListeners.remove(listener);
+ boolean isLastRemoved = removed && mListeners.isEmpty();
+ if (isLastRemoved) {
+ try {
+ unregisterFromServer();
+ } catch (RemoteException e) {
+
+ }
+ }
+ }
+ }
+
+ protected abstract boolean registerWithServer() throws RemoteException;
+ protected abstract void unregisterFromServer() throws RemoteException;
+
+ protected interface ListenerOperation<TListener> {
+ void execute(TListener listener) throws RemoteException;
+ }
+
+ protected void foreach(ListenerOperation operation) {
+ Collection<TListener> listeners;
+ synchronized (mListeners) {
+ listeners = new ArrayList<TListener>(mListeners);
+ }
+
+ for (TListener listener : listeners) {
+ try {
+ operation.execute(listener);
+ } catch (RemoteException e) {
+ Log.e(mTag, "Error in monitored listener.", e);
+ // don't return, give a fair chance to all listeners to receive the event
+ }
+ }
+ }
+}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index d6a8fb8..082a158 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -59,6 +59,7 @@ public class LocationManager {
private final Context mContext;
private final ILocationManager mService;
private final GpsMeasurementListenerTransport mGpsMeasurementListenerTransport;
+ private final GpsNavigationMessageListenerTransport mGpsNavigationMessageListenerTransport;
private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners =
new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>();
private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
@@ -310,6 +311,8 @@ public class LocationManager {
mService = service;
mContext = context;
mGpsMeasurementListenerTransport = new GpsMeasurementListenerTransport(mContext, mService);
+ mGpsNavigationMessageListenerTransport =
+ new GpsNavigationMessageListenerTransport(mContext, mService);
}
private LocationProvider createProvider(String name, ProviderProperties properties) {
@@ -1573,7 +1576,7 @@ public class LocationManager {
/**
* Adds a GPS Measurement listener.
*
- * @param listener a {@link android.location.GpsMeasurementsEvent.Listener} object to register.
+ * @param listener a {@link GpsMeasurementsEvent.Listener} object to register.
* @return {@code true} if the listener was successfully registered, {@code false} otherwise.
*
* @hide
@@ -1593,6 +1596,30 @@ public class LocationManager {
mGpsMeasurementListenerTransport.remove(listener);
}
+ /**
+ * Adds a GPS Navigation Message listener.
+ *
+ * @param listener a {@link GpsNavigationMessageEvent.Listener} object to register.
+ * @return {@code true} if the listener was successfully registered, {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {
+ return mGpsNavigationMessageListenerTransport.add(listener);
+ }
+
+ /**
+ * Removes a GPS Navigation Message listener.
+ *
+ * @param listener a {@link GpsNavigationMessageEvent.Listener} object to remove.
+ *
+ * @hide
+ */
+ public void removeGpsNavigationMessageListener(
+ GpsNavigationMessageEvent.Listener listener) {
+ mGpsNavigationMessageListenerTransport.remove(listener);
+ }
+
/**
* Retrieves information about the current status of the GPS engine.
* This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index bae2d22..3a4e2ee 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -28,6 +28,7 @@ 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.GpsNavigationMessageProvider;
import com.android.server.location.LocationBlacklist;
import com.android.server.location.LocationFudger;
import com.android.server.location.LocationProviderInterface;
@@ -60,6 +61,7 @@ import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
import android.location.IGpsMeasurementsListener;
+import android.location.IGpsNavigationMessageListener;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
import android.location.ILocationListener;
@@ -159,6 +161,7 @@ public class LocationManagerService extends ILocationManager.Stub {
private PassiveProvider mPassiveProvider; // track passive provider for special cases
private LocationBlacklist mBlacklist;
private GpsMeasurementsProvider mGpsMeasurementsProvider;
+ private GpsNavigationMessageProvider mGpsNavigationMessageProvider;
// --- fields below are protected by mLock ---
// Set of providers that are explicitly enabled
@@ -409,6 +412,7 @@ public class LocationManagerService extends ILocationManager.Stub {
mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
}
mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
+ mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider();
/*
Load package name(s) containing location provider support.
@@ -1847,7 +1851,6 @@ public class LocationManagerService extends ILocationManager.Stub {
if (!hasLocationAccess) {
return false;
}
-
return mGpsMeasurementsProvider.addListener(listener);
}
@@ -1857,6 +1860,35 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
+ public boolean addGpsNavigationMessageListener(
+ IGpsNavigationMessageListener 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 mGpsNavigationMessageProvider.addListener(listener);
+ }
+
+ @Override
+ public boolean removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) {
+ return mGpsNavigationMessageProvider.removeListener(listener);
+ }
+
+ @Override
public boolean sendExtraCommand(String provider, String command, Bundle extras) {
if (provider == null) {
// throw NullPointerException to remain compatible with previous implementation
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 09873c7..058a23e 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -38,6 +38,7 @@ import android.hardware.location.GeofenceHardwareImpl;
import android.location.Criteria;
import android.location.FusedBatchOptions;
import android.location.GpsMeasurementsEvent;
+import android.location.GpsNavigationMessageEvent;
import android.location.IGpsGeofenceHardware;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
@@ -324,6 +325,14 @@ public class GpsLocationProvider implements LocationProviderInterface {
protected boolean isSupported() {
return GpsLocationProvider.isSupported();
}
+
+ @Override
+ protected boolean registerWithService() {
+ return true;
+ }
+
+ @Override
+ protected void unregisterFromService() {}
};
// Handler for processing events
@@ -374,16 +383,34 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
@Override
- protected void onFirstListenerAdded() {
- native_start_measurement_collection();
+ protected boolean registerWithService() {
+ return native_start_measurement_collection();
}
@Override
- protected void onLastListenerRemoved() {
+ protected void unregisterFromService() {
native_stop_measurement_collection();
}
};
+ private final GpsNavigationMessageProvider mGpsNavigationMessageProvider =
+ new GpsNavigationMessageProvider() {
+ @Override
+ protected boolean isSupported() {
+ return native_is_navigation_message_supported();
+ }
+
+ @Override
+ protected boolean registerWithService() {
+ return native_start_navigation_message_collection();
+ }
+
+ @Override
+ protected void unregisterFromService() {
+ native_stop_navigation_message_collection();
+ }
+ };
+
public IGpsStatusProvider getGpsStatusProvider() {
return mGpsStatusProvider;
}
@@ -396,6 +423,10 @@ public class GpsLocationProvider implements LocationProviderInterface {
return mGpsMeasurementsProvider;
}
+ public GpsNavigationMessageProvider getGpsNavigationMessageProvider() {
+ return mGpsNavigationMessageProvider;
+ }
+
private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -1357,13 +1388,20 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
/**
- * called from native code - Gps Data callback
+ * called from native code - Gps measurements callback
*/
private void reportMeasurementData(GpsMeasurementsEvent event) {
mGpsMeasurementsProvider.onMeasurementsAvailable(event);
}
/**
+ * called from native code - GPS navigation message callback
+ */
+ private void reportNavigationMessage(GpsNavigationMessageEvent event) {
+ mGpsNavigationMessageProvider.onNavigationMessageAvailable(event);
+ }
+
+ /**
* called from native code to inform us what the GPS engine capabilities are
*/
private void setEngineCapabilities(int capabilities) {
@@ -1954,6 +1992,11 @@ public class GpsLocationProvider implements LocationProviderInterface {
// 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();
+ private native boolean native_start_measurement_collection();
+ private native boolean native_stop_measurement_collection();
+
+ // Gps Navigation message support.
+ private static native boolean native_is_navigation_message_supported();
+ private native boolean native_start_navigation_message_collection();
+ private native boolean native_stop_navigation_message_collection();
}
diff --git a/services/core/java/com/android/server/location/GpsMeasurementsProvider.java b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
index 001f638..1c48257 100644
--- a/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
@@ -29,6 +29,9 @@ import android.os.RemoteException;
*/
public abstract class GpsMeasurementsProvider
extends RemoteListenerHelper<IGpsMeasurementsListener> {
+ public GpsMeasurementsProvider() {
+ super("GpsMeasurementsProvider");
+ }
public void onMeasurementsAvailable(final GpsMeasurementsEvent event) {
ListenerOperation<IGpsMeasurementsListener> operation =
diff --git a/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java b/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java
new file mode 100644
index 0000000..fca7378
--- /dev/null
+++ b/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java
@@ -0,0 +1,48 @@
+/*
+ * 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.GpsNavigationMessageEvent;
+import android.location.IGpsNavigationMessageListener;
+import android.os.RemoteException;
+
+/**
+ * An base implementation for GPS navigation messages provider.
+ * It abstracts out the responsibility of handling listeners, while still allowing technology
+ * specific implementations to be built.
+ *
+ * @hide
+ */
+public abstract class GpsNavigationMessageProvider
+ extends RemoteListenerHelper<IGpsNavigationMessageListener> {
+ public GpsNavigationMessageProvider() {
+ super("GpsNavigationMessageProvider");
+ }
+
+ public void onNavigationMessageAvailable(final GpsNavigationMessageEvent event) {
+ ListenerOperation<IGpsNavigationMessageListener> operation =
+ new ListenerOperation<IGpsNavigationMessageListener>() {
+ @Override
+ public void execute(IGpsNavigationMessageListener listener)
+ throws RemoteException {
+ listener.onGpsNavigationMessageReceived(event);
+ }
+ };
+
+ foreach(operation);
+ }
+}
diff --git a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
index b741e75..27cf3d8 100644
--- a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
@@ -23,6 +23,10 @@ import android.os.RemoteException;
* Implementation of a handler for {@link IGpsStatusListener}.
*/
abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusListener> {
+ public GpsStatusListenerHelper() {
+ super("GpsStatusListenerHelper");
+ }
+
public void onFirstFix(final int timeToFirstFix) {
Operation operation = new Operation() {
@Override
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
index 79335f7..451af18 100644
--- a/services/core/java/com/android/server/location/RemoteListenerHelper.java
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -32,16 +32,19 @@ 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 String mTag;
private final HashMap<IBinder, LinkedListener> mListenerMap =
new HashMap<IBinder, LinkedListener>();
+ protected RemoteListenerHelper(String name) {
+ Preconditions.checkNotNull(name);
+ mTag = name;
+ }
+
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.");
+ Log.e(mTag, "Refused to add listener, the feature is not supported.");
return false;
}
@@ -58,13 +61,17 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
} 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);
+ Log.e(mTag, "Remote listener already died.", e);
return false;
}
mListenerMap.put(binder, deathListener);
if (mListenerMap.size() == 1) {
- onFirstListenerAdded();
+ if (!registerWithService()) {
+ Log.e(mTag, "RegisterWithService failed, listener will be removed.");
+ removeListener(listener);
+ return false;
+ }
}
}
@@ -73,9 +80,8 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
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.");
+ Log.e(mTag, "Refused to remove listener, the feature is not supported.");
return false;
}
@@ -84,26 +90,19 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
synchronized (mListenerMap) {
linkedListener = mListenerMap.remove(binder);
if (mListenerMap.isEmpty() && linkedListener != null) {
- onLastListenerRemoved();
+ unregisterFromService();
}
}
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 abstract boolean registerWithService();
+ protected abstract void unregisterFromService();
protected interface ListenerOperation<TListener extends IInterface> {
void execute(TListener listener) throws RemoteException;
@@ -121,7 +120,7 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
try {
operation.execute(listener);
} catch (RemoteException e) {
- Log.e(TAG, "Error in monitored listener.", e);
+ Log.e(mTag, "Error in monitored listener.", e);
removeListener(listener);
}
}
@@ -141,7 +140,7 @@ abstract class RemoteListenerHelper<TListener extends IInterface> {
@Override
public void binderDied() {
- Log.d(TAG, "Remote Listener died: " + mListener);
+ Log.d(mTag, "Remote Listener died: " + mListener);
removeListener(mListener);
}
}
diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
index 8bb6e8a..46327d7 100644
--- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -53,6 +53,7 @@ static jmethodID method_reportGeofenceRemoveStatus;
static jmethodID method_reportGeofencePauseStatus;
static jmethodID method_reportGeofenceResumeStatus;
static jmethodID method_reportMeasurementData;
+static jmethodID method_reportNavigationMessages;
static const GpsInterface* sGpsInterface = NULL;
static const GpsXtraInterface* sGpsXtraInterface = NULL;
@@ -62,6 +63,7 @@ static const GpsDebugInterface* sGpsDebugInterface = NULL;
static const AGpsRilInterface* sAGpsRilInterface = NULL;
static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
static const GpsMeasurementInterface* sGpsMeasurementInterface = NULL;
+static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL;
// temporary storage for GPS callbacks
static GpsSvStatus sGpsSvStatus;
@@ -447,6 +449,10 @@ static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env,
clazz,
"reportMeasurementData",
"(Landroid/location/GpsMeasurementsEvent;)V");
+ method_reportNavigationMessages = env->GetMethodID(
+ clazz,
+ "reportNavigationMessage",
+ "(Landroid/location/GpsNavigationMessageEvent;)V");
err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {
@@ -472,6 +478,9 @@ static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env,
(const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE);
sGpsMeasurementInterface =
(const GpsMeasurementInterface*)sGpsInterface->get_extension(GPS_MEASUREMENT_INTERFACE);
+ sGpsNavigationMessageInterface =
+ (const GpsNavigationMessageInterface*)sGpsInterface->get_extension(
+ GPS_NAVIGATION_MESSAGE_INTERFACE);
}
}
@@ -1212,7 +1221,6 @@ static void measurement_callback(GpsData* data) {
checkAndClearExceptionFromCallback(env, __FUNCTION__);
} else {
ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%d", data->size);
- return;
}
}
@@ -1223,7 +1231,7 @@ GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
static jboolean android_location_GpsLocationProvider_is_measurement_supported(
JNIEnv* env,
- jobject obj) {
+ jclass clazz) {
if (sGpsMeasurementInterface != NULL) {
return JNI_TRUE;
}
@@ -1259,6 +1267,110 @@ static jboolean android_location_GpsLocationProvider_stop_measurement_collection
return JNI_TRUE;
}
+static jobject translate_gps_navigation_message(JNIEnv* env, GpsNavigationMessage* message) {
+ size_t dataLength = message->data_length;
+ uint8_t* data = message->data;
+ if (dataLength == 0 || data == NULL) {
+ ALOGE("Invalid Navigation Message found: data=%p, length=%d", data, dataLength);
+ return NULL;
+ }
+
+ jclass navigationMessageClass = env->FindClass("android/location/GpsNavigationMessage");
+ jmethodID navigationMessageCtor = env->GetMethodID(navigationMessageClass, "<init>", "()V");
+ jobject navigationMessageObject = env->NewObject(navigationMessageClass, navigationMessageCtor);
+
+ jmethodID setTypeMethod = env->GetMethodID(navigationMessageClass, "setType", "(B)V");
+ env->CallVoidMethod(navigationMessageObject, setTypeMethod, message->type);
+
+ jmethodID setPrnMethod = env->GetMethodID(navigationMessageClass, "setPrn", "(B)V");
+ env->CallVoidMethod(navigationMessageObject, setPrnMethod, message->prn);
+
+ jmethodID setMessageIdMethod = env->GetMethodID(navigationMessageClass, "setMessageId", "(S)V");
+ env->CallVoidMethod(navigationMessageObject, setMessageIdMethod, message->message_id);
+
+ jmethodID setSubmessageIdMethod =
+ env->GetMethodID(navigationMessageClass, "setSubmessageId", "(S)V");
+ env->CallVoidMethod(navigationMessageObject, setSubmessageIdMethod, message->submessage_id);
+
+ jbyteArray dataArray = env->NewByteArray(dataLength);
+ env->SetByteArrayRegion(dataArray, 0, dataLength, (jbyte*) data);
+ jmethodID setDataMethod = env->GetMethodID(navigationMessageClass, "setData", "([B)V");
+ env->CallVoidMethod(navigationMessageObject, setDataMethod, dataArray);
+
+ return navigationMessageObject;
+}
+
+static void navigation_message_callback(GpsNavigationMessage* message) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (message == NULL) {
+ ALOGE("Invalid Navigation Message provided to callback");
+ return;
+ }
+
+ if (message->size == sizeof(GpsNavigationMessage)) {
+ jobject navigationMessage = translate_gps_navigation_message(env, message);
+
+ jclass navigationMessageEventClass =
+ env->FindClass("android/location/GpsNavigationMessageEvent");
+ jmethodID navigationMessageEventCtor = env->GetMethodID(
+ navigationMessageEventClass,
+ "<init>",
+ "(Landroid/location/GpsNavigationMessage;)V");
+ jobject navigationMessageEvent = env->NewObject(
+ navigationMessageEventClass,
+ navigationMessageEventCtor,
+ navigationMessage);
+
+ env->CallVoidMethod(mCallbacksObj, method_reportNavigationMessages, navigationMessageEvent);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ } else {
+ ALOGE("Invalid GpsNavigationMessage size found: %d", message->size);
+ }
+}
+
+GpsNavigationMessageCallbacks sGpsNavigationMessageCallbacks = {
+ sizeof(GpsNavigationMessageCallbacks),
+ navigation_message_callback,
+};
+
+static jboolean android_location_GpsLocationProvider_is_navigation_message_supported(
+ JNIEnv* env,
+ jclass clazz) {
+ if(sGpsNavigationMessageInterface != NULL) {
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+}
+
+static jboolean android_location_GpsLocationProvider_start_navigation_message_collection(
+ JNIEnv* env,
+ jobject obj) {
+ if (sGpsNavigationMessageInterface == NULL) {
+ ALOGE("Navigation Message interface is not available.");
+ return JNI_FALSE;
+ }
+
+ int result = sGpsNavigationMessageInterface->init(&sGpsNavigationMessageCallbacks);
+ if (result != GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS) {
+ ALOGE("An error has been found in %s: %d", __FUNCTION__, result);
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+static jboolean android_location_GpsLocationProvider_stop_navigation_message_collection(
+ JNIEnv* env,
+ jobject obj) {
+ if (sGpsNavigationMessageInterface == NULL) {
+ ALOGE("Navigation Message interface is not available.");
+ return JNI_FALSE;
+ }
+
+ sGpsNavigationMessageInterface->close();
+ return JNI_TRUE;
+}
+
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
@@ -1336,7 +1448,16 @@ static JNINativeMethod sMethods[] = {
(void*) android_location_GpsLocationProvider_start_measurement_collection},
{"native_stop_measurement_collection",
"()Z",
- (void*) android_location_GpsLocationProvider_stop_measurement_collection}
+ (void*) android_location_GpsLocationProvider_stop_measurement_collection},
+ {"native_is_navigation_message_supported",
+ "()Z",
+ (void*) android_location_GpsLocationProvider_is_navigation_message_supported},
+ {"native_start_navigation_message_collection",
+ "()Z",
+ (void*) android_location_GpsLocationProvider_start_navigation_message_collection},
+ {"native_stop_navigation_message_collection",
+ "()Z",
+ (void*) android_location_GpsLocationProvider_stop_navigation_message_collection},
};
int register_android_server_location_GpsLocationProvider(JNIEnv* env)