FlpHardwareProvider.java revision cc972725af35284c0b571aaa0dc6873e69b15119
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.location; 18 19import android.hardware.location.GeofenceHardware; 20import android.hardware.location.GeofenceHardwareImpl; 21import android.hardware.location.GeofenceHardwareRequestParcelable; 22import android.hardware.location.IFusedLocationHardware; 23import android.hardware.location.IFusedLocationHardwareSink; 24import android.location.IFusedGeofenceHardware; 25import android.location.FusedBatchOptions; 26import android.location.Location; 27import android.location.LocationListener; 28import android.location.LocationManager; 29import android.location.LocationRequest; 30 31import android.content.Context; 32import android.os.Bundle; 33import android.os.Looper; 34import android.os.RemoteException; 35import android.os.SystemClock; 36import android.util.Log; 37 38/** 39 * This class is an interop layer for JVM types and the JNI code that interacts 40 * with the FLP HAL implementation. 41 * 42 * {@hide} 43 */ 44public class FlpHardwareProvider { 45 private GeofenceHardwareImpl mGeofenceHardwareSink = null; 46 private IFusedLocationHardwareSink mLocationSink = null; 47 48 private static FlpHardwareProvider sSingletonInstance = null; 49 50 private final static String TAG = "FlpHardwareProvider"; 51 private final Context mContext; 52 private final Object mLocationSinkLock = new Object(); 53 54 // FlpHal result codes, they must be equal to the ones in fused_location.h 55 private static final int FLP_RESULT_SUCCESS = 0; 56 private static final int FLP_RESULT_ERROR = -1; 57 private static final int FLP_RESULT_INSUFFICIENT_MEMORY = -2; 58 private static final int FLP_RESULT_TOO_MANY_GEOFENCES = -3; 59 private static final int FLP_RESULT_ID_EXISTS = -4; 60 private static final int FLP_RESULT_ID_UNKNOWN = -5; 61 private static final int FLP_RESULT_INVALID_GEOFENCE_TRANSITION = -6; 62 63 // FlpHal monitor status codes, they must be equal to the ones in fused_location.h 64 private static final int FLP_GEOFENCE_MONITOR_STATUS_UNAVAILABLE = 1<<0; 65 private static final int FLP_GEOFENCE_MONITOR_STATUS_AVAILABLE = 1<<1; 66 67 public static FlpHardwareProvider getInstance(Context context) { 68 if (sSingletonInstance == null) { 69 sSingletonInstance = new FlpHardwareProvider(context); 70 } 71 72 return sSingletonInstance; 73 } 74 75 private FlpHardwareProvider(Context context) { 76 mContext = context; 77 78 // register for listening for passive provider data 79 LocationManager manager = (LocationManager) mContext.getSystemService( 80 Context.LOCATION_SERVICE); 81 final long minTime = 0; 82 final float minDistance = 0; 83 final boolean oneShot = false; 84 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 85 LocationManager.PASSIVE_PROVIDER, 86 minTime, 87 minDistance, 88 oneShot); 89 // Don't keep track of this request since it's done on behalf of other clients 90 // (which are kept track of separately). 91 request.setHideFromAppOps(true); 92 manager.requestLocationUpdates( 93 request, 94 new NetworkLocationListener(), 95 Looper.myLooper()); 96 } 97 98 public static boolean isSupported() { 99 return nativeIsSupported(); 100 } 101 102 /** 103 * Private callback functions used by FLP HAL. 104 */ 105 // FlpCallbacks members 106 private void onLocationReport(Location[] locations) { 107 for (Location location : locations) { 108 location.setProvider(LocationManager.FUSED_PROVIDER); 109 // set the elapsed time-stamp just as GPS provider does 110 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 111 } 112 113 IFusedLocationHardwareSink sink; 114 synchronized (mLocationSinkLock) { 115 sink = mLocationSink; 116 } 117 try { 118 if (sink != null) { 119 sink.onLocationAvailable(locations); 120 } 121 } catch (RemoteException e) { 122 Log.e(TAG, "RemoteException calling onLocationAvailable"); 123 } 124 } 125 126 // FlpDiagnosticCallbacks members 127 private void onDataReport(String data) { 128 IFusedLocationHardwareSink sink; 129 synchronized (mLocationSinkLock) { 130 sink = mLocationSink; 131 } 132 try { 133 if (mLocationSink != null) { 134 sink.onDiagnosticDataAvailable(data); 135 } 136 } catch (RemoteException e) { 137 Log.e(TAG, "RemoteException calling onDiagnosticDataAvailable"); 138 } 139 } 140 141 // FlpGeofenceCallbacks members 142 private void onGeofenceTransition( 143 int geofenceId, 144 Location location, 145 int transition, 146 long timestamp, 147 int sourcesUsed) { 148 // the transition Id does not require translation because the values in fused_location.h 149 // and GeofenceHardware are in sync 150 getGeofenceHardwareSink().reportGeofenceTransition( 151 geofenceId, 152 updateLocationInformation(location), 153 transition, 154 timestamp, 155 GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE, 156 sourcesUsed); 157 } 158 159 private void onGeofenceMonitorStatus(int status, int source, Location location) { 160 // allow the location to be optional in this event 161 Location updatedLocation = null; 162 if(location != null) { 163 updatedLocation = updateLocationInformation(location); 164 } 165 166 int monitorStatus; 167 switch (status) { 168 case FLP_GEOFENCE_MONITOR_STATUS_UNAVAILABLE: 169 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; 170 break; 171 case FLP_GEOFENCE_MONITOR_STATUS_AVAILABLE: 172 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; 173 break; 174 default: 175 Log.e(TAG, "Invalid FlpHal Geofence monitor status: " + status); 176 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; 177 break; 178 } 179 180 getGeofenceHardwareSink().reportGeofenceMonitorStatus( 181 GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE, 182 monitorStatus, 183 updatedLocation, 184 source); 185 } 186 187 private void onGeofenceAdd(int geofenceId, int result) { 188 getGeofenceHardwareSink().reportGeofenceAddStatus( 189 geofenceId, 190 translateToGeofenceHardwareStatus(result)); 191 } 192 193 private void onGeofenceRemove(int geofenceId, int result) { 194 getGeofenceHardwareSink().reportGeofenceRemoveStatus( 195 geofenceId, 196 translateToGeofenceHardwareStatus(result)); 197 } 198 199 private void onGeofencePause(int geofenceId, int result) { 200 getGeofenceHardwareSink().reportGeofencePauseStatus( 201 geofenceId, 202 translateToGeofenceHardwareStatus(result)); 203 } 204 205 private void onGeofenceResume(int geofenceId, int result) { 206 getGeofenceHardwareSink().reportGeofenceResumeStatus( 207 geofenceId, 208 translateToGeofenceHardwareStatus(result)); 209 } 210 211 /** 212 * Private native methods accessing FLP HAL. 213 */ 214 static { nativeClassInit(); } 215 216 // Core members 217 private static native void nativeClassInit(); 218 private static native boolean nativeIsSupported(); 219 220 // FlpLocationInterface members 221 private native void nativeInit(); 222 private native int nativeGetBatchSize(); 223 private native void nativeStartBatching(int requestId, FusedBatchOptions options); 224 private native void nativeUpdateBatchingOptions(int requestId, FusedBatchOptions optionsObject); 225 private native void nativeStopBatching(int id); 226 private native void nativeRequestBatchedLocation(int lastNLocations); 227 private native void nativeInjectLocation(Location location); 228 // TODO [Fix] sort out the lifetime of the instance 229 private native void nativeCleanup(); 230 231 // FlpDiagnosticsInterface members 232 private native boolean nativeIsDiagnosticSupported(); 233 private native void nativeInjectDiagnosticData(String data); 234 235 // FlpDeviceContextInterface members 236 private native boolean nativeIsDeviceContextSupported(); 237 private native void nativeInjectDeviceContext(int deviceEnabledContext); 238 239 // FlpGeofencingInterface members 240 private native boolean nativeIsGeofencingSupported(); 241 private native void nativeAddGeofences( 242 GeofenceHardwareRequestParcelable[] geofenceRequestsArray); 243 private native void nativePauseGeofence(int geofenceId); 244 private native void nativeResumeGeofence(int geofenceId, int monitorTransitions); 245 private native void nativeModifyGeofenceOption( 246 int geofenceId, 247 int lastTransition, 248 int monitorTransitions, 249 int notificationResponsiveness, 250 int unknownTimer, 251 int sourcesToUse); 252 private native void nativeRemoveGeofences(int[] geofenceIdsArray); 253 254 /** 255 * Interface implementations for services built on top of this functionality. 256 */ 257 public static final String LOCATION = "Location"; 258 public static final String GEOFENCING = "Geofencing"; 259 260 public IFusedLocationHardware getLocationHardware() { 261 nativeInit(); 262 return mLocationHardware; 263 } 264 265 public IFusedGeofenceHardware getGeofenceHardware() { 266 nativeInit(); 267 return mGeofenceHardwareService; 268 } 269 270 private final IFusedLocationHardware mLocationHardware = new IFusedLocationHardware.Stub() { 271 @Override 272 public void registerSink(IFusedLocationHardwareSink eventSink) { 273 synchronized (mLocationSinkLock) { 274 // only one sink is allowed at the moment 275 if (mLocationSink != null) { 276 throw new RuntimeException( 277 "IFusedLocationHardware does not support multiple sinks"); 278 } 279 280 mLocationSink = eventSink; 281 } 282 } 283 284 @Override 285 public void unregisterSink(IFusedLocationHardwareSink eventSink) { 286 synchronized (mLocationSinkLock) { 287 // don't throw if the sink is not registered, simply make it a no-op 288 if (mLocationSink == eventSink) { 289 mLocationSink = null; 290 } 291 } 292 } 293 294 @Override 295 public int getSupportedBatchSize() { 296 return nativeGetBatchSize(); 297 } 298 299 @Override 300 public void startBatching(int requestId, FusedBatchOptions options) { 301 nativeStartBatching(requestId, options); 302 } 303 304 @Override 305 public void stopBatching(int requestId) { 306 nativeStopBatching(requestId); 307 } 308 309 @Override 310 public void updateBatchingOptions(int requestId, FusedBatchOptions options) { 311 nativeUpdateBatchingOptions(requestId, options); 312 } 313 314 @Override 315 public void requestBatchOfLocations(int batchSizeRequested) { 316 nativeRequestBatchedLocation(batchSizeRequested); 317 } 318 319 @Override 320 public boolean supportsDiagnosticDataInjection() { 321 return nativeIsDiagnosticSupported(); 322 } 323 324 @Override 325 public void injectDiagnosticData(String data) { 326 nativeInjectDiagnosticData(data); 327 } 328 329 @Override 330 public boolean supportsDeviceContextInjection() { 331 return nativeIsDeviceContextSupported(); 332 } 333 334 @Override 335 public void injectDeviceContext(int deviceEnabledContext) { 336 nativeInjectDeviceContext(deviceEnabledContext); 337 } 338 }; 339 340 private final IFusedGeofenceHardware mGeofenceHardwareService = 341 new IFusedGeofenceHardware.Stub() { 342 @Override 343 public boolean isSupported() { 344 return nativeIsGeofencingSupported(); 345 } 346 347 @Override 348 public void addGeofences(GeofenceHardwareRequestParcelable[] geofenceRequestsArray) { 349 nativeAddGeofences(geofenceRequestsArray); 350 } 351 352 @Override 353 public void removeGeofences(int[] geofenceIds) { 354 nativeRemoveGeofences(geofenceIds); 355 } 356 357 @Override 358 public void pauseMonitoringGeofence(int geofenceId) { 359 nativePauseGeofence(geofenceId); 360 } 361 362 @Override 363 public void resumeMonitoringGeofence(int geofenceId, int monitorTransitions) { 364 nativeResumeGeofence(geofenceId, monitorTransitions); 365 } 366 367 @Override 368 public void modifyGeofenceOptions(int geofenceId, 369 int lastTransition, 370 int monitorTransitions, 371 int notificationResponsiveness, 372 int unknownTimer, 373 int sourcesToUse) { 374 nativeModifyGeofenceOption( 375 geofenceId, 376 lastTransition, 377 monitorTransitions, 378 notificationResponsiveness, 379 unknownTimer, 380 sourcesToUse); 381 } 382 }; 383 384 /** 385 * Internal classes and functions used by the provider. 386 */ 387 private final class NetworkLocationListener implements LocationListener { 388 @Override 389 public void onLocationChanged(Location location) { 390 if ( 391 !LocationManager.NETWORK_PROVIDER.equals(location.getProvider()) || 392 !location.hasAccuracy() 393 ) { 394 return; 395 } 396 397 nativeInjectLocation(location); 398 } 399 400 @Override 401 public void onStatusChanged(String provider, int status, Bundle extras) { } 402 403 @Override 404 public void onProviderEnabled(String provider) { } 405 406 @Override 407 public void onProviderDisabled(String provider) { } 408 } 409 410 private GeofenceHardwareImpl getGeofenceHardwareSink() { 411 if (mGeofenceHardwareSink == null) { 412 mGeofenceHardwareSink = GeofenceHardwareImpl.getInstance(mContext); 413 } 414 415 return mGeofenceHardwareSink; 416 } 417 418 private static int translateToGeofenceHardwareStatus(int flpHalResult) { 419 switch(flpHalResult) { 420 case FLP_RESULT_SUCCESS: 421 return GeofenceHardware.GEOFENCE_SUCCESS; 422 case FLP_RESULT_ERROR: 423 return GeofenceHardware.GEOFENCE_FAILURE; 424 // TODO: uncomment this once the ERROR definition is marked public 425 //case FLP_RESULT_INSUFFICIENT_MEMORY: 426 // return GeofenceHardware.GEOFENCE_ERROR_INSUFFICIENT_MEMORY; 427 case FLP_RESULT_TOO_MANY_GEOFENCES: 428 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; 429 case FLP_RESULT_ID_EXISTS: 430 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; 431 case FLP_RESULT_ID_UNKNOWN: 432 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; 433 case FLP_RESULT_INVALID_GEOFENCE_TRANSITION: 434 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; 435 default: 436 Log.e(TAG, String.format("Invalid FlpHal result code: %d", flpHalResult)); 437 return GeofenceHardware.GEOFENCE_FAILURE; 438 } 439 } 440 441 private Location updateLocationInformation(Location location) { 442 location.setProvider(LocationManager.FUSED_PROVIDER); 443 // set the elapsed time-stamp just as GPS provider does 444 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 445 return location; 446 } 447} 448