content: package com.android.server.location;
  
  import android.location.IGpsGeofenceHardware;
  import android.util.Log;
  import android.util.SparseArray;
  
  import com.android.internal.annotations.GuardedBy;
  import com.android.internal.annotations.VisibleForTesting;
  
  /**
   * Manages GNSS Geofence operations.
   */
  class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub {
  
      private static final String TAG = "GnssGeofenceProvider";
      private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
  
      /** Holds the parameters of a geofence. */
      private static class GeofenceEntry {
          public int geofenceId;
          public double latitude;
          public double longitude;
          public double radius;
          public int lastTransition;
          public int monitorTransitions;
          public int notificationResponsiveness;
          public int unknownTimer;
          public boolean paused;
      }
  
      private final Object mLock = new Object();
      @GuardedBy("mLock")
      private final GnssGeofenceProviderNative mNative;
      @GuardedBy("mLock")
      private final SparseArray<GeofenceEntry> mGeofenceEntries = new SparseArray<>();
  
      GnssGeofenceProvider() {
          this(new GnssGeofenceProviderNative());
      }
  
      @VisibleForTesting
      GnssGeofenceProvider(GnssGeofenceProviderNative gnssGeofenceProviderNative) {
          mNative = gnssGeofenceProviderNative;
      }
  
      void resumeIfStarted() {
          if (DEBUG) {
              Log.d(TAG, "resumeIfStarted");
          }
          synchronized (mLock) {
              for (int i = 0; i < mGeofenceEntries.size(); i++) {
                  GeofenceEntry entry = mGeofenceEntries.valueAt(i);
                  boolean added = mNative.addGeofence(entry.geofenceId, entry.latitude,
                          entry.longitude,
                          entry.radius,
                          entry.lastTransition, entry.monitorTransitions,
                          entry.notificationResponsiveness, entry.unknownTimer);
                  if (added && entry.paused) {
                      mNative.pauseGeofence(entry.geofenceId);
                  }
              }
          }
      }
  
      @Override
      public boolean isHardwareGeofenceSupported() {
          synchronized (mLock) {
              return mNative.isGeofenceSupported();
          }
      }
  
      @Override
      public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
              double longitude, double radius, int lastTransition, int monitorTransitions,
              int notificationResponsiveness, int unknownTimer) {
          synchronized (mLock) {
              boolean added = mNative.addGeofence(geofenceId, latitude, longitude, radius,
                      lastTransition, monitorTransitions, notificationResponsiveness,
                      unknownTimer);
              if (added) {
                  GeofenceEntry entry = new GeofenceEntry();
                  entry.geofenceId = geofenceId;
                  entry.latitude = latitude;
                  entry.longitude = longitude;
                  entry.radius = radius;
                  entry.lastTransition = lastTransition;
                  entry.monitorTransitions = monitorTransitions;
                  entry.notificationResponsiveness = notificationResponsiveness;
                  entry.unknownTimer = unknownTimer;
                  mGeofenceEntries.put(geofenceId, entry);
              }
              return added;
          }
      }
  
      @Override
      public boolean removeHardwareGeofence(int geofenceId) {
          synchronized (mLock) {
              boolean removed = mNative.removeGeofence(geofenceId);
              if (removed) {
                  mGeofenceEntries.remove(geofenceId);
              }
              return removed;
          }
      }
  
      @Override
      public boolean pauseHardwareGeofence(int geofenceId) {
          synchronized (mLock) {
              boolean paused = mNative.pauseGeofence(geofenceId);
              if (paused) {
                  GeofenceEntry entry = mGeofenceEntries.get(geofenceId);
                  if (entry != null) {
                      entry.paused = true;
                  }
              }
              return paused;
          }
      }
  
      @Override
      public boolean resumeHardwareGeofence(int geofenceId, int monitorTransitions) {
          synchronized (mLock) {
              boolean resumed = mNative.resumeGeofence(geofenceId, monitorTransitions);
              if (resumed) {
                  GeofenceEntry entry = mGeofenceEntries.get(geofenceId);
                  if (entry != null) {
                      entry.paused = false;
                      entry.monitorTransitions = monitorTransitions;
                  }
              }
              return resumed;
          }
      }
  
      @VisibleForTesting
      static class GnssGeofenceProviderNative {
          public boolean isGeofenceSupported() {
              return native_is_geofence_supported();
          }
  
          public boolean addGeofence(int geofenceId, double latitude, double longitude, double radius,
                  int lastTransition, int monitorTransitions, int notificationResponsiveness,
                  int unknownTimer) {
              return native_add_geofence(geofenceId, latitude, longitude, radius, lastTransition,
                      monitorTransitions, notificationResponsiveness, unknownTimer);
          }
  
          public boolean removeGeofence(int geofenceId) {
              return native_remove_geofence(geofenceId);
          }
  
          public boolean resumeGeofence(int geofenceId, int transitions) {
              return native_resume_geofence(geofenceId, transitions);
          }
  
          public boolean pauseGeofence(int geofenceId) {
              return native_pause_geofence(geofenceId);
          }
      }
  
      private static native boolean native_is_geofence_supported();
  
      private static native boolean native_add_geofence(int geofenceId, double latitude,
              double longitude, double radius, int lastTransition, int monitorTransitions,
              int notificationResponsivenes, int unknownTimer);
  
      private static native boolean native_remove_geofence(int geofenceId);
  
      private static native boolean native_resume_geofence(int geofenceId, int transitions);
  
      private static native boolean native_pause_geofence(int geofenceId);
  }
  