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