diff options
author | destradaa <destradaa@google.com> | 2013-07-12 15:43:36 -0700 |
---|---|---|
committer | destradaa <destradaa@google.com> | 2013-08-08 15:27:38 -0700 |
commit | 1af4b0280af406cfc7eb46810f6b76e57b983e11 (patch) | |
tree | 1f7f8d5a86c8dcd42cb24474e93b58bb0775071e | |
parent | 8ffe17ae32e72e5d872a36d5048bf912d28e766f (diff) | |
download | frameworks_base-1af4b0280af406cfc7eb46810f6b76e57b983e11.zip frameworks_base-1af4b0280af406cfc7eb46810f6b76e57b983e11.tar.gz frameworks_base-1af4b0280af406cfc7eb46810f6b76e57b983e11.tar.bz2 |
Add FlpHal layer to support Location Batching.
Change-Id: Ia3a57d869dfb3f067a1b95fa66d54f311ddcfdc3
18 files changed, 2336 insertions, 0 deletions
@@ -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); |