Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

In the AndroidManifest file, you must declare ACCESS_FINE_LOCATION and ACCESS_BACKGROUND_LOCATION

Code Block
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

If your app targets Android 10 (API level 29) or higher  ACCESS_BACKGROUND_LOCATION is mandatory. 

Ask for runtime permission when the user interacts with a feature in your application which demands location access. 

Code Block
private boolean isGeoPermissionGranted() {
        if (Build.VERSION.SDK_INT >= 29) {
            return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                    && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED ;
        }
        else {
            return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
        }
    }
 
 private void askForGeoPermission() {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION,},
                    MY_PERMISSIONS_ACCESS_FINE_LOCATION);
    }
 
 private void askForGeoPermissionWithBackgroundLocation() {
        boolean permissionAccessFineLocationApproved =
                ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                        == PackageManager.PERMISSION_GRANTED;
 
        if (permissionAccessFineLocationApproved) {
            boolean backgroundLocationPermissionApproved =
                    ContextCompat.checkSelfPermission(this,
                            Manifest.permission.ACCESS_BACKGROUND_LOCATION)
                            == PackageManager.PERMISSION_GRANTED;
 
            if (backgroundLocationPermissionApproved) {
 
            } else {
                ActivityCompat.requestPermissions(this, new String[] {
                                Manifest.permission.ACCESS_BACKGROUND_LOCATION},
                        MY_PERMISSIONS_ACCESS_FINE_AND_BACKGROUND_LOCATION);
            }
        } else {
            ActivityCompat.requestPermissions(this, new String[] {
                            Manifest.permission.ACCESS_FINE_LOCATION,
                            Manifest.permission.ACCESS_BACKGROUND_LOCATION
                    },
                    MY_PERMISSIONS_ACCESS_FINE_AND_BACKGROUND_LOCATION);
        }
    }
 
 
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (MY_PERMISSIONS_ACCESS_FINE_LOCATION == requestCode) {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Appoxee.instance().startGeoFencing();
                Log.w("MainActivity", "startGeoFencing()");
            }
            else {
                Log.w("MainActivity", "Geo permission not granted");
            }
        }
}


To start geofence call (deprecated, without receiving Geofence status or errors)

Code Block
@Deprecated("Use method bellow for better error and status handling of geofence starting.")
Appoxee.instance().startGeoFencing();

To start geofence call (with receiving geofence status or errors)

Code Block
// Define callback for getting result when calling start geofence
private final ResultCallback<String> geofenceCallback = new ResultCallback<>() {
    @Override
    public void onResult(@Nullable String result) {
        devLogger.d(result);
        if (result != null) {
            switch (result) {
                // handle different cases of a result status
            }
        }
    }
};

// Start Geofence
Appoxee.instance().startGeoFencing(geofenceCallback);

List of all possible statuses when starting Geofence:

Code Block
    String GEOFENCE_SDK_NOT_READY = "GEOFENCE_SDK_NOT_READY";
    String GEOFENCE_LOCATION_PERMISSIONS_NOT_GRANTED = "GEOFENCE_LOCATION_PERMISSIONS_NOT_GRANTED";
    String GEOFENCE_LOCATION_NOT_ACCURATE = "GEOFENCE_LOCATION_NOT_ACCURATE";
    String GEOFENCE_LOCATION_NOT_AVAILABLE = "GEOFENCE_LOCATION_NOT_AVAILABLE";
    String GEOFENCE_NO_INTERNET_CONNECTION = "GEOFENCE_NO_INTERNET_CONNECTION";
    String GEOFENCE_FAILED_GETTING_REGIONS = "GEOFENCE_FAILED_GETTING_REGIONS";
    String GEOFENCE_STARTED_OK = "GEOFENCE_STARTED_OK";
    String GEOFENCE_STOPPED_OK="GEOFENCE_STOPPED_OK";
    String GEOFENCE_GENERAL_ERROR = "GEOFENCE_GENERAL_ERROR";
    String GEOFENCE_TOO_MANY_GEOFENCE_CALLS = "GEOFENCE_TOO_MANY_GEOFENCE_CALLS";
    String GEOFENCE_TOO_MANY_GEOFENCES = "GEOFENCE_TOO_MANY_GEOFENCES";
    String GEOFENCE_TOO_MANY_PENDING_INTENTS="GEOFENCE_TOO_MANY_PENDING_INTENTS";
    String GEOFENCE_ERROR_STOPPING = "GEOFENCE_ERROR_STOPPING";

In the example below, you can see  how to ask for permission and start geofencing:

Code Block
private void startGeo() {
      if (isGeoPermissionGranted()) {
          Appoxee.instance().startGeoFencing(geofenceCallback);
      } else {
          if (Build.VERSION.SDK_INT >= 29) {
              askForGeoPermissionWithBackgroundLocation();
          } else {
              askForGeoPermission();
          }
      }
  }

To stop geofence call (deprecated, without receiving Geofence status or errors)

Code Block
Appoxee.instance().stopGeoFencing();

To stop geofence call (with receiving Geofence status or errors)

Code Block
Appoxee.instance().stopGeoFencing(geofenceCallback);

Best practices to improve geofencing:

  1. enable Wi-Fi or Wi-Fi scanning 

  2. enable Bluetooth or Bluetooth scanning

  3. enable Mobile data 

  4. disable Airplane Mode (the phone must NOT be in Airplane Mode)

  5. avoid using Power Saving Mode

  6. enable Mobile data

Use code below to enable Wi-Fi scanning from code 

Code Block
startActivity(new Intent(WifiManager.ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE));

Or you can use code below to redirect the user to Location Service in Settings: 

Code Block
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));

On this page user should enable:

  1. Wi-FI scanning,

  2. Bluetooth scanning,

  3. Emergency Location Service and

  4. Google Location Accuracy 

...


In the screenshots above you can see which options should be enabled when the user is redirected to Location Service in Settings. 

...

To change location settings: 

  1. Open your device's Settings app.

  2. Tap Security & Location →  Location.

    • If you have a work profile, tap Advanced.

Then, choose the option:

  • Turn Location on or off: Tap Location.

  • Scan for nearby networks: Tap Advanced →  Scanning. Turn Wi-Fi scanning and Bluetooth scanning on.

  • Turn emergency location service on or off:  Tap Advanced → Google Emergency Location Service. Turn Emergency Location Service on. 

...

You can choose your location mode based on accuracy, speed, and battery use.

  1. Open your phone's Settings app.

  2. Tap Security & Location → Location. If you don't see "Security & Location," tap Location.

  3. Tap Mode. Then pick:

  • High accuracy: Use GPS, Wi-Fi, mobile networks, and sensors to get the most accurate location. Use Google Location Services to help estimate your phone's location faster and more accurately.

  • Battery saving: Use sources that use less battery, like Wi-Fi and mobile networks. Use Google Location Services to help estimate your phone's location faster and more accurately.

  • Device only: Use the only GPS. Don’t use Google Location Services to provide location information. This can estimate your phone's location more slowly and use more battery.

...