am 541ba710: Merge "Add FlpHal layer to support Location Batching." into klp-dev

* commit '541ba710731c484926440fbb9b2c39d69f38b652':
  Add FlpHal layer to support Location Batching.
This commit is contained in:
destradaa
2013-08-08 16:09:52 -07:00
committed by Android Git Automerger
18 changed files with 2336 additions and 0 deletions

View File

@@ -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 \

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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.");
}
}
/**

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}
}

View File

@@ -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

View File

@@ -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 */

View File

@@ -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);