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