blob: 226c18c2ad8ef0241fa1493929977a6b67fbe074 [file] [log] [blame]
destradaa1af4b022013-07-12 15:43:36 -07001/*
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.GeofenceHardwareImpl;
20import android.hardware.location.IFusedLocationHardware;
21import android.hardware.location.IFusedLocationHardwareSink;
22import android.location.IFusedGeofenceHardware;
23import android.location.FusedBatchOptions;
24import android.location.Geofence;
25import android.location.Location;
26import android.location.LocationListener;
27import android.location.LocationManager;
28
29import android.content.Context;
30import android.os.Bundle;
destradaa64be0c62013-08-09 15:01:49 -070031import android.os.Looper;
destradaa1af4b022013-07-12 15:43:36 -070032import android.os.RemoteException;
33import android.os.SystemClock;
34import android.util.Log;
destradaa1af4b022013-07-12 15:43:36 -070035
36/**
37 * This class is an interop layer for JVM types and the JNI code that interacts
38 * with the FLP HAL implementation.
39 *
40 * {@hide}
41 */
42public class FlpHardwareProvider {
43 private GeofenceHardwareImpl mGeofenceHardwareSink = null;
44 private IFusedLocationHardwareSink mLocationSink = null;
45
46 private static FlpHardwareProvider sSingletonInstance = null;
47
48 private final static String TAG = "FlpHardwareProvider";
49 private final Context mContext;
destradaa64be0c62013-08-09 15:01:49 -070050 private final Object mLocationSinkLock = new Object();
destradaa1af4b022013-07-12 15:43:36 -070051
52 public static FlpHardwareProvider getInstance(Context context) {
53 if (sSingletonInstance == null) {
54 sSingletonInstance = new FlpHardwareProvider(context);
55 }
56
57 return sSingletonInstance;
58 }
59
60 private FlpHardwareProvider(Context context) {
61 mContext = context;
62
63 // register for listening for passive provider data
destradaa1af4b022013-07-12 15:43:36 -070064 LocationManager manager = (LocationManager) mContext.getSystemService(
65 Context.LOCATION_SERVICE);
66 manager.requestLocationUpdates(
67 LocationManager.PASSIVE_PROVIDER,
68 0 /* minTime */,
69 0 /* minDistance */,
70 new NetworkLocationListener(),
destradaa64be0c62013-08-09 15:01:49 -070071 Looper.myLooper());
destradaa1af4b022013-07-12 15:43:36 -070072 }
73
74 public static boolean isSupported() {
75 return nativeIsSupported();
76 }
77
78 /**
79 * Private callback functions used by FLP HAL.
80 */
81 // FlpCallbacks members
82 private void onLocationReport(Location[] locations) {
83 for (Location location : locations) {
84 location.setProvider(LocationManager.FUSED_PROVIDER);
85 // set the elapsed time-stamp just as GPS provider does
86 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
87 }
88
destradaa64be0c62013-08-09 15:01:49 -070089 IFusedLocationHardwareSink sink;
90 synchronized (mLocationSinkLock) {
91 sink = mLocationSink;
92 }
destradaa1af4b022013-07-12 15:43:36 -070093 try {
destradaa64be0c62013-08-09 15:01:49 -070094 if (sink != null) {
95 sink.onLocationAvailable(locations);
destradaa1af4b022013-07-12 15:43:36 -070096 }
97 } catch (RemoteException e) {
98 Log.e(TAG, "RemoteException calling onLocationAvailable");
99 }
100 }
101
102 // FlpDiagnosticCallbacks members
103 private void onDataReport(String data) {
destradaa64be0c62013-08-09 15:01:49 -0700104 IFusedLocationHardwareSink sink;
105 synchronized (mLocationSinkLock) {
106 sink = mLocationSink;
107 }
destradaa1af4b022013-07-12 15:43:36 -0700108 try {
109 if (mLocationSink != null) {
destradaa64be0c62013-08-09 15:01:49 -0700110 sink.onDiagnosticDataAvailable(data);
destradaa1af4b022013-07-12 15:43:36 -0700111 }
112 } catch (RemoteException e) {
113 Log.e(TAG, "RemoteException calling onDiagnosticDataAvailable");
114 }
115 }
116
117 // FlpGeofenceCallbacks members
118 private void onGeofenceTransition(
119 int geofenceId,
120 Location location,
121 int transition,
122 long timestamp,
123 int sourcesUsed
124 ) {
125 // TODO: [GeofenceIntegration] change GeofenceHardwareImpl to accept a location object
126 }
127
128 private void onGeofenceMonitorStatus(int status, int source, Location location) {
129 // TODO: [GeofenceIntegration]
130 }
131
132 private void onGeofenceAdd(int geofenceId, int result) {
133 // TODO: [GeofenceIntegration] map between GPS and FLP results to pass a consistent status
134 }
135
136 private void onGeofenceRemove(int geofenceId, int result) {
137 // TODO: [GeofenceIntegration] map between GPS and FLP results to pass a consistent status
138 }
139
140 private void onGeofencePause(int geofenceId, int result) {
141 // TODO; [GeofenceIntegration] map between GPS and FLP results
142 }
143
144 private void onGeofenceResume(int geofenceId, int result) {
145 // TODO: [GeofenceIntegration] map between GPS and FLP results
146 }
147
148 /**
149 * Private native methods accessing FLP HAL.
150 */
151 static { nativeClassInit(); }
152
153 // Core members
154 private static native void nativeClassInit();
155 private static native boolean nativeIsSupported();
156
157 // FlpLocationInterface members
158 private native void nativeInit();
159 private native int nativeGetBatchSize();
160 private native void nativeStartBatching(int requestId, FusedBatchOptions options);
161 private native void nativeUpdateBatchingOptions(int requestId, FusedBatchOptions optionsObject);
162 private native void nativeStopBatching(int id);
163 private native void nativeRequestBatchedLocation(int lastNLocations);
164 private native void nativeInjectLocation(Location location);
165 // TODO [Fix] sort out the lifetime of the instance
166 private native void nativeCleanup();
167
168 // FlpDiagnosticsInterface members
169 private native boolean nativeIsDiagnosticSupported();
170 private native void nativeInjectDiagnosticData(String data);
171
172 // FlpDeviceContextInterface members
173 private native boolean nativeIsDeviceContextSupported();
174 private native void nativeInjectDeviceContext(int deviceEnabledContext);
175
176 // FlpGeofencingInterface members
177 private native boolean nativeIsGeofencingSupported();
178 private native void nativeAddGeofences(int[] geofenceIdsArray, Geofence[] geofencesArray);
179 private native void nativePauseGeofence(int geofenceId);
180 private native void nativeResumeGeofence(int geofenceId, int monitorTransitions);
181 private native void nativeModifyGeofenceOption(
182 int geofenceId,
183 int lastTransition,
184 int monitorTransitions,
185 int notificationResponsiveness,
186 int unknownTimer,
187 int sourcesToUse);
188 private native void nativeRemoveGeofences(int[] geofenceIdsArray);
189
190 /**
191 * Interface implementations for services built on top of this functionality.
192 */
193 public static final String LOCATION = "Location";
194 public static final String GEOFENCING = "Geofencing";
195
196 public IFusedLocationHardware getLocationHardware() {
197 nativeInit();
198 return mLocationHardware;
199 }
200
201 public IFusedGeofenceHardware getGeofenceHardware() {
202 nativeInit();
203 return mGeofenceHardwareService;
204 }
205
206 private final IFusedLocationHardware mLocationHardware = new IFusedLocationHardware.Stub() {
207 @Override
208 public void registerSink(IFusedLocationHardwareSink eventSink) {
destradaa64be0c62013-08-09 15:01:49 -0700209 synchronized (mLocationSinkLock) {
210 // only one sink is allowed at the moment
211 if (mLocationSink != null) {
212 throw new RuntimeException(
213 "IFusedLocationHardware does not support multiple sinks");
214 }
destradaa1af4b022013-07-12 15:43:36 -0700215
destradaa64be0c62013-08-09 15:01:49 -0700216 mLocationSink = eventSink;
217 }
destradaa1af4b022013-07-12 15:43:36 -0700218 }
219
220 @Override
221 public void unregisterSink(IFusedLocationHardwareSink eventSink) {
destradaa64be0c62013-08-09 15:01:49 -0700222 synchronized (mLocationSinkLock) {
223 // don't throw if the sink is not registered, simply make it a no-op
224 if (mLocationSink == eventSink) {
225 mLocationSink = null;
226 }
destradaa1af4b022013-07-12 15:43:36 -0700227 }
228 }
229
230 @Override
231 public int getSupportedBatchSize() {
232 return nativeGetBatchSize();
233 }
234
235 @Override
236 public void startBatching(int requestId, FusedBatchOptions options) {
237 nativeStartBatching(requestId, options);
238 }
239
240 @Override
241 public void stopBatching(int requestId) {
242 nativeStopBatching(requestId);
243 }
244
245 @Override
246 public void updateBatchingOptions(int requestId, FusedBatchOptions options) {
247 nativeUpdateBatchingOptions(requestId, options);
248 }
249
250 @Override
251 public void requestBatchOfLocations(int batchSizeRequested) {
252 nativeRequestBatchedLocation(batchSizeRequested);
253 }
254
255 @Override
256 public boolean supportsDiagnosticDataInjection() {
257 return nativeIsDiagnosticSupported();
258 }
259
260 @Override
261 public void injectDiagnosticData(String data) {
262 nativeInjectDiagnosticData(data);
263 }
264
265 @Override
266 public boolean supportsDeviceContextInjection() {
267 return nativeIsDeviceContextSupported();
268 }
269
270 @Override
271 public void injectDeviceContext(int deviceEnabledContext) {
272 nativeInjectDeviceContext(deviceEnabledContext);
273 }
274 };
275
276 private final IFusedGeofenceHardware mGeofenceHardwareService =
277 new IFusedGeofenceHardware.Stub() {
278 @Override
279 public boolean isSupported() {
280 return nativeIsGeofencingSupported();
281 }
282
283 @Override
284 public void addGeofences(int[] geofenceIdsArray, Geofence[] geofencesArray) {
285 nativeAddGeofences(geofenceIdsArray, geofencesArray);
286 }
287
288 @Override
289 public void removeGeofences(int[] geofenceIds) {
290 nativeRemoveGeofences(geofenceIds);
291 }
292
293 @Override
294 public void pauseMonitoringGeofence(int geofenceId) {
295 nativePauseGeofence(geofenceId);
296 }
297
298 @Override
299 public void resumeMonitoringGeofence(int geofenceId, int monitorTransitions) {
300 nativeResumeGeofence(geofenceId, monitorTransitions);
301 }
302
303 @Override
304 public void modifyGeofenceOptions(int geofenceId,
305 int lastTransition,
306 int monitorTransitions,
307 int notificationResponsiveness,
308 int unknownTimer
309 ) {
310 // TODO: [GeofenceIntegration] set sourcesToUse to the right value
311 // TODO: expose sourcesToUse externally when needed
312 nativeModifyGeofenceOption(
313 geofenceId,
314 lastTransition,
315 monitorTransitions,
316 notificationResponsiveness,
317 unknownTimer,
318 /* sourcesToUse */ 0xFFFF);
319 }
320 };
321
322 /**
323 * Internal classes and functions used by the provider.
324 */
325 private final class NetworkLocationListener implements LocationListener {
326 @Override
327 public void onLocationChanged(Location location) {
328 if (
329 !LocationManager.NETWORK_PROVIDER.equals(location.getProvider()) ||
330 !location.hasAccuracy()
331 ) {
332 return;
333 }
334
335 nativeInjectLocation(location);
336 }
337
338 @Override
339 public void onStatusChanged(String provider, int status, Bundle extras) { }
340
341 @Override
342 public void onProviderEnabled(String provider) { }
343
344 @Override
345 public void onProviderDisabled(String provider) { }
346 }
347
348 private GeofenceHardwareImpl getGeofenceHardwareSink() {
349 if (mGeofenceHardwareSink == null) {
350 // TODO: [GeofenceIntegration] we need to register ourselves with GeofenceHardwareImpl
351 mGeofenceHardwareSink = GeofenceHardwareImpl.getInstance(mContext);
352 }
353
354 return mGeofenceHardwareSink;
355 }
356}