diff --git a/Geofencing/app/src/main/java/com/google/android/gms/location/sample/geofencing/MainActivity.java b/Geofencing/app/src/main/java/com/google/android/gms/location/sample/geofencing/MainActivity.java
index 79ee5a02..93f8e676 100644
--- a/Geofencing/app/src/main/java/com/google/android/gms/location/sample/geofencing/MainActivity.java
+++ b/Geofencing/app/src/main/java/com/google/android/gms/location/sample/geofencing/MainActivity.java
@@ -22,18 +22,19 @@
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.Settings;
-import androidx.annotation.NonNull;
-import com.google.android.material.snackbar.Snackbar;
-import androidx.core.app.ActivityCompat;
-import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingClient;
import com.google.android.gms.location.GeofencingRequest;
@@ -41,17 +42,20 @@
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
+import com.google.android.material.snackbar.Snackbar;
import java.util.ArrayList;
import java.util.Map;
/**
- * Demonstrates how to create and remove geofences using the GeofencingApi. Uses an IntentService
- * to monitor geofence transitions and creates notifications whenever a device enters or exits
- * a geofence.
- *
- * This sample requires a device's Location settings to be turned on. It also requires
- * the ACCESS_FINE_LOCATION permission, as specified in AndroidManifest.xml.
+ * Demonstrates how to create and remove geofences using the GeofencingApi. Uses an IntentService to
+ * monitor geofence transitions and creates notifications whenever a device enters or exits a
+ * geofence.
+ *
+ *
This sample requires a device's Location settings to be turned on. It also requires the
+ * ACCESS_FINE_LOCATION permission and the ACCESS_BACKGROUND_LOCATION permission, as specified in
+ * AndroidManifest.xml.
+ *
*
*/
public class MainActivity extends AppCompatActivity implements OnCompleteListener {
@@ -60,26 +64,20 @@ public class MainActivity extends AppCompatActivity implements OnCompleteListene
private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
- /**
- * Tracks whether the user requested to add or remove geofences, or to do neither.
- */
+ /** Tracks whether the user requested to add or remove geofences, or to do neither. */
private enum PendingGeofenceTask {
- ADD, REMOVE, NONE
+ ADD,
+ REMOVE,
+ NONE
}
- /**
- * Provides access to the Geofencing API.
- */
+ /** Provides access to the Geofencing API. */
private GeofencingClient mGeofencingClient;
- /**
- * The list of geofences used in this sample.
- */
+ /** The list of geofences used in this sample. */
private ArrayList mGeofenceList;
- /**
- * Used when requesting to add or remove geofences.
- */
+ /** Used when requesting to add or remove geofences. */
private PendingIntent mGeofencePendingIntent;
// Buttons for kicking off the process of adding or removing geofences.
@@ -94,8 +92,8 @@ public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.main_activity);
// Get the UI widgets.
- mAddGeofencesButton = (Button) findViewById(R.id.add_geofences_button);
- mRemoveGeofencesButton = (Button) findViewById(R.id.remove_geofences_button);
+ mAddGeofencesButton = findViewById(R.id.add_geofences_button);
+ mRemoveGeofencesButton = findViewById(R.id.remove_geofences_button);
// Empty list for storing geofences.
mGeofenceList = new ArrayList<>();
@@ -108,7 +106,7 @@ public void onCreate(Bundle savedInstanceState) {
// Get the geofences used. Geofence data is hard coded in this sample.
populateGeofenceList();
- mGeofencingClient = LocationServices.getGeofencingClient(this);
+ mGeofencingClient = LocationServices.getGeofencingClient(this);
}
@Override
@@ -123,8 +121,8 @@ public void onStart() {
}
/**
- * Builds and returns a GeofencingRequest. Specifies the list of geofences to be monitored.
- * Also specifies how the geofence notifications are initially triggered.
+ * Builds and returns a GeofencingRequest. Specifies the list of geofences to be monitored. Also
+ * specifies how the geofence notifications are initially triggered.
*/
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
@@ -165,7 +163,8 @@ private void addGeofences() {
return;
}
- mGeofencingClient.addGeofences(getGeofencingRequest(), getGeofencePendingIntent())
+ mGeofencingClient
+ .addGeofences(getGeofencingRequest(), getGeofencePendingIntent())
.addOnCompleteListener(this);
}
@@ -197,8 +196,9 @@ private void removeGeofences() {
}
/**
- * Runs when the result of calling {@link #addGeofences()} and/or {@link #removeGeofences()}
- * is available.
+ * Runs when the result of calling {@link #addGeofences()} and/or {@link #removeGeofences()} is
+ * available.
+ *
* @param task the resulting Task, containing either a result or error.
*/
@Override
@@ -208,13 +208,13 @@ public void onComplete(@NonNull Task task) {
updateGeofencesAdded(!getGeofencesAdded());
setButtonsEnabledState();
- int messageId = getGeofencesAdded() ? R.string.geofences_added :
- R.string.geofences_removed;
+ int messageId =
+ getGeofencesAdded() ? R.string.geofences_added : R.string.geofences_removed;
Toast.makeText(this, getString(messageId), Toast.LENGTH_SHORT).show();
} else {
// Get the status code for the error and log it using a user-friendly message.
String errorMessage = GeofenceErrorMessages.getErrorString(this, task.getException());
- Log.w(TAG, errorMessage);
+ Log.w(TAG, errorMessage, task.getException());
}
}
@@ -233,8 +233,15 @@ private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling
// addGeofences() and removeGeofences().
- mGeofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- return mGeofencePendingIntent;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ return PendingIntent.getBroadcast(
+ this,
+ 0,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
+ } else {
+ return PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
}
/**
@@ -244,36 +251,39 @@ private PendingIntent getGeofencePendingIntent() {
private void populateGeofenceList() {
for (Map.Entry entry : Constants.BAY_AREA_LANDMARKS.entrySet()) {
- mGeofenceList.add(new Geofence.Builder()
- // Set the request ID of the geofence. This is a string to identify this
- // geofence.
- .setRequestId(entry.getKey())
-
- // Set the circular region of this geofence.
- .setCircularRegion(
- entry.getValue().latitude,
- entry.getValue().longitude,
- Constants.GEOFENCE_RADIUS_IN_METERS
- )
-
- // Set the expiration duration of the geofence. This geofence gets automatically
- // removed after this period of time.
- .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
-
- // Set the transition types of interest. Alerts are only generated for these
- // transition. We track entry and exit transitions in this sample.
- .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
- Geofence.GEOFENCE_TRANSITION_EXIT)
-
- // Create the geofence.
- .build());
+ mGeofenceList.add(
+ new Geofence.Builder()
+ // Set the request ID of the geofence. This is a string to identify this
+ // geofence.
+ .setRequestId(entry.getKey())
+
+ // Set the circular region of this geofence.
+ .setCircularRegion(
+ entry.getValue().latitude,
+ entry.getValue().longitude,
+ Constants.GEOFENCE_RADIUS_IN_METERS)
+
+ // Set the expiration duration of the geofence. This geofence gets
+ // automatically
+ // removed after this period of time.
+ .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
+
+ // Set the transition types of interest. Alerts are only generated for
+ // these
+ // transition. We track entry and exit transitions in this sample.
+ .setTransitionTypes(
+ Geofence.GEOFENCE_TRANSITION_ENTER
+ | Geofence.GEOFENCE_TRANSITION_EXIT)
+
+ // Create the geofence.
+ .build());
}
}
/**
- * Ensures that only one button is enabled at any time. The Add Geofences button is enabled
- * if the user hasn't yet added geofences. The Remove Geofences button is enabled if the
- * user has added geofences.
+ * Ensures that only one button is enabled at any time. The Add Geofences button is enabled if
+ * the user hasn't yet added geofences. The Remove Geofences button is enabled if the user has
+ * added geofences.
*/
private void setButtonsEnabledState() {
if (getGeofencesAdded()) {
@@ -301,24 +311,23 @@ private void showSnackbar(final String text) {
* Shows a {@link Snackbar}.
*
* @param mainTextStringId The id for the string resource for the Snackbar text.
- * @param actionStringId The text of the action item.
- * @param listener The listener associated with the Snackbar action.
+ * @param actionStringId The text of the action item.
+ * @param listener The listener associated with the Snackbar action.
*/
- private void showSnackbar(final int mainTextStringId, final int actionStringId,
- View.OnClickListener listener) {
+ private void showSnackbar(
+ final int mainTextStringId, final int actionStringId, View.OnClickListener listener) {
Snackbar.make(
- findViewById(android.R.id.content),
- getString(mainTextStringId),
- Snackbar.LENGTH_INDEFINITE)
- .setAction(getString(actionStringId), listener).show();
+ findViewById(android.R.id.content),
+ getString(mainTextStringId),
+ Snackbar.LENGTH_INDEFINITE)
+ .setAction(getString(actionStringId), listener)
+ .show();
}
- /**
- * Returns true if geofences were added, otherwise false.
- */
+ /** Returns true if geofences were added, otherwise false. */
private boolean getGeofencesAdded() {
- return PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
- Constants.GEOFENCES_ADDED_KEY, false);
+ return PreferenceManager.getDefaultSharedPreferences(this)
+ .getBoolean(Constants.GEOFENCES_ADDED_KEY, false);
}
/**
@@ -333,9 +342,7 @@ private void updateGeofencesAdded(boolean added) {
.apply();
}
- /**
- * Performs the geofencing task that was pending until location permission was granted.
- */
+ /** Performs the geofencing task that was pending until location permission was granted. */
private void performPendingGeofenceTask() {
if (mPendingGeofenceTask == PendingGeofenceTask.ADD) {
addGeofences();
@@ -344,51 +351,63 @@ private void performPendingGeofenceTask() {
}
}
- /**
- * Return the current state of the permissions needed.
- */
+ /** Return the current state of the permissions needed. */
private boolean checkPermissions() {
- int permissionState = ActivityCompat.checkSelfPermission(this,
- Manifest.permission.ACCESS_FINE_LOCATION);
+ int permissionState =
+ ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
+ if (permissionState != PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ permissionState =
+ ActivityCompat.checkSelfPermission(
+ this, Manifest.permission.ACCESS_BACKGROUND_LOCATION);
return permissionState == PackageManager.PERMISSION_GRANTED;
}
private void requestPermissions() {
boolean shouldProvideRationale =
- ActivityCompat.shouldShowRequestPermissionRationale(this,
- Manifest.permission.ACCESS_FINE_LOCATION);
+ ActivityCompat.shouldShowRequestPermissionRationale(
+ this, Manifest.permission.ACCESS_FINE_LOCATION)
+ && ActivityCompat.shouldShowRequestPermissionRationale(
+ this, Manifest.permission.ACCESS_BACKGROUND_LOCATION);
// Provide an additional rationale to the user. This would happen if the user denied the
// request previously, but didn't check the "Don't ask again" checkbox.
if (shouldProvideRationale) {
Log.i(TAG, "Displaying permission rationale to provide additional context.");
- showSnackbar(R.string.permission_rationale, android.R.string.ok,
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- // Request permission
- ActivityCompat.requestPermissions(MainActivity.this,
- new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
- REQUEST_PERMISSIONS_REQUEST_CODE);
- }
+ showSnackbar(
+ R.string.permission_rationale,
+ android.R.string.ok,
+ view -> {
+ // Request permission
+ ActivityCompat.requestPermissions(
+ MainActivity.this,
+ new String[] {
+ Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.ACCESS_BACKGROUND_LOCATION
+ },
+ REQUEST_PERMISSIONS_REQUEST_CODE);
});
} else {
Log.i(TAG, "Requesting permission");
// Request permission. It's possible this can be auto answered if device policy
// sets the permission in a given state or the user denied the permission
// previously and checked "Never ask again".
- ActivityCompat.requestPermissions(MainActivity.this,
- new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
+ ActivityCompat.requestPermissions(
+ MainActivity.this,
+ new String[] {
+ Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.ACCESS_BACKGROUND_LOCATION
+ },
REQUEST_PERMISSIONS_REQUEST_CODE);
}
}
- /**
- * Callback received when a permissions request has been completed.
- */
+ /** Callback received when a permissions request has been completed. */
@Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
- @NonNull int[] grantResults) {
+ public void onRequestPermissionsResult(
+ int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Log.i(TAG, "onRequestPermissionResult");
if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
if (grantResults.length <= 0) {
@@ -410,20 +429,17 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis
// again" prompts). Therefore, a user interface affordance is typically implemented
// when permissions are denied. Otherwise, your app could appear unresponsive to
// touches or interactions which have required permissions.
- showSnackbar(R.string.permission_denied_explanation, R.string.settings,
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- // Build intent that displays the App settings screen.
- Intent intent = new Intent();
- intent.setAction(
- Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
- Uri uri = Uri.fromParts("package",
- BuildConfig.APPLICATION_ID, null);
- intent.setData(uri);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
- }
+ showSnackbar(
+ R.string.permission_denied_explanation,
+ R.string.settings,
+ view -> {
+ // Build intent that displays the App settings screen.
+ Intent intent = new Intent();
+ intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ Uri uri = Uri.fromParts("package", BuildConfig.APPLICATION_ID, null);
+ intent.setData(uri);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
});
mPendingGeofenceTask = PendingGeofenceTask.NONE;
}
diff --git a/Geofencing/build.gradle b/Geofencing/build.gradle
index df8f9e2f..357f64ec 100644
--- a/Geofencing/build.gradle
+++ b/Geofencing/build.gradle
@@ -6,7 +6,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.5.1'
+ classpath 'com.android.tools.build:gradle:7.2.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/Geofencing/gradle.properties b/Geofencing/gradle.properties
index 5d08ba75..64c14731 100644
--- a/Geofencing/gradle.properties
+++ b/Geofencing/gradle.properties
@@ -15,4 +15,5 @@
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
\ No newline at end of file
+# org.gradle.parallel=true
+android.useAndroidX=true
\ No newline at end of file
diff --git a/Geofencing/gradle/wrapper/gradle-wrapper.properties b/Geofencing/gradle/wrapper/gradle-wrapper.properties
index 2c302a99..a98f0b14 100644
--- a/Geofencing/gradle/wrapper/gradle-wrapper.properties
+++ b/Geofencing/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip