summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordestradaa <destradaa@google.com>2013-07-12 15:43:36 -0700
committerdestradaa <destradaa@google.com>2013-08-08 15:27:38 -0700
commit1af4b0280af406cfc7eb46810f6b76e57b983e11 (patch)
tree1f7f8d5a86c8dcd42cb24474e93b58bb0775071e
parent8ffe17ae32e72e5d872a36d5048bf912d28e766f (diff)
downloadframeworks_base-1af4b0280af406cfc7eb46810f6b76e57b983e11.zip
frameworks_base-1af4b0280af406cfc7eb46810f6b76e57b983e11.tar.gz
frameworks_base-1af4b0280af406cfc7eb46810f6b76e57b983e11.tar.bz2
Add FlpHal layer to support Location Batching.
Change-Id: Ia3a57d869dfb3f067a1b95fa66d54f311ddcfdc3
-rw-r--r--Android.mk5
-rw-r--r--core/java/android/hardware/location/IFusedLocationHardware.aidl117
-rw-r--r--core/java/android/hardware/location/IFusedLocationHardwareSink.aidl41
-rw-r--r--location/java/android/location/FusedBatchOptions.aidl19
-rw-r--r--location/java/android/location/FusedBatchOptions.java135
-rw-r--r--location/java/android/location/IFusedGeofenceHardware.aidl93
-rw-r--r--location/java/android/location/IFusedProvider.aidl32
-rw-r--r--location/lib/java/com/android/location/provider/FusedLocationHardware.java202
-rw-r--r--location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java31
-rw-r--r--location/lib/java/com/android/location/provider/FusedProvider.java59
-rw-r--r--location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java106
-rw-r--r--services/java/com/android/server/LocationManagerService.java13
-rw-r--r--services/java/com/android/server/location/FlpHardwareProvider.java344
-rw-r--r--services/java/com/android/server/location/FusedLocationHardwareSecure.java119
-rw-r--r--services/java/com/android/server/location/FusedProxy.java116
-rw-r--r--services/jni/Android.mk1
-rw-r--r--services/jni/com_android_server_location_FlpHardwareProvider.cpp901
-rw-r--r--services/jni/onload.cpp2
18 files changed, 2336 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
index 7e34c84..df10876 100644
--- a/Android.mk
+++ b/Android.mk
@@ -128,6 +128,8 @@ LOCAL_SRC_FILES += \
core/java/android/hardware/display/IDisplayManagerCallback.aidl \
core/java/android/hardware/input/IInputManager.aidl \
core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
+ core/java/android/hardware/location/IFusedLocationHardware.aidl \
+ core/java/android/hardware/location/IFusedLocationHardwareSink.aidl \
core/java/android/hardware/location/IGeofenceHardware.aidl \
core/java/android/hardware/location/IGeofenceHardwareCallback.aidl \
core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
@@ -232,12 +234,14 @@ LOCAL_SRC_FILES += \
keystore/java/android/security/IKeyChainService.aidl \
location/java/android/location/ICountryDetector.aidl \
location/java/android/location/ICountryListener.aidl \
+ location/java/android/location/IFusedProvider.aidl \
location/java/android/location/IGeocodeProvider.aidl \
location/java/android/location/IGeofenceProvider.aidl \
location/java/android/location/IGpsStatusListener.aidl \
location/java/android/location/IGpsStatusProvider.aidl \
location/java/android/location/ILocationListener.aidl \
location/java/android/location/ILocationManager.aidl \
+ location/java/android/location/IFusedGeofenceHardware.aidl \
location/java/android/location/IGpsGeofenceHardware.aidl \
location/java/android/location/INetInitiatedListener.aidl \
location/java/com/android/internal/location/ILocationProvider.aidl \
@@ -379,6 +383,7 @@ aidl_files := \
frameworks/base/location/java/android/location/Geofence.aidl \
frameworks/base/location/java/android/location/Location.aidl \
frameworks/base/location/java/android/location/LocationRequest.aidl \
+ frameworks/base/location/java/android/location/FusedBatchOptions.aidl \
frameworks/base/location/java/com/android/internal/location/ProviderProperties.aidl \
frameworks/base/location/java/com/android/internal/location/ProviderRequest.aidl \
frameworks/base/telephony/java/android/telephony/ServiceState.aidl \
diff --git a/core/java/android/hardware/location/IFusedLocationHardware.aidl b/core/java/android/hardware/location/IFusedLocationHardware.aidl
new file mode 100644
index 0000000..382c12c
--- /dev/null
+++ b/core/java/android/hardware/location/IFusedLocationHardware.aidl
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013, 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/license/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.hardware.location;
+
+import android.hardware.location.IFusedLocationHardwareSink;
+import android.location.FusedBatchOptions;
+
+/**
+ * Fused Location hardware interface.
+ * This interface is the basic set of supported functionality by Fused Hardware
+ * modules that offer Location batching capabilities.
+ *
+ * @hide
+ */
+interface IFusedLocationHardware {
+ /**
+ * Registers a sink with the Location Hardware object.
+ *
+ * @param eventSink The sink to register.
+ */
+ void registerSink(in IFusedLocationHardwareSink eventSink);
+
+ /**
+ * Unregisters a sink with the Location Hardware object.
+ *
+ * @param eventSink The sink to unregister.
+ */
+ void unregisterSink(in IFusedLocationHardwareSink eventSink);
+
+ /**
+ * Provides access to the batch size available in Hardware.
+ *
+ * @return The batch size the hardware supports.
+ */
+ int getSupportedBatchSize();
+
+ /**
+ * Requests the Hardware to start batching locations.
+ *
+ * @param id An Id associated with the request.
+ * @param batchOptions The options required for batching.
+ *
+ * @throws RuntimeException if the request Id exists.
+ */
+ void startBatching(in int id, in FusedBatchOptions batchOptions);
+
+ /**
+ * Requests the Hardware to stop batching for the given Id.
+ *
+ * @param id The request that needs to be stopped.
+ * @throws RuntimeException if the request Id is unknown.
+ */
+ void stopBatching(in int id);
+
+ /**
+ * Updates a batching operation in progress.
+ *
+ * @param id The Id of the operation to update.
+ * @param batchOptions The options to apply to the given operation.
+ *
+ * @throws RuntimeException if the Id of the request is unknown.
+ */
+ void updateBatchingOptions(in int id, in FusedBatchOptions batchOptions);
+
+ /**
+ * Requests the most recent locations available in Hardware.
+ * This operation does not dequeue the locations, so still other batching
+ * events will continue working.
+ *
+ * @param batchSizeRequested The number of locations requested.
+ */
+ void requestBatchOfLocations(in int batchSizeRequested);
+
+ /**
+ * Flags if the Hardware supports injection of diagnostic data.
+ *
+ * @return True if data injection is supported, false otherwise.
+ */
+ boolean supportsDiagnosticDataInjection();
+
+ /**
+ * Injects diagnostic data into the Hardware subsystem.
+ *
+ * @param data The data to inject.
+ * @throws RuntimeException if injection is not supported.
+ */
+ void injectDiagnosticData(in String data);
+
+ /**
+ * Flags if the Hardware supports injection of device context information.
+ *
+ * @return True if device context injection is supported, false otherwise.
+ */
+ boolean supportsDeviceContextInjection();
+
+ /**
+ * Injects device context information into the Hardware subsystem.
+ *
+ * @param deviceEnabledContext The context to inject.
+ * @throws RuntimeException if injection is not supported.
+ */
+ void injectDeviceContext(in int deviceEnabledContext);
+}
diff --git a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
new file mode 100644
index 0000000..a11d8ab
--- /dev/null
+++ b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013, 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/license/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.hardware.location;
+
+import android.location.Location;
+
+/**
+ * Fused Location hardware event sink interface.
+ * This interface defines the set of events that the FusedLocationHardware provides.
+ *
+ * @hide
+ */
+interface IFusedLocationHardwareSink {
+ /**
+ * Event generated when a batch of location information is available.
+ *
+ * @param locations The batch of location information available.
+ */
+ void onLocationAvailable(in Location[] locations);
+
+ /**
+ * Event generated from FLP HAL to provide diagnostic data to the platform.
+ *
+ * @param data The diagnostic data provided by FLP HAL.
+ */
+ void onDiagnosticDataAvailable(in String data);
+} \ No newline at end of file
diff --git a/location/java/android/location/FusedBatchOptions.aidl b/location/java/android/location/FusedBatchOptions.aidl
new file mode 100644
index 0000000..94cb6e1
--- /dev/null
+++ b/location/java/android/location/FusedBatchOptions.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013, 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 FusedBatchOptions; \ No newline at end of file
diff --git a/location/java/android/location/FusedBatchOptions.java b/location/java/android/location/FusedBatchOptions.java
new file mode 100644
index 0000000..623d707
--- /dev/null
+++ b/location/java/android/location/FusedBatchOptions.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2013 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 data class representing a set of options to configure batching sessions.
+ * @hide
+ */
+public class FusedBatchOptions implements Parcelable {
+ private volatile long mPeriodInNS = 0;
+ private volatile int mSourcesToUse = 0;
+ private volatile int mFlags = 0;
+
+ // the default value is set to request fixes at no cost
+ private volatile double mMaxPowerAllocationInMW = 0;
+
+ /*
+ * Getters and setters for properties needed to hold the options.
+ */
+ public void setMaxPowerAllocationInMW(double value) {
+ mMaxPowerAllocationInMW = value;
+ }
+
+ public double getMaxPowerAllocationInMW() {
+ return mMaxPowerAllocationInMW;
+ }
+
+ public void setPeriodInNS(long value) {
+ mPeriodInNS = value;
+ }
+
+ public long getPeriodInNS() {
+ return mPeriodInNS;
+ }
+
+ public void setSourceToUse(int source) {
+ mSourcesToUse |= source;
+ }
+
+ public void resetSourceToUse(int source) {
+ mSourcesToUse &= ~source;
+ }
+
+ public boolean isSourceToUseSet(int source) {
+ return (mSourcesToUse & source) != 0;
+ }
+
+ public int getSourcesToUse() {
+ return mSourcesToUse;
+ }
+
+ public void setFlag(int flag) {
+ mFlags |= flag;
+ }
+
+ public void resetFlag(int flag) {
+ mFlags &= ~flag;
+ }
+
+ public boolean isFlagSet(int flag) {
+ return (mFlags & flag) != 0;
+ }
+
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * Definition of enum flag sets needed by this class.
+ * Such values need to be kept in sync with the ones in fused_location.h
+ */
+ public static final class SourceTechnologies {
+ public static int GNSS = 1<<0;
+ public static int WIFI = 1<<1;
+ public static int SENSORS = 1<<2;
+ public static int CELL = 1<<3;
+ public static int BLUETOOTH = 1<<4;
+ }
+
+ public static final class BatchFlags {
+ public static int WAKEUP_ON_FIFO_FULL = 1<<0;
+ public static int CALLBACK_ON_LOCATION_FIX = 1<<1;
+ }
+
+ /*
+ * Method definitions to support Parcelable operations.
+ */
+ public static final Parcelable.Creator<FusedBatchOptions> CREATOR =
+ new Parcelable.Creator<FusedBatchOptions>() {
+ @Override
+ public FusedBatchOptions createFromParcel(Parcel parcel) {
+ FusedBatchOptions options = new FusedBatchOptions();
+ options.setMaxPowerAllocationInMW(parcel.readDouble());
+ options.setPeriodInNS(parcel.readLong());
+ options.setSourceToUse(parcel.readInt());
+ options.setFlag(parcel.readInt());
+ return options;
+ }
+
+ @Override
+ public FusedBatchOptions[] newArray(int size) {
+ return new FusedBatchOptions[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeDouble(mMaxPowerAllocationInMW);
+ parcel.writeLong(mPeriodInNS);
+ parcel.writeInt(mSourcesToUse);
+ parcel.writeInt(mFlags);
+ }
+}
diff --git a/location/java/android/location/IFusedGeofenceHardware.aidl b/location/java/android/location/IFusedGeofenceHardware.aidl
new file mode 100644
index 0000000..9dbf1f4
--- /dev/null
+++ b/location/java/android/location/IFusedGeofenceHardware.aidl
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2013, 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/license/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.Geofence;
+
+/**
+ * Fused Geofence Hardware interface.
+ *
+ * <p>This interface is the basic set of supported functionality by Fused Hardware modules that offer
+ * Geofencing capabilities.
+ *
+ * All operations are asynchronous and the status codes can be obtained via a set of callbacks.
+ *
+ * @hide
+ */
+interface IFusedGeofenceHardware {
+ /**
+ * Flags if the interface functionality is supported by the platform.
+ *
+ * @return true if the functionality is supported, false otherwise.
+ */
+ boolean isSupported();
+
+ /**
+ * Adds a given list of geofences to the system.
+ *
+ * @param geofenceIdsArray The list of geofence Ids to add.
+ * @param geofencesArray the list of geofences to add.
+ */
+ // TODO: [GeofenceIntegration] GeofenceHardwareRequest is not a parcelable class exposed in aidl
+ void addGeofences(in int[] geofenceIdsArray, in Geofence[] geofencesArray);
+
+ /**
+ * Removes a give list of geofences from the system.
+ *
+ * @param geofences The list of geofences to remove.
+ */
+ void removeGeofences(in int[] geofenceIds);
+
+ /**
+ * Pauses monitoring a particular geofence.
+ *
+ * @param geofenceId The geofence to pause monitoring.
+ */
+ void pauseMonitoringGeofence(in int geofenceId);
+
+ /**
+ * Resumes monitoring a particular geofence.
+ *
+ * @param geofenceid The geofence to resume monitoring.
+ * @param transitionsToMonitor The transitions to monitor upon resume.
+ *
+ * Remarks: keep naming of geofence request options consistent with the naming used in
+ * GeofenceHardwareRequest
+ */
+ void resumeMonitoringGeofence(in int geofenceId, in int monitorTransitions);
+
+ /**
+ * Modifies the request options if a geofence that is already known by the
+ * system.
+ *
+ * @param geofenceId The geofence to modify.
+ * @param lastTransition The last known transition state of
+ * the geofence.
+ * @param monitorTransitions The set of transitions to monitor.
+ * @param notificationResponsiveness The notification responsivness needed.
+ * @param unknownTimer The time span associated with the
+ *
+ * Remarks: keep the options as separate fields to be able to leverage the class
+ * GeofenceHardwareRequest without any changes
+ */
+ void modifyGeofenceOptions(
+ in int geofenceId,
+ in int lastTransition,
+ in int monitorTransitions,
+ in int notificationResponsiveness,
+ in int unknownTimer);
+}
diff --git a/location/java/android/location/IFusedProvider.aidl b/location/java/android/location/IFusedProvider.aidl
new file mode 100644
index 0000000..8870d2a
--- /dev/null
+++ b/location/java/android/location/IFusedProvider.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2013 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.hardware.location.IFusedLocationHardware;
+
+/**
+ * Interface definition for Location providers that require FLP services.
+ * @hide
+ */
+interface IFusedProvider {
+ /**
+ * Provides access to a FusedLocationHardware instance needed for the provider to work.
+ *
+ * @param instance The FusedLocationHardware available for the provider to use.
+ */
+ void onFusedLocationHardwareChange(in IFusedLocationHardware instance);
+} \ No newline at end of file
diff --git a/location/lib/java/com/android/location/provider/FusedLocationHardware.java b/location/lib/java/com/android/location/provider/FusedLocationHardware.java
new file mode 100644
index 0000000..abea9fb
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/FusedLocationHardware.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2013 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 CONDITIOS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.location.provider;
+
+import android.hardware.location.IFusedLocationHardware;
+import android.hardware.location.IFusedLocationHardwareSink;
+
+import android.location.Location;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/**
+ * Class that exposes IFusedLocationHardware functionality to unbundled services.
+ * Namely this is used by GmsCore Fused Location Provider.
+ */
+public final class FusedLocationHardware {
+ private final String TAG = "FusedLocationHardware";
+
+ private IFusedLocationHardware mLocationHardware;
+ ArrayList<FusedLocationHardwareSink> mSinkList = new ArrayList<FusedLocationHardwareSink>();
+
+ private IFusedLocationHardwareSink mInternalSink = new IFusedLocationHardwareSink.Stub() {
+ @Override
+ public void onLocationAvailable(Location[] locations) {
+ dispatchLocations(locations);
+ }
+
+ @Override
+ public void onDiagnosticDataAvailable(String data) {
+ dispatchDiagnosticData(data);
+ }
+ };
+
+ public FusedLocationHardware(IFusedLocationHardware locationHardware) {
+ mLocationHardware = locationHardware;
+ }
+
+ /*
+ * Methods to provide a Facade for IFusedLocationHardware
+ */
+ public void registerSink(FusedLocationHardwareSink sink) {
+ if(sink == null) {
+ return;
+ }
+
+ boolean registerSink = false;
+ synchronized (mSinkList) {
+ // register only on first insertion
+ registerSink = mSinkList.size() == 0;
+ // guarantee uniqueness
+ if(!mSinkList.contains(sink)) {
+ mSinkList.add(sink);
+ }
+ }
+
+ if(registerSink) {
+ try {
+ mLocationHardware.registerSink(mInternalSink);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at registerSink");
+ }
+ }
+ }
+
+ public void unregisterSink(FusedLocationHardwareSink sink) {
+ if(sink == null) {
+ return;
+ }
+
+ boolean unregisterSink = false;
+ synchronized(mSinkList) {
+ mSinkList.remove(sink);
+ // unregister after the last sink
+ unregisterSink = mSinkList.size() == 0;
+ }
+
+ if(unregisterSink) {
+ try {
+ mLocationHardware.unregisterSink(mInternalSink);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at unregisterSink");
+ }
+ }
+ }
+
+ public int getSupportedBatchSize() {
+ try {
+ return mLocationHardware.getSupportedBatchSize();
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at getSupportedBatchSize");
+ return 0;
+ }
+ }
+
+ public void startBatching(int id, GmsFusedBatchOptions batchOptions) {
+ try {
+ mLocationHardware.startBatching(id, batchOptions.getParcelableOptions());
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at startBatching");
+ }
+ }
+
+ public void stopBatching(int id) {
+ try {
+ mLocationHardware.stopBatching(id);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at stopBatching");
+ }
+ }
+
+ public void updateBatchingOptions(int id, GmsFusedBatchOptions batchOptions) {
+ try {
+ mLocationHardware.updateBatchingOptions(id, batchOptions.getParcelableOptions());
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at updateBatchingOptions");
+ }
+ }
+
+ public void requestBatchOfLocations(int batchSizeRequest) {
+ try {
+ mLocationHardware.requestBatchOfLocations(batchSizeRequest);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at requestBatchOfLocations");
+ }
+ }
+
+ public boolean supportsDiagnosticDataInjection() {
+ try {
+ return mLocationHardware.supportsDiagnosticDataInjection();
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at supportsDiagnisticDataInjection");
+ return false;
+ }
+ }
+
+ public void injectDiagnosticData(String data) {
+ try {
+ mLocationHardware.injectDiagnosticData(data);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at injectDiagnosticData");
+ }
+ }
+
+ public boolean supportsDeviceContextInjection() {
+ try {
+ return mLocationHardware.supportsDeviceContextInjection();
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at supportsDeviceContextInjection");
+ return false;
+ }
+ }
+
+ public void injectDeviceContext(int deviceEnabledContext) {
+ try {
+ mLocationHardware.injectDeviceContext(deviceEnabledContext);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at injectDeviceContext");
+ }
+ }
+
+ /*
+ * Helper methods
+ */
+ private void dispatchLocations(Location[] locations) {
+ ArrayList<FusedLocationHardwareSink> sinks = null;
+ synchronized (mSinkList) {
+ sinks = new ArrayList<FusedLocationHardwareSink>(mSinkList);
+ }
+
+ for(FusedLocationHardwareSink sink : sinks) {
+ sink.onLocationAvailable(locations);
+ }
+ }
+
+ private void dispatchDiagnosticData(String data) {
+ ArrayList<FusedLocationHardwareSink> sinks = null;
+ synchronized(mSinkList) {
+ sinks = new ArrayList<FusedLocationHardwareSink>(mSinkList);
+ }
+
+ for(FusedLocationHardwareSink sink : sinks) {
+ sink.onDiagnosticDataAvailable(data);
+ }
+ }
+}
diff --git a/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java b/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java
new file mode 100644
index 0000000..118b663
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 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.location.provider;
+
+import android.location.Location;
+
+/**
+ * Base class for sinks to interact with FusedLocationHardware.
+ * This is mainly used by GmsCore Fused Provider.
+ */
+public abstract class FusedLocationHardwareSink {
+ /*
+ * Methods to provide a facade for IFusedLocationHardware
+ */
+ public abstract void onLocationAvailable(Location[] locations);
+ public abstract void onDiagnosticDataAvailable(String data);
+} \ No newline at end of file
diff --git a/location/lib/java/com/android/location/provider/FusedProvider.java b/location/lib/java/com/android/location/provider/FusedProvider.java
new file mode 100644
index 0000000..bc9feef
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/FusedProvider.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 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.location.provider;
+
+import android.hardware.location.IFusedLocationHardware;
+import android.location.IFusedProvider;
+import android.os.IBinder;
+
+/**
+ * Base class for Fused providers implemented as unbundled services.
+ *
+ * <p>Fused providers can be implemented as services and return the result of
+ * {@link com.android.location.provider.FusedProvider#getBinder()} in its getBinder() method.
+ *
+ * <p>IMPORTANT: This class is effectively a public API for unbundled applications, and must remain
+ * API stable. See README.txt in the root of this package for more information.
+ *
+ * @hide
+ */
+public abstract class FusedProvider {
+ private IFusedProvider.Stub mProvider = new IFusedProvider.Stub() {
+ @Override
+ public void onFusedLocationHardwareChange(IFusedLocationHardware instance) {
+ setFusedLocationHardware(new FusedLocationHardware(instance));
+ }
+ };
+
+ /**
+ * Gets the Binder associated with the provider.
+ * This is intended to be used for the onBind() method of a service that implements a fused
+ * service.
+ *
+ * @return The IBinder instance associated with the provider.
+ */
+ public IBinder getBinder() {
+ return mProvider;
+ }
+
+ /**
+ * Sets the FusedLocationHardware instance in the provider..
+ * @param value The instance to set. This can be null in cases where the service connection
+ * is disconnected.
+ */
+ public abstract void setFusedLocationHardware(FusedLocationHardware value);
+}
diff --git a/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java b/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java
new file mode 100644
index 0000000..fd3f402
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2013 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.location.provider;
+
+import android.location.FusedBatchOptions;
+
+/**
+ * Class that exposes FusedBatchOptions to the GmsCore .
+ */
+public class GmsFusedBatchOptions {
+ private FusedBatchOptions mOptions = new FusedBatchOptions();
+
+ /*
+ * Methods that provide a facade for properties in FusedBatchOptions.
+ */
+ public void setMaxPowerAllocationInMW(double value) {
+ mOptions.setMaxPowerAllocationInMW(value);
+ }
+
+ public double getMaxPowerAllocationInMW() {
+ return mOptions.getMaxPowerAllocationInMW();
+ }
+
+ public void setPeriodInNS(long value) {
+ mOptions.setPeriodInNS(value);
+ }
+
+ public long getPeriodInNS() {
+ return mOptions.getPeriodInNS();
+ }
+
+ public void setSourceToUse(int source) {
+ mOptions.setSourceToUse(source);
+ }
+
+ public void resetSourceToUse(int source) {
+ mOptions.resetSourceToUse(source);
+ }
+
+ public boolean isSourceToUseSet(int source) {
+ return mOptions.isSourceToUseSet(source);
+ }
+
+ public int getSourcesToUse() {
+ return mOptions.getSourcesToUse();
+ }
+
+ public void setFlag(int flag) {
+ mOptions.setFlag(flag);
+ }
+
+ public void resetFlag(int flag) {
+ mOptions.resetFlag(flag);
+ }
+
+ public boolean isFlagSet(int flag) {
+ return mOptions.isFlagSet(flag);
+ }
+
+ public int getFlags() {
+ return mOptions.getFlags();
+ }
+
+ /**
+ * Definition of enum flag sets needed by this class.
+ * Such values need to be kept in sync with the ones in fused_location.h
+ */
+
+ public static final class SourceTechnologies {
+ public static int GNSS = 1<<0;
+ public static int WIFI = 1<<1;
+ public static int SENSORS = 1<<2;
+ public static int CELL = 1<<3;
+ public static int BLUETOOTH = 1<<4;
+ }
+
+ public static final class BatchFlags {
+ public static int WAKEUP_ON_FIFO_FULL = 1<<0;
+ public static int CALLBACK_ON_LOCATION_FIX = 1<<1;
+ }
+
+ /*
+ * Method definitions for internal use.
+ */
+
+ /*
+ * @hide
+ */
+ public FusedBatchOptions getParcelableOptions() {
+ return mOptions;
+ }
+}
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 6175268..49746ff 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -63,6 +63,8 @@ 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;
@@ -429,6 +431,17 @@ public class LocationManagerService extends ILocationManager.Stub {
Slog.e(TAG, "no geofence provider found");
}
+ // bind to fused provider
+ // TODO: [GeofenceIntegration] bind #getGeofenceHardware() with the GeofenceProxy
+ FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
+ FusedProxy fusedProxy = FusedProxy.createAndBind(
+ mContext,
+ mLocationHandler,
+ flpHardwareProvider.getLocationHardware());
+
+ if(fusedProxy == null) {
+ Slog.e(TAG, "No FusedProvider found.");
+ }
}
/**
diff --git a/services/java/com/android/server/location/FlpHardwareProvider.java b/services/java/com/android/server/location/FlpHardwareProvider.java
new file mode 100644
index 0000000..469f7ce
--- /dev/null
+++ b/services/java/com/android/server/location/FlpHardwareProvider.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2013 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.hardware.location.GeofenceHardwareImpl;
+import android.hardware.location.IFusedLocationHardware;
+import android.hardware.location.IFusedLocationHardwareSink;
+import android.location.IFusedGeofenceHardware;
+import android.location.FusedBatchOptions;
+import android.location.Geofence;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.Slog;
+
+/**
+ * This class is an interop layer for JVM types and the JNI code that interacts
+ * with the FLP HAL implementation.
+ *
+ * {@hide}
+ */
+public class FlpHardwareProvider {
+ private GeofenceHardwareImpl mGeofenceHardwareSink = null;
+ private IFusedLocationHardwareSink mLocationSink = null;
+
+ private static FlpHardwareProvider sSingletonInstance = null;
+
+ private final static String TAG = "FlpHardwareProvider";
+ private final Context mContext;
+
+ public static FlpHardwareProvider getInstance(Context context) {
+ if (sSingletonInstance == null) {
+ sSingletonInstance = new FlpHardwareProvider(context);
+ }
+
+ return sSingletonInstance;
+ }
+
+ private FlpHardwareProvider(Context context) {
+ mContext = context;
+
+ // register for listening for passive provider data
+ Handler handler = new Handler();
+ LocationManager manager = (LocationManager) mContext.getSystemService(
+ Context.LOCATION_SERVICE);
+ manager.requestLocationUpdates(
+ LocationManager.PASSIVE_PROVIDER,
+ 0 /* minTime */,
+ 0 /* minDistance */,
+ new NetworkLocationListener(),
+ handler.getLooper());
+ }
+
+ public static boolean isSupported() {
+ return nativeIsSupported();
+ }
+
+ /**
+ * Private callback functions used by FLP HAL.
+ */
+ // FlpCallbacks members
+ private void onLocationReport(Location[] locations) {
+ for (Location location : locations) {
+ location.setProvider(LocationManager.FUSED_PROVIDER);
+ // set the elapsed time-stamp just as GPS provider does
+ location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+ }
+
+ try {
+ if (mLocationSink != null) {
+ mLocationSink.onLocationAvailable(locations);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException calling onLocationAvailable");
+ }
+ }
+
+ // FlpDiagnosticCallbacks members
+ private void onDataReport(String data) {
+ try {
+ if (mLocationSink != null) {
+ mLocationSink.onDiagnosticDataAvailable(data);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException calling onDiagnosticDataAvailable");
+ }
+ }
+
+ // FlpGeofenceCallbacks members
+ private void onGeofenceTransition(
+ int geofenceId,
+ Location location,
+ int transition,
+ long timestamp,
+ int sourcesUsed
+ ) {
+ // TODO: [GeofenceIntegration] change GeofenceHardwareImpl to accept a location object
+ }
+
+ private void onGeofenceMonitorStatus(int status, int source, Location location) {
+ // TODO: [GeofenceIntegration]
+ }
+
+ private void onGeofenceAdd(int geofenceId, int result) {
+ // TODO: [GeofenceIntegration] map between GPS and FLP results to pass a consistent status
+ }
+
+ private void onGeofenceRemove(int geofenceId, int result) {
+ // TODO: [GeofenceIntegration] map between GPS and FLP results to pass a consistent status
+ }
+
+ private void onGeofencePause(int geofenceId, int result) {
+ // TODO; [GeofenceIntegration] map between GPS and FLP results
+ }
+
+ private void onGeofenceResume(int geofenceId, int result) {
+ // TODO: [GeofenceIntegration] map between GPS and FLP results
+ }
+
+ /**
+ * Private native methods accessing FLP HAL.
+ */
+ static { nativeClassInit(); }
+
+ // Core members
+ private static native void nativeClassInit();
+ private static native boolean nativeIsSupported();
+
+ // FlpLocationInterface members
+ private native void nativeInit();
+ private native int nativeGetBatchSize();
+ private native void nativeStartBatching(int requestId, FusedBatchOptions options);
+ private native void nativeUpdateBatchingOptions(int requestId, FusedBatchOptions optionsObject);
+ private native void nativeStopBatching(int id);
+ private native void nativeRequestBatchedLocation(int lastNLocations);
+ private native void nativeInjectLocation(Location location);
+ // TODO [Fix] sort out the lifetime of the instance
+ private native void nativeCleanup();
+
+ // FlpDiagnosticsInterface members
+ private native boolean nativeIsDiagnosticSupported();
+ private native void nativeInjectDiagnosticData(String data);
+
+ // FlpDeviceContextInterface members
+ private native boolean nativeIsDeviceContextSupported();
+ private native void nativeInjectDeviceContext(int deviceEnabledContext);
+
+ // FlpGeofencingInterface members
+ private native boolean nativeIsGeofencingSupported();
+ private native void nativeAddGeofences(int[] geofenceIdsArray, Geofence[] geofencesArray);
+ private native void nativePauseGeofence(int geofenceId);
+ private native void nativeResumeGeofence(int geofenceId, int monitorTransitions);
+ private native void nativeModifyGeofenceOption(
+ int geofenceId,
+ int lastTransition,
+ int monitorTransitions,
+ int notificationResponsiveness,
+ int unknownTimer,
+ int sourcesToUse);
+ private native void nativeRemoveGeofences(int[] geofenceIdsArray);
+
+ /**
+ * Interface implementations for services built on top of this functionality.
+ */
+ public static final String LOCATION = "Location";
+ public static final String GEOFENCING = "Geofencing";
+
+ public IFusedLocationHardware getLocationHardware() {
+ nativeInit();
+ return mLocationHardware;
+ }
+
+ public IFusedGeofenceHardware getGeofenceHardware() {
+ nativeInit();
+ return mGeofenceHardwareService;
+ }
+
+ private final IFusedLocationHardware mLocationHardware = new IFusedLocationHardware.Stub() {
+ @Override
+ public void registerSink(IFusedLocationHardwareSink eventSink) {
+ // only one sink is allowed at the moment
+ if (mLocationSink != null) {
+ throw new RuntimeException("IFusedLocationHardware does not support multiple sinks");
+ }
+
+ mLocationSink = eventSink;
+ }
+
+ @Override
+ public void unregisterSink(IFusedLocationHardwareSink eventSink) {
+ // don't throw if the sink is not registered, simply make it a no-op
+ if (mLocationSink == eventSink) {
+ mLocationSink = null;
+ }
+ }
+
+ @Override
+ public int getSupportedBatchSize() {
+ return nativeGetBatchSize();
+ }
+
+ @Override
+ public void startBatching(int requestId, FusedBatchOptions options) {
+ nativeStartBatching(requestId, options);
+ }
+
+ @Override
+ public void stopBatching(int requestId) {
+ nativeStopBatching(requestId);
+ }
+
+ @Override
+ public void updateBatchingOptions(int requestId, FusedBatchOptions options) {
+ nativeUpdateBatchingOptions(requestId, options);
+ }
+
+ @Override
+ public void requestBatchOfLocations(int batchSizeRequested) {
+ nativeRequestBatchedLocation(batchSizeRequested);
+ }
+
+ @Override
+ public boolean supportsDiagnosticDataInjection() {
+ return nativeIsDiagnosticSupported();
+ }
+
+ @Override
+ public void injectDiagnosticData(String data) {
+ nativeInjectDiagnosticData(data);
+ }
+
+ @Override
+ public boolean supportsDeviceContextInjection() {
+ return nativeIsDeviceContextSupported();
+ }
+
+ @Override
+ public void injectDeviceContext(int deviceEnabledContext) {
+ nativeInjectDeviceContext(deviceEnabledContext);
+ }
+ };
+
+ private final IFusedGeofenceHardware mGeofenceHardwareService =
+ new IFusedGeofenceHardware.Stub() {
+ @Override
+ public boolean isSupported() {
+ return nativeIsGeofencingSupported();
+ }
+
+ @Override
+ public void addGeofences(int[] geofenceIdsArray, Geofence[] geofencesArray) {
+ nativeAddGeofences(geofenceIdsArray, geofencesArray);
+ }
+
+ @Override
+ public void removeGeofences(int[] geofenceIds) {
+ nativeRemoveGeofences(geofenceIds);
+ }
+
+ @Override
+ public void pauseMonitoringGeofence(int geofenceId) {
+ nativePauseGeofence(geofenceId);
+ }
+
+ @Override
+ public void resumeMonitoringGeofence(int geofenceId, int monitorTransitions) {
+ nativeResumeGeofence(geofenceId, monitorTransitions);
+ }
+
+ @Override
+ public void modifyGeofenceOptions(int geofenceId,
+ int lastTransition,
+ int monitorTransitions,
+ int notificationResponsiveness,
+ int unknownTimer
+ ) {
+ // TODO: [GeofenceIntegration] set sourcesToUse to the right value
+ // TODO: expose sourcesToUse externally when needed
+ nativeModifyGeofenceOption(
+ geofenceId,
+ lastTransition,
+ monitorTransitions,
+ notificationResponsiveness,
+ unknownTimer,
+ /* sourcesToUse */ 0xFFFF);
+ }
+ };
+
+ /**
+ * Internal classes and functions used by the provider.
+ */
+ private final class NetworkLocationListener implements LocationListener {
+ @Override
+ public void onLocationChanged(Location location) {
+ if (
+ !LocationManager.NETWORK_PROVIDER.equals(location.getProvider()) ||
+ !location.hasAccuracy()
+ ) {
+ return;
+ }
+
+ nativeInjectLocation(location);
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) { }
+
+ @Override
+ public void onProviderEnabled(String provider) { }
+
+ @Override
+ public void onProviderDisabled(String provider) { }
+ }
+
+ private GeofenceHardwareImpl getGeofenceHardwareSink() {
+ if (mGeofenceHardwareSink == null) {
+ // TODO: [GeofenceIntegration] we need to register ourselves with GeofenceHardwareImpl
+ mGeofenceHardwareSink = GeofenceHardwareImpl.getInstance(mContext);
+ }
+
+ return mGeofenceHardwareSink;
+ }
+} \ No newline at end of file
diff --git a/services/java/com/android/server/location/FusedLocationHardwareSecure.java b/services/java/com/android/server/location/FusedLocationHardwareSecure.java
new file mode 100644
index 0000000..389bd24
--- /dev/null
+++ b/services/java/com/android/server/location/FusedLocationHardwareSecure.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2013 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.content.Context;
+import android.hardware.location.IFusedLocationHardware;
+import android.hardware.location.IFusedLocationHardwareSink;
+import android.location.FusedBatchOptions;
+import android.os.RemoteException;
+
+/**
+ * FusedLocationHardware decorator that adds permission checking.
+ * @hide
+ */
+public class FusedLocationHardwareSecure extends IFusedLocationHardware.Stub {
+ private final IFusedLocationHardware mLocationHardware;
+ private final Context mContext;
+ private final String mPermissionId;
+
+ public FusedLocationHardwareSecure(
+ IFusedLocationHardware locationHardware,
+ Context context,
+ String permissionId) {
+ mLocationHardware = locationHardware;
+ mContext = context;
+ mPermissionId = permissionId;
+ }
+
+ private void checkPermissions() {
+ mContext.enforceCallingPermission(
+ mPermissionId,
+ String.format(
+ "Permission '%s' not granted to access FusedLocationHardware",
+ mPermissionId));
+ }
+
+ @Override
+ public void registerSink(IFusedLocationHardwareSink eventSink) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.registerSink(eventSink);
+ }
+
+ @Override
+ public void unregisterSink(IFusedLocationHardwareSink eventSink) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.unregisterSink(eventSink);
+ }
+
+ @Override
+ public int getSupportedBatchSize() throws RemoteException {
+ checkPermissions();
+ return mLocationHardware.getSupportedBatchSize();
+ }
+
+ @Override
+ public void startBatching(int id, FusedBatchOptions batchOptions) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.startBatching(id, batchOptions);
+ }
+
+ @Override
+ public void stopBatching(int id) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.stopBatching(id);
+ }
+
+ @Override
+ public void updateBatchingOptions(
+ int id,
+ FusedBatchOptions batchoOptions
+ ) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.updateBatchingOptions(id, batchoOptions);
+ }
+
+ @Override
+ public void requestBatchOfLocations(int batchSizeRequested) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.requestBatchOfLocations(batchSizeRequested);
+ }
+
+ @Override
+ public boolean supportsDiagnosticDataInjection() throws RemoteException {
+ checkPermissions();
+ return mLocationHardware.supportsDiagnosticDataInjection();
+ }
+
+ @Override
+ public void injectDiagnosticData(String data) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.injectDiagnosticData(data);
+ }
+
+ @Override
+ public boolean supportsDeviceContextInjection() throws RemoteException {
+ checkPermissions();
+ return mLocationHardware.supportsDeviceContextInjection();
+ }
+
+ @Override
+ public void injectDeviceContext(int deviceEnabledContext) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.injectDeviceContext(deviceEnabledContext);
+ }
+}
diff --git a/services/java/com/android/server/location/FusedProxy.java b/services/java/com/android/server/location/FusedProxy.java
new file mode 100644
index 0000000..8278b96
--- /dev/null
+++ b/services/java/com/android/server/location/FusedProxy.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2013 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 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.server.ServiceWatcher;
+
+import android.Manifest;
+import android.content.Context;
+import android.hardware.location.IFusedLocationHardware;
+import android.location.IFusedProvider;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Proxy that helps bind GCore FusedProvider implementations to the Fused Hardware instances.
+ *
+ * @hide
+ */
+public final class FusedProxy {
+ private final String TAG = "FusedProxy";
+
+ private ServiceWatcher mServiceWatcher;
+
+ private FusedLocationHardwareSecure mLocationHardware;
+
+ /**
+ * Constructor of the class.
+ * This is private as the class follows a factory pattern for construction.
+ *
+ * @param context The context needed for construction.
+ * @param handler The handler needed for construction.
+ * @param locationHardware The instance of the Fused location hardware assigned to the proxy.
+ */
+ private FusedProxy(Context context, Handler handler, IFusedLocationHardware locationHardware) {
+ mLocationHardware = new FusedLocationHardwareSecure(
+ locationHardware,
+ context,
+ Manifest.permission.LOCATION_HARDWARE);
+ Runnable newServiceWork = new Runnable() {
+ @Override
+ public void run() {
+ bindProvider(mLocationHardware);
+ }
+ };
+
+ // prepare the connection to the provider
+ mServiceWatcher = new ServiceWatcher(
+ context,
+ TAG,
+ "com.android.location.service.FusedProvider",
+ com.android.internal.R.bool.config_enableFusedLocationOverlay,
+ com.android.internal.R.string.config_fusedLocationProviderPackageName,
+ com.android.internal.R.array.config_locationProviderPackageNames,
+ newServiceWork,
+ handler);
+ }
+
+ /**
+ * Creates an instance of the proxy and binds it to the appropriate FusedProvider.
+ *
+ * @param context The context needed for construction.
+ * @param handler The handler needed for construction.
+ * @param locationHardware The instance of the Fused location hardware assigned to the proxy.
+ *
+ * @return An instance of the proxy if it could be bound, null otherwise.
+ */
+ public static FusedProxy createAndBind(
+ Context context,
+ Handler handler,
+ IFusedLocationHardware locationHardware
+ ) {
+ FusedProxy fusedProxy = new FusedProxy(context, handler, locationHardware);
+
+ // try to bind the Fused provider
+ if (!fusedProxy.mServiceWatcher.start()) {
+ return null;
+ }
+
+ return fusedProxy;
+ }
+
+ /**
+ * Helper function to bind the FusedLocationHardware to the appropriate FusedProvider instance.
+ *
+ * @param locationHardware The FusedLocationHardware instance to use for the binding operation.
+ */
+ private void bindProvider(IFusedLocationHardware locationHardware) {
+ IFusedProvider provider = IFusedProvider.Stub.asInterface(mServiceWatcher.getBinder());
+
+ if (provider == null) {
+ Log.e(TAG, "No instance of FusedProvider found on FusedLocationHardware connected.");
+ return;
+ }
+
+ try {
+ provider.onFusedLocationHardwareChange(locationHardware);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+}
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 3946f15..93d8e07 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -15,6 +15,7 @@ LOCAL_SRC_FILES:= \
com_android_server_UsbHostManager.cpp \
com_android_server_VibratorService.cpp \
com_android_server_location_GpsLocationProvider.cpp \
+ com_android_server_location_FlpHardwareProvider.cpp \
com_android_server_connectivity_Vpn.cpp \
onload.cpp
diff --git a/services/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/jni/com_android_server_location_FlpHardwareProvider.cpp
new file mode 100644
index 0000000..48b86db
--- /dev/null
+++ b/services/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -0,0 +1,901 @@
+/*
+ * Copyright (C) 2013 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/license/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.
+ */
+
+#define LOG_TAG "FuseLocationProvider"
+#define LOG_NDEBUG 0
+
+#define WAKE_LOCK_NAME "FLP"
+#define LOCATION_CLASS_NAME "android/location/Location"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "hardware/fused_location.h"
+#include "hardware_legacy/power.h"
+
+static jobject sCallbacksObj = NULL;
+static JNIEnv *sCallbackEnv = NULL;
+static hw_device_t* sHardwareDevice = NULL;
+
+static jmethodID sOnLocationReport = NULL;
+static jmethodID sOnDataReport = NULL;
+static jmethodID sOnGeofenceTransition = NULL;
+static jmethodID sOnGeofenceMonitorStatus = NULL;
+static jmethodID sOnGeofenceAdd = NULL;
+static jmethodID sOnGeofenceRemove = NULL;
+static jmethodID sOnGeofencePause = NULL;
+static jmethodID sOnGeofenceResume = NULL;
+
+static const FlpLocationInterface* sFlpInterface = NULL;
+static const FlpDiagnosticInterface* sFlpDiagnosticInterface = NULL;
+static const FlpGeofencingInterface* sFlpGeofencingInterface = NULL;
+static const FlpDeviceContextInterface* sFlpDeviceContextInterface = NULL;
+
+namespace android {
+
+static inline void CheckExceptions(JNIEnv* env, const char* methodName) {
+ if(!env->ExceptionCheck()) {
+ return;
+ }
+
+ ALOGE("An exception was thrown by '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+}
+
+static inline void ThrowOnError(
+ JNIEnv* env,
+ int resultCode,
+ const char* methodName) {
+ if(resultCode == FLP_RESULT_SUCCESS) {
+ return;
+ }
+
+ ALOGE("Error %d in '%s'", resultCode, methodName);
+ jclass exceptionClass = env->FindClass("java/lang/RuntimeException");
+ env->ThrowNew(exceptionClass, methodName);
+}
+
+static bool IsValidCallbackThread() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ if(sCallbackEnv == NULL || sCallbackEnv != env) {
+ ALOGE("CallbackThread check fail: env=%p, expected=%p", env, sCallbackEnv);
+ return false;
+ }
+
+ return true;
+}
+
+static int SetThreadEvent(ThreadEvent event) {
+ JavaVM* javaVm = AndroidRuntime::getJavaVM();
+
+ switch(event) {
+ case ASSOCIATE_JVM:
+ {
+ if(sCallbackEnv != NULL) {
+ ALOGE(
+ "Attempted to associate callback in '%s'. Callback already associated.",
+ __FUNCTION__
+ );
+ return FLP_RESULT_ERROR;
+ }
+
+ JavaVMAttachArgs args = {
+ JNI_VERSION_1_6,
+ "FLP Service Callback Thread",
+ /* group */ NULL
+ };
+
+ jint attachResult = javaVm->AttachCurrentThread(&sCallbackEnv, &args);
+ if (attachResult != 0) {
+ ALOGE("Callback thread attachment error: %d", attachResult);
+ return FLP_RESULT_ERROR;
+ }
+
+ ALOGV("Callback thread attached: %p", sCallbackEnv);
+ break;
+ }
+ case DISASSOCIATE_JVM:
+ {
+ if (!IsValidCallbackThread()) {
+ ALOGE(
+ "Attempted to dissasociate an unnownk callback thread : '%s'.",
+ __FUNCTION__
+ );
+ return FLP_RESULT_ERROR;
+ }
+
+ if (javaVm->DetachCurrentThread() != 0) {
+ return FLP_RESULT_ERROR;
+ }
+
+ sCallbackEnv = NULL;
+ break;
+ }
+ default:
+ ALOGE("Invalid ThreadEvent request %d", event);
+ return FLP_RESULT_ERROR;
+ }
+
+ return FLP_RESULT_SUCCESS;
+}
+
+/*
+ * Initializes the FlpHardwareProvider class from the native side by opening
+ * the HW module and obtaining the proper interfaces.
+ */
+static void ClassInit(JNIEnv* env, jclass clazz) {
+ // get references to the Java provider methods
+ sOnLocationReport = env->GetMethodID(
+ clazz,
+ "onLocationReport",
+ "([Landroid/location/Location;)V");
+ sOnDataReport = env->GetMethodID(
+ clazz,
+ "onDataReport",
+ "(Ljava/lang/String;)V"
+ );
+ sOnGeofenceTransition = env->GetMethodID(
+ clazz,
+ "onGeofenceTransition",
+ "(ILandroid/location/Location;IJI)V"
+ );
+ sOnGeofenceMonitorStatus = env->GetMethodID(
+ clazz,
+ "onGeofenceMonitorStatus",
+ "(IILandroid/location/Location;)V"
+ );
+ sOnGeofenceAdd = env->GetMethodID(clazz, "onGeofenceAdd", "(II)V");
+ sOnGeofenceRemove = env->GetMethodID(clazz, "onGeofenceRemove", "(II)V");
+ sOnGeofencePause = env->GetMethodID(clazz, "onGeofencePause", "(II)V");
+ sOnGeofenceResume = env->GetMethodID(clazz, "onGeofenceResume", "(II)V");
+}
+
+/*
+ * Helper function to unwrap a java object back into a FlpLocation structure.
+ */
+static void TranslateFromObject(
+ JNIEnv* env,
+ jobject locationObject,
+ FlpLocation& location) {
+ location.size = sizeof(FlpLocation);
+ location.flags = 0;
+
+ jclass locationClass = env->GetObjectClass(locationObject);
+
+ jmethodID getLatitude = env->GetMethodID(locationClass, "getLatitude", "()D");
+ location.latitude = env->CallDoubleMethod(locationObject, getLatitude);
+ jmethodID getLongitude = env->GetMethodID(locationClass, "getLongitude", "()D");
+ location.longitude = env->CallDoubleMethod(locationObject, getLongitude);
+ jmethodID getTime = env->GetMethodID(locationClass, "getTime", "()J");
+ location.timestamp = env->CallLongMethod(locationObject, getTime);
+ location.flags |= FLP_LOCATION_HAS_LAT_LONG;
+
+ jmethodID hasAltitude = env->GetMethodID(locationClass, "hasAltitude", "()Z");
+ if (env->CallBooleanMethod(locationObject, hasAltitude)) {
+ jmethodID getAltitude = env->GetMethodID(locationClass, "getAltitude", "()D");
+ location.altitude = env->CallDoubleMethod(locationObject, getAltitude);
+ location.flags |= FLP_LOCATION_HAS_ALTITUDE;
+ }
+
+ jmethodID hasSpeed = env->GetMethodID(locationClass, "hasSpeed", "()Z");
+ if (env->CallBooleanMethod(locationObject, hasSpeed)) {
+ jmethodID getSpeed = env->GetMethodID(locationClass, "getSpeed", "()F");
+ location.speed = env->CallFloatMethod(locationObject, getSpeed);
+ location.flags |= FLP_LOCATION_HAS_SPEED;
+ }
+
+ jmethodID hasBearing = env->GetMethodID(locationClass, "hasBearing", "()Z");
+ if (env->CallBooleanMethod(locationObject, hasBearing)) {
+ jmethodID getBearing = env->GetMethodID(locationClass, "getBearing", "()F");
+ location.bearing = env->CallFloatMethod(locationObject, getBearing);
+ location.flags |= FLP_LOCATION_HAS_BEARING;
+ }
+
+ jmethodID hasAccuracy = env->GetMethodID(locationClass, "hasAccuracy", "()Z");
+ if (env->CallBooleanMethod(locationObject, hasAccuracy)) {
+ jmethodID getAccuracy = env->GetMethodID(
+ locationClass,
+ "getAccuracy",
+ "()F"
+ );
+ location.accuracy = env->CallFloatMethod(locationObject, getAccuracy);
+ location.flags |= FLP_LOCATION_HAS_ACCURACY;
+ }
+
+ // TODO: wire sources_used if Location class exposes them
+}
+
+/*
+ * Helper function to unwrap FlpBatchOptions from the Java Runtime calls.
+ */
+static void TranslateFromObject(
+ JNIEnv* env,
+ jobject batchOptionsObject,
+ FlpBatchOptions& batchOptions) {
+ jclass batchOptionsClass = env->GetObjectClass(batchOptionsObject);
+
+ jmethodID getMaxPower = env->GetMethodID(
+ batchOptionsClass,
+ "getMaxPowerAllocationInMW",
+ "()D"
+ );
+ batchOptions.max_power_allocation_mW = env->CallDoubleMethod(
+ batchOptionsObject,
+ getMaxPower
+ );
+
+ jmethodID getPeriod = env->GetMethodID(
+ batchOptionsClass,
+ "getPeriodInNS",
+ "()J"
+ );
+ batchOptions.period_ns = env->CallLongMethod(batchOptionsObject, getPeriod);
+
+ jmethodID getSourcesToUse = env->GetMethodID(
+ batchOptionsClass,
+ "getSourcesToUse",
+ "()I"
+ );
+ batchOptions.sources_to_use = env->CallIntMethod(
+ batchOptionsObject,
+ getSourcesToUse
+ );
+
+ jmethodID getFlags = env->GetMethodID(batchOptionsClass, "getFlags", "()I");
+ batchOptions.flags = env->CallIntMethod(batchOptionsObject, getFlags);
+}
+
+/*
+ * Helper function to transform FlpLocation into a java object.
+ */
+static void TranslateToObject(const FlpLocation* location, jobject& locationObject) {
+ jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
+ jmethodID locationCtor = sCallbackEnv->GetMethodID(
+ locationClass,
+ "<init>",
+ "(Ljava/lang/String;)V"
+ );
+
+ // the provider is set in the upper JVM layer
+ locationObject = sCallbackEnv->NewObject(locationClass, locationCtor, NULL);
+ jint flags = location->flags;
+
+ // set the valid information in the object
+ if (flags & FLP_LOCATION_HAS_LAT_LONG) {
+ jmethodID setLatitude = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setLatitude",
+ "(D)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setLatitude, location->latitude);
+
+ jmethodID setLongitude = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setLongitude",
+ "(D)V"
+ );
+ sCallbackEnv->CallVoidMethod(
+ locationObject,
+ setLongitude,
+ location->longitude
+ );
+
+ jmethodID setTime = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setTime",
+ "(J)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setTime, location->timestamp);
+ }
+
+ if (flags & FLP_LOCATION_HAS_ALTITUDE) {
+ jmethodID setAltitude = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setAltitude",
+ "(D)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setAltitude, location->altitude);
+ }
+
+ if (flags & FLP_LOCATION_HAS_SPEED) {
+ jmethodID setSpeed = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setSpeed",
+ "(F)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setSpeed, location->speed);
+ }
+
+ if (flags & FLP_LOCATION_HAS_BEARING) {
+ jmethodID setBearing = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setBearing",
+ "(F)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setBearing, location->bearing);
+ }
+
+ if (flags & FLP_LOCATION_HAS_ACCURACY) {
+ jmethodID setAccuracy = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setAccuracy",
+ "(F)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setAccuracy, location->accuracy);
+ }
+
+ // TODO: wire FlpLocation::sources_used when needed
+}
+
+/*
+ * Helper function to serialize FlpLocation structures.
+ */
+static void TranslateToObjectArray(
+ int32_t locationsCount,
+ FlpLocation** locations,
+ jobjectArray& locationsArray) {
+ jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
+ locationsArray = sCallbackEnv->NewObjectArray(
+ locationsCount,
+ locationClass,
+ /* initialElement */ NULL
+ );
+
+ for (int i = 0; i < locationsCount; ++i) {
+ jobject locationObject = NULL;
+ TranslateToObject(locations[i], locationObject);
+ sCallbackEnv->SetObjectArrayElement(locationsArray, i, locationObject);
+ sCallbackEnv->DeleteLocalRef(locationObject);
+ }
+}
+
+static void LocationCallback(int32_t locationsCount, FlpLocation** locations) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ if(locationsCount == 0 || locations == NULL) {
+ ALOGE(
+ "Invalid LocationCallback. Count: %d, Locations: %p",
+ locationsCount,
+ locations
+ );
+ return;
+ }
+
+ jobjectArray locationsArray = NULL;
+ TranslateToObjectArray(locationsCount, locations, locationsArray);
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnLocationReport,
+ locationsArray
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void AcquireWakelock() {
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
+}
+
+static void ReleaseWakelock() {
+ release_wake_lock(WAKE_LOCK_NAME);
+}
+
+FlpCallbacks sFlpCallbacks = {
+ sizeof(FlpCallbacks),
+ LocationCallback,
+ AcquireWakelock,
+ ReleaseWakelock,
+ SetThreadEvent
+};
+
+static void ReportData(char* data, int length) {
+ jstring stringData = NULL;
+
+ if(length != 0 && data != NULL) {
+ stringData = sCallbackEnv->NewString(reinterpret_cast<jchar*>(data), length);
+ } else {
+ ALOGE("Invalid ReportData callback. Length: %d, Data: %p", length, data);
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnDataReport, stringData);
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+FlpDiagnosticCallbacks sFlpDiagnosticCallbacks = {
+ sizeof(FlpDiagnosticCallbacks),
+ SetThreadEvent,
+ ReportData
+};
+
+static void GeofenceTransitionCallback(
+ int32_t geofenceId,
+ FlpLocation* location,
+ int32_t transition,
+ FlpUtcTime timestamp,
+ uint32_t sourcesUsed
+ ) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ if(location == NULL) {
+ ALOGE("GeofenceTransition received with invalid location: %p", location);
+ return;
+ }
+
+ jobject locationObject = NULL;
+ TranslateToObject(location, locationObject);
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofenceTransition,
+ geofenceId,
+ locationObject,
+ transition,
+ timestamp,
+ sourcesUsed
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofenceMonitorStatusCallback(
+ int32_t status,
+ uint32_t source,
+ FlpLocation* lastLocation) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ jobject locationObject = NULL;
+ if(lastLocation != NULL) {
+ TranslateToObject(lastLocation, locationObject);
+ }
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofenceMonitorStatus,
+ status,
+ source,
+ locationObject
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofenceAddCallback(int32_t geofenceId, int32_t result) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnGeofenceAdd, geofenceId, result);
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofenceRemoveCallback(int32_t geofenceId, int32_t result) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofenceRemove,
+ geofenceId,
+ result
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofencePauseCallback(int32_t geofenceId, int32_t result) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofencePause,
+ geofenceId,
+ result
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofenceResumeCallback(int32_t geofenceId, int32_t result) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofenceResume,
+ geofenceId,
+ result
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+FlpGeofenceCallbacks sFlpGeofenceCallbacks = {
+ sizeof(FlpGeofenceCallbacks),
+ GeofenceTransitionCallback,
+ GeofenceMonitorStatusCallback,
+ GeofenceAddCallback,
+ GeofenceRemoveCallback,
+ GeofencePauseCallback,
+ GeofenceResumeCallback,
+ SetThreadEvent
+};
+
+/*
+ * Initializes the Fused Location Provider in the native side. It ensures that
+ * the Flp interfaces are initialized properly.
+ */
+static void Init(JNIEnv* env, jobject obj) {
+ if(sHardwareDevice != NULL) {
+ ALOGD("Hardware Device already opened.");
+ return;
+ }
+
+ const hw_module_t* module = NULL;
+ int err = hw_get_module(FUSED_LOCATION_HARDWARE_MODULE_ID, &module);
+ if(err != 0) {
+ ALOGE("Error hw_get_module '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
+ return;
+ }
+
+ err = module->methods->open(
+ module,
+ FUSED_LOCATION_HARDWARE_MODULE_ID, &sHardwareDevice);
+ if(err != 0) {
+ ALOGE("Error opening device '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
+ return;
+ }
+
+ sFlpInterface = NULL;
+ flp_device_t* flp_device = reinterpret_cast<flp_device_t*>(sHardwareDevice);
+ sFlpInterface = flp_device->get_flp_interface(flp_device);
+
+ if(sFlpInterface != NULL) {
+ sFlpDiagnosticInterface = reinterpret_cast<const FlpDiagnosticInterface*>(
+ sFlpInterface->get_extension(FLP_DIAGNOSTIC_INTERFACE)
+ );
+
+ sFlpGeofencingInterface = reinterpret_cast<const FlpGeofencingInterface*>(
+ sFlpInterface->get_extension(FLP_GEOFENCING_INTERFACE)
+ );
+
+ sFlpDeviceContextInterface = reinterpret_cast<const FlpDeviceContextInterface*>(
+ sFlpInterface->get_extension(FLP_DEVICE_CONTEXT_INTERFACE)
+ );
+ }
+
+ if(sCallbacksObj == NULL) {
+ sCallbacksObj = env->NewGlobalRef(obj);
+ }
+
+ // initialize the Flp interfaces
+ if(sFlpInterface == NULL || sFlpInterface->init(&sFlpCallbacks) != 0) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ if(sFlpDiagnosticInterface != NULL) {
+ sFlpDiagnosticInterface->init(&sFlpDiagnosticCallbacks);
+ }
+
+ if(sFlpGeofencingInterface != NULL) {
+ sFlpGeofencingInterface->init(&sFlpGeofenceCallbacks);
+ }
+
+ // TODO: inject any device context if when needed
+}
+
+static jboolean IsSupported(JNIEnv* env, jclass clazz) {
+ return sFlpInterface != NULL;
+}
+
+static jint GetBatchSize(JNIEnv* env, jobject object) {
+ if(sFlpInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ return sFlpInterface->get_batch_size();
+}
+
+static void StartBatching(
+ JNIEnv* env,
+ jobject object,
+ jint id,
+ jobject optionsObject) {
+ if(sFlpInterface == NULL || optionsObject == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ FlpBatchOptions options;
+ TranslateFromObject(env, optionsObject, options);
+ int result = sFlpInterface->start_batching(id, &options);
+ ThrowOnError(env, result, __FUNCTION__);
+}
+
+static void UpdateBatchingOptions(
+ JNIEnv* env,
+ jobject object,
+ jint id,
+ jobject optionsObject) {
+ if(sFlpInterface == NULL || optionsObject == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ FlpBatchOptions options;
+ TranslateFromObject(env, optionsObject, options);
+ int result = sFlpInterface->update_batching_options(id, &options);
+ ThrowOnError(env, result, __FUNCTION__);
+}
+
+static void StopBatching(JNIEnv* env, jobject object, jint id) {
+ if(sFlpInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpInterface->stop_batching(id);
+}
+
+static void Cleanup(JNIEnv* env, jobject object) {
+ if(sFlpInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpInterface->cleanup();
+
+ if(sCallbacksObj != NULL) {
+ env->DeleteGlobalRef(sCallbacksObj);
+ sCallbacksObj = NULL;
+ }
+
+ sFlpInterface = NULL;
+ sFlpDiagnosticInterface = NULL;
+ sFlpDeviceContextInterface = NULL;
+ sFlpGeofencingInterface = NULL;
+
+ if(sHardwareDevice != NULL) {
+ sHardwareDevice->close(sHardwareDevice);
+ sHardwareDevice = NULL;
+ }
+}
+
+static void GetBatchedLocation(JNIEnv* env, jobject object, jint lastNLocations) {
+ if(sFlpInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpInterface->get_batched_location(lastNLocations);
+}
+
+static void InjectLocation(JNIEnv* env, jobject object, jobject locationObject) {
+ if(locationObject == NULL) {
+ ALOGE("Invalid location for injection: %p", locationObject);
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ if(sFlpInterface == NULL) {
+ // there is no listener, bail
+ return;
+ }
+
+ FlpLocation location;
+ TranslateFromObject(env, locationObject, location);
+ int result = sFlpInterface->inject_location(&location);
+ if (result != FLP_RESULT_ERROR) {
+ // do not throw but log, this operation should be fire and forget
+ ALOGE("Error %d in '%s'", result, __FUNCTION__);
+ }
+}
+
+static jboolean IsDiagnosticSupported() {
+ return sFlpDiagnosticInterface != NULL;
+}
+
+static void InjectDiagnosticData(JNIEnv* env, jobject object, jstring stringData) {
+ if(stringData == NULL) {
+ ALOGE("Invalid diagnostic data for injection: %p", stringData);
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ if(sFlpDiagnosticInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ int length = env->GetStringLength(stringData);
+ const jchar* data = env->GetStringChars(stringData, /* isCopy */ NULL);
+ if(data == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ int result = sFlpDiagnosticInterface->inject_data((char*) data, length);
+ ThrowOnError(env, result, __FUNCTION__);
+}
+
+static jboolean IsDeviceContextSupported() {
+ return sFlpDeviceContextInterface != NULL;
+}
+
+static void InjectDeviceContext(JNIEnv* env, jobject object, jint enabledMask) {
+ if(sFlpDeviceContextInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ int result = sFlpDeviceContextInterface->inject_device_context(enabledMask);
+ ThrowOnError(env, result, __FUNCTION__);
+}
+
+static jboolean IsGeofencingSupported() {
+ return sFlpGeofencingInterface != NULL;
+}
+
+static void AddGeofences(
+ JNIEnv* env,
+ jobject object,
+ jintArray geofenceIdsArray,
+ jobjectArray geofencesArray) {
+ if(geofencesArray == NULL) {
+ ALOGE("Invalid Geofences to add: %p", geofencesArray);
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ if (sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ jint geofencesCount = env->GetArrayLength(geofenceIdsArray);
+ Geofence* geofences = new Geofence[geofencesCount];
+ if (geofences == NULL) {
+ ThrowOnError(env, FLP_RESULT_INSUFFICIENT_MEMORY, __FUNCTION__);
+ }
+
+ jint* ids = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL);
+ for (int i = 0; i < geofencesCount; ++i) {
+ geofences[i].geofence_id = ids[i];
+
+ // TODO: fill in the GeofenceData
+
+ // TODO: fill in the GeofenceOptions
+ }
+
+ sFlpGeofencingInterface->add_geofences(geofencesCount, &geofences);
+ if (geofences != NULL) delete[] geofences;
+}
+
+static void PauseGeofence(JNIEnv* env, jobject object, jint geofenceId) {
+ if(sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpGeofencingInterface->pause_geofence(geofenceId);
+}
+
+static void ResumeGeofence(
+ JNIEnv* env,
+ jobject object,
+ jint geofenceId,
+ jint monitorTransitions) {
+ if(sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpGeofencingInterface->resume_geofence(geofenceId, monitorTransitions);
+}
+
+static void ModifyGeofenceOption(
+ JNIEnv* env,
+ jobject object,
+ jint geofenceId,
+ jint lastTransition,
+ jint monitorTransitions,
+ jint notificationResponsiveness,
+ jint unknownTimer,
+ jint sourcesToUse) {
+ if(sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ GeofenceOptions options = {
+ lastTransition,
+ monitorTransitions,
+ notificationResponsiveness,
+ unknownTimer,
+ (uint32_t)sourcesToUse
+ };
+
+ sFlpGeofencingInterface->modify_geofence_option(geofenceId, &options);
+}
+
+static void RemoveGeofences(
+ JNIEnv* env,
+ jobject object,
+ jintArray geofenceIdsArray) {
+ if(sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ jsize geofenceIdsCount = env->GetArrayLength(geofenceIdsArray);
+ jint* geofenceIds = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL);
+ if(geofenceIds == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpGeofencingInterface->remove_geofences(geofenceIdsCount, geofenceIds);
+}
+
+static JNINativeMethod sMethods[] = {
+ //{"name", "signature", functionPointer }
+ {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)},
+ {"nativeInit", "()V", reinterpret_cast<void*>(Init)},
+ {"nativeCleanup", "()V", reinterpret_cast<void*>(Cleanup)},
+ {"nativeIsSupported", "()Z", reinterpret_cast<void*>(IsSupported)},
+ {"nativeGetBatchSize", "()I", reinterpret_cast<void*>(GetBatchSize)},
+ {"nativeStartBatching",
+ "(ILandroid/location/FusedBatchOptions;)V",
+ reinterpret_cast<void*>(StartBatching)},
+ {"nativeUpdateBatchingOptions",
+ "(ILandroid/location/FusedBatchOptions;)V",
+ reinterpret_cast<void*>(UpdateBatchingOptions)},
+ {"nativeStopBatching", "(I)V", reinterpret_cast<void*>(StopBatching)},
+ {"nativeRequestBatchedLocation",
+ "(I)V",
+ reinterpret_cast<void*>(GetBatchedLocation)},
+ {"nativeInjectLocation",
+ "(Landroid/location/Location;)V",
+ reinterpret_cast<void*>(InjectLocation)},
+ {"nativeIsDiagnosticSupported",
+ "()Z",
+ reinterpret_cast<void*>(IsDiagnosticSupported)},
+ {"nativeInjectDiagnosticData",
+ "(Ljava/lang/String;)V",
+ reinterpret_cast<void*>(InjectDiagnosticData)},
+ {"nativeIsDeviceContextSupported",
+ "()Z",
+ reinterpret_cast<void*>(IsDeviceContextSupported)},
+ {"nativeInjectDeviceContext",
+ "(I)V",
+ reinterpret_cast<void*>(InjectDeviceContext)},
+ {"nativeIsGeofencingSupported",
+ "()Z",
+ reinterpret_cast<void*>(IsGeofencingSupported)},
+ {"nativeAddGeofences",
+ "([I[Landroid/location/Geofence;)V",
+ reinterpret_cast<void*>(AddGeofences)},
+ {"nativePauseGeofence", "(I)V", reinterpret_cast<void*>(PauseGeofence)},
+ {"nativeResumeGeofence", "(II)V", reinterpret_cast<void*>(ResumeGeofence)},
+ {"nativeModifyGeofenceOption",
+ "(IIIIII)V",
+ reinterpret_cast<void*>(ModifyGeofenceOption)},
+ {"nativeRemoveGeofences", "([I)V", reinterpret_cast<void*>(RemoveGeofences)}
+};
+
+/*
+ * Registration method invoked on JNI Load.
+ */
+int register_android_server_location_FlpHardwareProvider(JNIEnv* env) {
+ return jniRegisterNativeMethods(
+ env,
+ "com/android/server/location/FlpHardwareProvider",
+ sMethods,
+ NELEM(sMethods)
+ );
+}
+
+} /* name-space Android */
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index 736ef24..5427277 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -32,6 +32,7 @@ int register_android_server_UsbHostManager(JNIEnv* env);
int register_android_server_VibratorService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
int register_android_server_location_GpsLocationProvider(JNIEnv* env);
+int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_AssetAtlasService(JNIEnv* env);
};
@@ -61,6 +62,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
register_android_server_VibratorService(env);
register_android_server_SystemServer(env);
register_android_server_location_GpsLocationProvider(env);
+ register_android_server_location_FlpHardwareProvider(env);
register_android_server_connectivity_Vpn(env);
register_android_server_AssetAtlasService(env);