diff options
Diffstat (limited to 'services/core/java/com/android/server/location/FlpHardwareProvider.java')
-rw-r--r-- | services/core/java/com/android/server/location/FlpHardwareProvider.java | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java new file mode 100644 index 0000000..fab84a8 --- /dev/null +++ b/services/core/java/com/android/server/location/FlpHardwareProvider.java @@ -0,0 +1,427 @@ +/* + * 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.GeofenceHardware; +import android.hardware.location.GeofenceHardwareImpl; +import android.hardware.location.GeofenceHardwareRequestParcelable; +import android.hardware.location.IFusedLocationHardware; +import android.hardware.location.IFusedLocationHardwareSink; +import android.location.IFusedGeofenceHardware; +import android.location.FusedBatchOptions; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.location.LocationRequest; + +import android.content.Context; +import android.os.Bundle; +import android.os.Looper; +import android.os.RemoteException; +import android.os.SystemClock; +import android.util.Log; + +/** + * 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; + private final Object mLocationSinkLock = new Object(); + + // FlpHal result codes, they must be equal to the ones in fused_location.h + private static final int FLP_RESULT_SUCCESS = 0; + private static final int FLP_RESULT_ERROR = -1; + private static final int FLP_RESULT_INSUFFICIENT_MEMORY = -2; + private static final int FLP_RESULT_TOO_MANY_GEOFENCES = -3; + private static final int FLP_RESULT_ID_EXISTS = -4; + private static final int FLP_RESULT_ID_UNKNOWN = -5; + private static final int FLP_RESULT_INVALID_GEOFENCE_TRANSITION = -6; + + 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 + LocationManager manager = (LocationManager) mContext.getSystemService( + Context.LOCATION_SERVICE); + final long minTime = 0; + final float minDistance = 0; + final boolean oneShot = false; + LocationRequest request = LocationRequest.createFromDeprecatedProvider( + LocationManager.PASSIVE_PROVIDER, + minTime, + minDistance, + oneShot); + // Don't keep track of this request since it's done on behalf of other clients + // (which are kept track of separately). + request.setHideFromAppOps(true); + manager.requestLocationUpdates( + request, + new NetworkLocationListener(), + Looper.myLooper()); + } + + 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()); + } + + IFusedLocationHardwareSink sink; + synchronized (mLocationSinkLock) { + sink = mLocationSink; + } + try { + if (sink != null) { + sink.onLocationAvailable(locations); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling onLocationAvailable"); + } + } + + // FlpDiagnosticCallbacks members + private void onDataReport(String data) { + IFusedLocationHardwareSink sink; + synchronized (mLocationSinkLock) { + sink = mLocationSink; + } + try { + if (mLocationSink != null) { + sink.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) { + getGeofenceHardwareSink().reportGeofenceTransition( + geofenceId, + updateLocationInformation(location), + transition, + timestamp, + GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE, + sourcesUsed); + } + + private void onGeofenceMonitorStatus(int status, int source, Location location) { + // allow the location to be optional in this event + Location updatedLocation = null; + if(location != null) { + updatedLocation = updateLocationInformation(location); + } + + getGeofenceHardwareSink().reportGeofenceMonitorStatus( + GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE, + status, + updatedLocation, + source); + } + + private void onGeofenceAdd(int geofenceId, int result) { + getGeofenceHardwareSink().reportGeofenceAddStatus( + geofenceId, + translateToGeofenceHardwareStatus(result)); + } + + private void onGeofenceRemove(int geofenceId, int result) { + getGeofenceHardwareSink().reportGeofenceRemoveStatus( + geofenceId, + translateToGeofenceHardwareStatus(result)); + } + + private void onGeofencePause(int geofenceId, int result) { + getGeofenceHardwareSink().reportGeofencePauseStatus( + geofenceId, + translateToGeofenceHardwareStatus(result)); + } + + private void onGeofenceResume(int geofenceId, int result) { + getGeofenceHardwareSink().reportGeofenceResumeStatus( + geofenceId, + translateToGeofenceHardwareStatus(result)); + } + + /** + * 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( + GeofenceHardwareRequestParcelable[] geofenceRequestsArray); + 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) { + synchronized (mLocationSinkLock) { + // 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) { + synchronized (mLocationSinkLock) { + // 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(GeofenceHardwareRequestParcelable[] geofenceRequestsArray) { + nativeAddGeofences(geofenceRequestsArray); + } + + @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, + int sourcesToUse) { + nativeModifyGeofenceOption( + geofenceId, + lastTransition, + monitorTransitions, + notificationResponsiveness, + unknownTimer, + sourcesToUse); + } + }; + + /** + * 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) { + mGeofenceHardwareSink = GeofenceHardwareImpl.getInstance(mContext); + } + + return mGeofenceHardwareSink; + } + + private static int translateToGeofenceHardwareStatus(int flpHalResult) { + switch(flpHalResult) { + case FLP_RESULT_SUCCESS: + return GeofenceHardware.GEOFENCE_SUCCESS; + case FLP_RESULT_ERROR: + return GeofenceHardware.GEOFENCE_FAILURE; + // TODO: uncomment this once the ERROR definition is marked public + //case FLP_RESULT_INSUFFICIENT_MEMORY: + // return GeofenceHardware.GEOFENCE_ERROR_INSUFFICIENT_MEMORY; + case FLP_RESULT_TOO_MANY_GEOFENCES: + return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; + case FLP_RESULT_ID_EXISTS: + return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; + case FLP_RESULT_ID_UNKNOWN: + return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; + case FLP_RESULT_INVALID_GEOFENCE_TRANSITION: + return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; + default: + Log.e(TAG, String.format("Invalid FlpHal result code: %d", flpHalResult)); + return GeofenceHardware.GEOFENCE_FAILURE; + } + } + + private Location updateLocationInformation(Location location) { + location.setProvider(LocationManager.FUSED_PROVIDER); + // set the elapsed time-stamp just as GPS provider does + location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); + return location; + } +} |