1 package com.android.server.location;
2 
3 import android.location.IGpsGeofenceHardware;
4 import android.util.Log;
5 import android.util.SparseArray;
6 
7 import com.android.internal.annotations.GuardedBy;
8 import com.android.internal.annotations.VisibleForTesting;
9 
10 /**
11  * Manages GNSS Geofence operations.
12  */
13 class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub {
14 
15     private static final String TAG = "GnssGeofenceProvider";
16     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
17 
18     /** Holds the parameters of a geofence. */
19     private static class GeofenceEntry {
20         public int geofenceId;
21         public double latitude;
22         public double longitude;
23         public double radius;
24         public int lastTransition;
25         public int monitorTransitions;
26         public int notificationResponsiveness;
27         public int unknownTimer;
28         public boolean paused;
29     }
30 
31     private final Object mLock = new Object();
32     @GuardedBy("mLock")
33     private final GnssGeofenceProviderNative mNative;
34     @GuardedBy("mLock")
35     private final SparseArray<GeofenceEntry> mGeofenceEntries = new SparseArray<>();
36 
GnssGeofenceProvider()37     GnssGeofenceProvider() {
38         this(new GnssGeofenceProviderNative());
39     }
40 
41     @VisibleForTesting
GnssGeofenceProvider(GnssGeofenceProviderNative gnssGeofenceProviderNative)42     GnssGeofenceProvider(GnssGeofenceProviderNative gnssGeofenceProviderNative) {
43         mNative = gnssGeofenceProviderNative;
44     }
45 
resumeIfStarted()46     void resumeIfStarted() {
47         if (DEBUG) {
48             Log.d(TAG, "resumeIfStarted");
49         }
50         synchronized (mLock) {
51             for (int i = 0; i < mGeofenceEntries.size(); i++) {
52                 GeofenceEntry entry = mGeofenceEntries.valueAt(i);
53                 boolean added = mNative.addGeofence(entry.geofenceId, entry.latitude,
54                         entry.longitude,
55                         entry.radius,
56                         entry.lastTransition, entry.monitorTransitions,
57                         entry.notificationResponsiveness, entry.unknownTimer);
58                 if (added && entry.paused) {
59                     mNative.pauseGeofence(entry.geofenceId);
60                 }
61             }
62         }
63     }
64 
65     @Override
isHardwareGeofenceSupported()66     public boolean isHardwareGeofenceSupported() {
67         synchronized (mLock) {
68             return mNative.isGeofenceSupported();
69         }
70     }
71 
72     @Override
addCircularHardwareGeofence(int geofenceId, double latitude, double longitude, double radius, int lastTransition, int monitorTransitions, int notificationResponsiveness, int unknownTimer)73     public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
74             double longitude, double radius, int lastTransition, int monitorTransitions,
75             int notificationResponsiveness, int unknownTimer) {
76         synchronized (mLock) {
77             boolean added = mNative.addGeofence(geofenceId, latitude, longitude, radius,
78                     lastTransition, monitorTransitions, notificationResponsiveness,
79                     unknownTimer);
80             if (added) {
81                 GeofenceEntry entry = new GeofenceEntry();
82                 entry.geofenceId = geofenceId;
83                 entry.latitude = latitude;
84                 entry.longitude = longitude;
85                 entry.radius = radius;
86                 entry.lastTransition = lastTransition;
87                 entry.monitorTransitions = monitorTransitions;
88                 entry.notificationResponsiveness = notificationResponsiveness;
89                 entry.unknownTimer = unknownTimer;
90                 mGeofenceEntries.put(geofenceId, entry);
91             }
92             return added;
93         }
94     }
95 
96     @Override
removeHardwareGeofence(int geofenceId)97     public boolean removeHardwareGeofence(int geofenceId) {
98         synchronized (mLock) {
99             boolean removed = mNative.removeGeofence(geofenceId);
100             if (removed) {
101                 mGeofenceEntries.remove(geofenceId);
102             }
103             return removed;
104         }
105     }
106 
107     @Override
pauseHardwareGeofence(int geofenceId)108     public boolean pauseHardwareGeofence(int geofenceId) {
109         synchronized (mLock) {
110             boolean paused = mNative.pauseGeofence(geofenceId);
111             if (paused) {
112                 GeofenceEntry entry = mGeofenceEntries.get(geofenceId);
113                 if (entry != null) {
114                     entry.paused = true;
115                 }
116             }
117             return paused;
118         }
119     }
120 
121     @Override
resumeHardwareGeofence(int geofenceId, int monitorTransitions)122     public boolean resumeHardwareGeofence(int geofenceId, int monitorTransitions) {
123         synchronized (mLock) {
124             boolean resumed = mNative.resumeGeofence(geofenceId, monitorTransitions);
125             if (resumed) {
126                 GeofenceEntry entry = mGeofenceEntries.get(geofenceId);
127                 if (entry != null) {
128                     entry.paused = false;
129                     entry.monitorTransitions = monitorTransitions;
130                 }
131             }
132             return resumed;
133         }
134     }
135 
136     @VisibleForTesting
137     static class GnssGeofenceProviderNative {
isGeofenceSupported()138         public boolean isGeofenceSupported() {
139             return native_is_geofence_supported();
140         }
141 
addGeofence(int geofenceId, double latitude, double longitude, double radius, int lastTransition, int monitorTransitions, int notificationResponsiveness, int unknownTimer)142         public boolean addGeofence(int geofenceId, double latitude, double longitude, double radius,
143                 int lastTransition, int monitorTransitions, int notificationResponsiveness,
144                 int unknownTimer) {
145             return native_add_geofence(geofenceId, latitude, longitude, radius, lastTransition,
146                     monitorTransitions, notificationResponsiveness, unknownTimer);
147         }
148 
removeGeofence(int geofenceId)149         public boolean removeGeofence(int geofenceId) {
150             return native_remove_geofence(geofenceId);
151         }
152 
resumeGeofence(int geofenceId, int transitions)153         public boolean resumeGeofence(int geofenceId, int transitions) {
154             return native_resume_geofence(geofenceId, transitions);
155         }
156 
pauseGeofence(int geofenceId)157         public boolean pauseGeofence(int geofenceId) {
158             return native_pause_geofence(geofenceId);
159         }
160     }
161 
native_is_geofence_supported()162     private static native boolean native_is_geofence_supported();
163 
native_add_geofence(int geofenceId, double latitude, double longitude, double radius, int lastTransition, int monitorTransitions, int notificationResponsivenes, int unknownTimer)164     private static native boolean native_add_geofence(int geofenceId, double latitude,
165             double longitude, double radius, int lastTransition, int monitorTransitions,
166             int notificationResponsivenes, int unknownTimer);
167 
native_remove_geofence(int geofenceId)168     private static native boolean native_remove_geofence(int geofenceId);
169 
native_resume_geofence(int geofenceId, int transitions)170     private static native boolean native_resume_geofence(int geofenceId, int transitions);
171 
native_pause_geofence(int geofenceId)172     private static native boolean native_pause_geofence(int geofenceId);
173 }
174