blob: a1866af4370677c89f791e8c4219e484a2d57b0e [file] [log] [blame]
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -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 */
16package android.hardware.location;
17
destradaac4e1e592014-08-15 11:33:57 -070018import android.annotation.SystemApi;
Artur Satayev26958002019-12-10 17:47:52 +000019import android.compat.annotation.UnsupportedAppUsage;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070020import android.location.Location;
destradaaf9a274c2014-07-25 15:11:56 -070021import android.os.Build;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070022import android.os.RemoteException;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070023
24import java.lang.ref.WeakReference;
25import java.util.HashMap;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070026
27/**
28 * This class handles geofences managed by various hardware subsystems. It contains
29 * the public APIs that is needed to accomplish the task.
30 *
31 * <p>The APIs should not be called directly by the app developers. A higher level api
32 * which abstracts the hardware should be used instead. All the checks are done by the higher
33 * level public API. Any needed locking should be handled by the higher level API.
34 *
35 * <p> There are 3 states associated with a Geofence: Inside, Outside, Unknown.
36 * There are 3 transitions: {@link #GEOFENCE_ENTERED}, {@link #GEOFENCE_EXITED},
37 * {@link #GEOFENCE_UNCERTAIN}. The APIs only expose the transitions.
38 *
39 * <p> Inside state: The hardware subsystem is reasonably confident that the user is inside
40 * the geofence. Outside state: The hardware subsystem is reasonably confident that the user
41 * is outside the geofence Unknown state: Unknown state can be interpreted as a state in which the
42 * monitoring subsystem isn't confident enough that the user is either inside or
43 * outside the Geofence. If the accuracy does not improve for a sufficient period of time,
44 * the {@link #GEOFENCE_UNCERTAIN} transition would be triggered. If the accuracy improves later,
45 * an appropriate transition would be triggered. The "reasonably confident" parameter
46 * depends on the hardware system and the positioning algorithms used.
47 * For instance, {@link #MONITORING_TYPE_GPS_HARDWARE} uses 95% as a confidence level.
destradaac4e1e592014-08-15 11:33:57 -070048 *
49 * @hide
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070050 */
destradaac4e1e592014-08-15 11:33:57 -070051@SystemApi
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070052public final class GeofenceHardware {
53 private IGeofenceHardware mService;
54
55 // Hardware systems that do geofence monitoring.
destradaa0682809a2013-08-12 18:50:30 -070056 static final int NUM_MONITORS = 2;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070057
58 /**
59 * Constant for geofence monitoring done by the GPS hardware.
60 */
61 public static final int MONITORING_TYPE_GPS_HARDWARE = 0;
62
63 /**
destradaa0682809a2013-08-12 18:50:30 -070064 * Constant for geofence monitoring done by the Fused hardware.
destradaa0682809a2013-08-12 18:50:30 -070065 */
66 public static final int MONITORING_TYPE_FUSED_HARDWARE = 1;
67
68 /**
destradaaf9a274c2014-07-25 15:11:56 -070069 * Constant to indicate that the monitoring system is currently
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070070 * available for monitoring geofences.
71 */
72 public static final int MONITOR_CURRENTLY_AVAILABLE = 0;
73
74 /**
destradaaf9a274c2014-07-25 15:11:56 -070075 * Constant to indicate that the monitoring system is currently
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070076 * unavailable for monitoring geofences.
77 */
78 public static final int MONITOR_CURRENTLY_UNAVAILABLE = 1;
79
80 /**
destradaaf9a274c2014-07-25 15:11:56 -070081 * Constant to indicate that the monitoring system is unsupported
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070082 * for hardware geofence monitoring.
83 */
84 public static final int MONITOR_UNSUPPORTED = 2;
85
destradaacc972722014-04-25 11:37:52 -070086 // The following constants need to match geofence flags in gps.h and fused_location.h
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070087 /**
88 * The constant to indicate that the user has entered the geofence.
89 */
90 public static final int GEOFENCE_ENTERED = 1<<0L;
91
92 /**
93 * The constant to indicate that the user has exited the geofence.
94 */
95 public static final int GEOFENCE_EXITED = 1<<1L;
96
97 /**
98 * The constant to indicate that the user is uncertain with respect to a
destradaacc972722014-04-25 11:37:52 -070099 * geofence.
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700100 */
101 public static final int GEOFENCE_UNCERTAIN = 1<<2L;
102
103 /**
104 * The constant used to indicate success of the particular geofence call
105 */
106 public static final int GEOFENCE_SUCCESS = 0;
107
108 /**
109 * The constant used to indicate that too many geofences have been registered.
110 */
111 public static final int GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 1;
112
113 /**
114 * The constant used to indicate that the geofence id already exists.
115 */
116 public static final int GEOFENCE_ERROR_ID_EXISTS = 2;
117
118 /**
119 * The constant used to indicate that the geofence id is unknown.
120 */
121 public static final int GEOFENCE_ERROR_ID_UNKNOWN = 3;
122
123 /**
124 * The constant used to indicate that the transition requested for the geofence is invalid.
125 */
126 public static final int GEOFENCE_ERROR_INVALID_TRANSITION = 4;
127
128 /**
129 * The constant used to indicate that the geofence operation has failed.
130 */
131 public static final int GEOFENCE_FAILURE = 5;
132
destradaa0682809a2013-08-12 18:50:30 -0700133 /**
134 * The constant used to indicate that the operation failed due to insufficient memory.
destradaa0682809a2013-08-12 18:50:30 -0700135 */
136 public static final int GEOFENCE_ERROR_INSUFFICIENT_MEMORY = 6;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700137
destradaaf9a274c2014-07-25 15:11:56 -0700138 // the following values must match the definitions in fused_location.h
139
140 /**
141 * The constant used to indicate that the monitoring system supports GNSS.
142 */
143 public static final int SOURCE_TECHNOLOGY_GNSS = (1<<0);
144
145 /**
146 * The constant used to indicate that the monitoring system supports WiFi.
147 */
148 public static final int SOURCE_TECHNOLOGY_WIFI = (1<<1);
149
150 /**
151 * The constant used to indicate that the monitoring system supports Sensors.
152 */
153 public static final int SOURCE_TECHNOLOGY_SENSORS = (1<<2);
154
155 /**
156 * The constant used to indicate that the monitoring system supports Cell.
157 */
158 public static final int SOURCE_TECHNOLOGY_CELL = (1<<3);
159
160 /**
161 * The constant used to indicate that the monitoring system supports Bluetooth.
162 */
163 public static final int SOURCE_TECHNOLOGY_BLUETOOTH = (1<<4);
164
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700165 private HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>
166 mCallbacks = new HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>();
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700167 private HashMap<GeofenceHardwareMonitorCallback, GeofenceHardwareMonitorCallbackWrapper>
168 mMonitorCallbacks = new HashMap<GeofenceHardwareMonitorCallback,
169 GeofenceHardwareMonitorCallbackWrapper>();
destradaac4e1e592014-08-15 11:33:57 -0700170
Michael Wright05c68d32016-12-02 14:26:11 +0000171 /** @hide */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100172 @UnsupportedAppUsage
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700173 public GeofenceHardware(IGeofenceHardware service) {
174 mService = service;
175 }
176
177 /**
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700178 * Returns all the hardware geofence monitoring systems which are supported
179 *
180 * <p> Call {@link #getStatusOfMonitoringType(int)} to know the current state
181 * of a monitoring system.
182 *
183 * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
184 * geofencing in hardware.
185 *
186 * @return An array of all the monitoring types.
187 * An array of length 0 is returned in case of errors.
188 */
189 public int[] getMonitoringTypes() {
190 try {
191 return mService.getMonitoringTypes();
192 } catch (RemoteException e) {
193 }
194 return new int[0];
195 }
196
197 /**
198 * Returns current status of a hardware geofence monitoring system.
199 *
200 * <p>Status can be one of {@link #MONITOR_CURRENTLY_AVAILABLE},
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700201 * {@link #MONITOR_CURRENTLY_UNAVAILABLE} or {@link #MONITOR_UNSUPPORTED}
202 *
203 * <p> Some supported hardware monitoring systems might not be available
204 * for monitoring geofences in certain scenarios. For example, when a user
205 * enters a building, the GPS hardware subsystem might not be able monitor
206 * geofences and will change from {@link #MONITOR_CURRENTLY_AVAILABLE} to
207 * {@link #MONITOR_CURRENTLY_UNAVAILABLE}.
208 *
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700209 * @param monitoringType
210 * @return Current status of the monitoring type.
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700211 */
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700212 public int getStatusOfMonitoringType(int monitoringType) {
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700213 try {
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700214 return mService.getStatusOfMonitoringType(monitoringType);
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700215 } catch (RemoteException e) {
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700216 return MONITOR_UNSUPPORTED;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700217 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700218 }
219
220 /**
221 * Creates a circular geofence which is monitored by subsystems in the hardware.
222 *
223 * <p> When the device detects that is has entered, exited or is uncertain
224 * about the area specified by the geofence, the given callback will be called.
225 *
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700226 * <p> If this call returns true, it means that the geofence has been sent to the hardware.
227 * {@link GeofenceHardwareCallback#onGeofenceAdd} will be called with the result of the
228 * add call from the hardware. The {@link GeofenceHardwareCallback#onGeofenceAdd} will be
229 * called with the following parameters when a transition event occurs.
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700230 * <ul>
231 * <li> The geofence Id
232 * <li> The location object indicating the last known location.
233 * <li> The transition associated with the geofence. One of
234 * {@link #GEOFENCE_ENTERED}, {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
235 * <li> The timestamp when the geofence transition occured.
236 * <li> The monitoring type ({@link #MONITORING_TYPE_GPS_HARDWARE} is one such example)
237 * that was used.
238 * </ul>
239 *
240 * <p> The geofence will be monitored by the subsystem specified by monitoring_type parameter.
241 * The application does not need to hold a wakelock when the monitoring
242 * is being done by the underlying hardware subsystem. If the same geofence Id is being
243 * monitored by two different monitoring systems, the same id can be used for both calls, as
244 * long as the same callback object is used.
245 *
246 * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
247 * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
248 *
249 * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
250 * geofencing in hardware.
251 *
252 * <p>This API should not be called directly by the app developers. A higher level api
253 * which abstracts the hardware should be used instead. All the checks are done by the higher
254 * level public API. Any needed locking should be handled by the higher level API.
255 *
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700256 * <p> Create a geofence request object using the methods in {@link GeofenceHardwareRequest} to
257 * set all the characteristics of the geofence. Use the created GeofenceHardwareRequest object
258 * in this call.
259 *
260 * @param geofenceId The id associated with the geofence.
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700261 * @param monitoringType The type of the hardware subsystem that should be used
262 * to monitor the geofence.
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700263 * @param geofenceRequest The {@link GeofenceHardwareRequest} object associated with the
264 * geofence.
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700265 * @param callback {@link GeofenceHardwareCallback} that will be use to notify the
266 * transition.
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700267 * @return true when the geofence is successfully sent to the hardware for addition.
268 * @throws IllegalArgumentException when the geofence request type is not supported.
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700269 */
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700270 public boolean addGeofence(int geofenceId, int monitoringType, GeofenceHardwareRequest
271 geofenceRequest, GeofenceHardwareCallback callback) {
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700272 try {
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700273 if (geofenceRequest.getType() == GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) {
destradaaf9a274c2014-07-25 15:11:56 -0700274 return mService.addCircularFence(
275 monitoringType,
276 new GeofenceHardwareRequestParcelable(geofenceId, geofenceRequest),
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700277 getCallbackWrapper(callback));
278 } else {
279 throw new IllegalArgumentException("Geofence Request type not supported");
280 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700281 } catch (RemoteException e) {
282 }
283 return false;
284 }
285
286 /**
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700287 * Removes a geofence added by {@link #addGeofence} call.
288 *
289 * <p> If this call returns true, it means that the geofence has been sent to the hardware.
290 * {@link GeofenceHardwareCallback#onGeofenceRemove} will be called with the result of the
291 * remove call from the hardware.
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700292 *
293 * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
294 * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
295 *
296 * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
297 * geofencing in hardware.
298 *
299 * <p>This API should not be called directly by the app developers. A higher level api
300 * which abstracts the hardware should be used instead. All the checks are done by the higher
301 * level public API. Any needed locking should be handled by the higher level API.
302 *
303 * @param geofenceId The id of the geofence.
304 * @param monitoringType The type of the hardware subsystem that should be used
305 * to monitor the geofence.
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700306 * @return true when the geofence is successfully sent to the hardware for removal. .
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700307 */
308 public boolean removeGeofence(int geofenceId, int monitoringType) {
309 try {
310 return mService.removeGeofence(geofenceId, monitoringType);
311 } catch (RemoteException e) {
312 }
313 return false;
314 }
315
316 /**
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700317 * Pauses the monitoring of a geofence added by {@link #addGeofence} call.
318 *
319 * <p> If this call returns true, it means that the geofence has been sent to the hardware.
320 * {@link GeofenceHardwareCallback#onGeofencePause} will be called with the result of the
321 * pause call from the hardware.
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700322 *
323 * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
324 * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
325 *
326 * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
327 * geofencing in hardware.
328 *
329 * <p>This API should not be called directly by the app developers. A higher level api
330 * which abstracts the hardware should be used instead. All the checks are done by the higher
331 * level public API. Any needed locking should be handled by the higher level API.
332 *
333 * @param geofenceId The id of the geofence.
334 * @param monitoringType The type of the hardware subsystem that should be used
335 * to monitor the geofence.
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700336 * @return true when the geofence is successfully sent to the hardware for pausing.
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700337 */
338 public boolean pauseGeofence(int geofenceId, int monitoringType) {
339 try {
340 return mService.pauseGeofence(geofenceId, monitoringType);
341 } catch (RemoteException e) {
342 }
343 return false;
344 }
345
346 /**
347 * Resumes the monitoring of a geofence added by {@link #pauseGeofence} call.
348 *
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700349 * <p> If this call returns true, it means that the geofence has been sent to the hardware.
350 * {@link GeofenceHardwareCallback#onGeofenceResume} will be called with the result of the
351 * resume call from the hardware.
352 *
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700353 * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
354 * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
355 *
356 * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
357 * geofencing in hardware.
358 *
359 * <p>This API should not be called directly by the app developers. A higher level api
360 * which abstracts the hardware should be used instead. All the checks are done by the higher
361 * level public API. Any needed locking should be handled by the higher level API.
362 *
363 * @param geofenceId The id of the geofence.
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700364 * @param monitoringType The type of the hardware subsystem that should be used
365 * to monitor the geofence.
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700366 * @param monitorTransition Bitwise OR of {@link #GEOFENCE_ENTERED},
367 * {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
368 * @return true when the geofence is successfully sent to the hardware for resumption.
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700369 */
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700370 public boolean resumeGeofence(int geofenceId, int monitoringType, int monitorTransition) {
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700371 try {
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700372 return mService.resumeGeofence(geofenceId, monitoringType, monitorTransition);
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700373 } catch (RemoteException e) {
374 }
375 return false;
376 }
377
378 /**
379 * Register the callback to be notified when the state of a hardware geofence
380 * monitoring system changes. For instance, it can change from
381 * {@link #MONITOR_CURRENTLY_AVAILABLE} to {@link #MONITOR_CURRENTLY_UNAVAILABLE}
382 *
383 * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
384 * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
385 *
386 * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
387 * geofencing in hardware.
388 *
389 * <p>This API should not be called directly by the app developers. A higher level api
390 * which abstracts the hardware should be used instead. All the checks are done by the higher
391 * level public API. Any needed locking should be handled by the higher level API.
392 *
393 * <p> The same callback object can be used to be informed of geofence transitions
394 * and state changes of the underlying hardware subsystem.
395 *
396 * @param monitoringType Type of the monitor
397 * @param callback Callback that will be called.
398 * @return true on success
399 */
400 public boolean registerForMonitorStateChangeCallback(int monitoringType,
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700401 GeofenceHardwareMonitorCallback callback) {
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700402 try {
403 return mService.registerForMonitorStateChangeCallback(monitoringType,
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700404 getMonitorCallbackWrapper(callback));
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700405 } catch (RemoteException e) {
406 }
407 return false;
408 }
409
410 /**
411 * Unregister the callback that was used with {@link #registerForMonitorStateChangeCallback}
412 * to notify when the state of the hardware geofence monitoring system changes.
413 *
414 * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
415 * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
416 *
417 * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
418 * geofencing in hardware.
419 *
420 * <p>This API should not be called directly by the app developers. A higher level api
421 * which abstracts the hardware should be used instead. All the checks are done by the higher
422 * level public API. Any needed locking should be handled by the higher level API.
423 *
424 * @param monitoringType Type of the monitor
425 * @param callback Callback that will be called.
426 * @return true on success
427 */
428 public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700429 GeofenceHardwareMonitorCallback callback) {
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700430 boolean result = false;
431 try {
432 result = mService.unregisterForMonitorStateChangeCallback(monitoringType,
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700433 getMonitorCallbackWrapper(callback));
434 if (result) removeMonitorCallback(callback);
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700435
436 } catch (RemoteException e) {
437 }
438 return result;
439 }
440
441
442 private void removeCallback(GeofenceHardwareCallback callback) {
443 synchronized (mCallbacks) {
444 mCallbacks.remove(callback);
445 }
446 }
447
448 private GeofenceHardwareCallbackWrapper getCallbackWrapper(GeofenceHardwareCallback callback) {
449 synchronized (mCallbacks) {
450 GeofenceHardwareCallbackWrapper wrapper = mCallbacks.get(callback);
451 if (wrapper == null) {
452 wrapper = new GeofenceHardwareCallbackWrapper(callback);
453 mCallbacks.put(callback, wrapper);
454 }
455 return wrapper;
456 }
457 }
458
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700459 private void removeMonitorCallback(GeofenceHardwareMonitorCallback callback) {
460 synchronized (mMonitorCallbacks) {
461 mMonitorCallbacks.remove(callback);
462 }
463 }
464
465 private GeofenceHardwareMonitorCallbackWrapper getMonitorCallbackWrapper(
466 GeofenceHardwareMonitorCallback callback) {
467 synchronized (mMonitorCallbacks) {
468 GeofenceHardwareMonitorCallbackWrapper wrapper = mMonitorCallbacks.get(callback);
469 if (wrapper == null) {
470 wrapper = new GeofenceHardwareMonitorCallbackWrapper(callback);
471 mMonitorCallbacks.put(callback, wrapper);
472 }
473 return wrapper;
474 }
475 }
476
477 class GeofenceHardwareMonitorCallbackWrapper extends IGeofenceHardwareMonitorCallback.Stub {
478 private WeakReference<GeofenceHardwareMonitorCallback> mCallback;
479
480 GeofenceHardwareMonitorCallbackWrapper(GeofenceHardwareMonitorCallback c) {
481 mCallback = new WeakReference<GeofenceHardwareMonitorCallback>(c);
482 }
483
destradaaf9a274c2014-07-25 15:11:56 -0700484 public void onMonitoringSystemChange(GeofenceHardwareMonitorEvent event) {
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700485 GeofenceHardwareMonitorCallback c = mCallback.get();
destradaaf9a274c2014-07-25 15:11:56 -0700486 if (c == null) return;
487
488 // report the legacy event first, so older clients are not broken
489 c.onMonitoringSystemChange(
490 event.getMonitoringType(),
491 event.getMonitoringStatus() == GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE,
492 event.getLocation());
493
494 // and only call the updated callback on on L and above, this complies with the
495 // documentation of GeofenceHardwareMonitorCallback
Dianne Hackborn955d8d62014-10-07 20:17:19 -0700496 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
destradaaf9a274c2014-07-25 15:11:56 -0700497 c.onMonitoringSystemChange(event);
498 }
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700499 }
500 }
501
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700502 class GeofenceHardwareCallbackWrapper extends IGeofenceHardwareCallback.Stub {
503 private WeakReference<GeofenceHardwareCallback> mCallback;
504
505 GeofenceHardwareCallbackWrapper(GeofenceHardwareCallback c) {
506 mCallback = new WeakReference<GeofenceHardwareCallback>(c);
507 }
508
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700509 public void onGeofenceTransition(int geofenceId, int transition, Location location,
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700510 long timestamp, int monitoringType) {
511 GeofenceHardwareCallback c = mCallback.get();
512 if (c != null) {
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700513 c.onGeofenceTransition(geofenceId, transition, location, timestamp,
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700514 monitoringType);
515 }
516 }
517
518 public void onGeofenceAdd(int geofenceId, int status) {
519 GeofenceHardwareCallback c = mCallback.get();
520 if (c != null) c.onGeofenceAdd(geofenceId, status);
521 }
522
523 public void onGeofenceRemove(int geofenceId, int status) {
524 GeofenceHardwareCallback c = mCallback.get();
525 if (c != null) {
526 c.onGeofenceRemove(geofenceId, status);
527 removeCallback(c);
528 }
529 }
530
531 public void onGeofencePause(int geofenceId, int status) {
532 GeofenceHardwareCallback c = mCallback.get();
Jaikumar Ganeshda650892013-04-17 12:19:10 -0700533 if (c != null) {
534 c.onGeofencePause(geofenceId, status);
535 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700536 }
537
538 public void onGeofenceResume(int geofenceId, int status) {
539 GeofenceHardwareCallback c = mCallback.get();
540 if (c != null) c.onGeofenceResume(geofenceId, status);
541 }
542 }
543}