/* * PowerSwitch by Max Rosin & Markus Ressel * Copyright (C) 2015 Markus Ressel * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.power_switch.google_play_services.geofence; import android.Manifest; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.CommonStatusCodes; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.common.api.Status; import com.google.android.gms.location.Geofence; import com.google.android.gms.location.GeofencingRequest; import com.google.android.gms.location.LocationServices; import java.util.ArrayList; import eu.power_switch.R; import eu.power_switch.gui.StatusMessageHandler; import eu.power_switch.shared.constants.GeofenceConstants; import eu.power_switch.shared.log.Log; /** * Google Geofence API Handler * Used to manage Google Location/Geofence API Geofences * <p/> * Created by Markus on 21.12.2015. */ public class GeofenceApiHandler { private Context context; private GoogleApiClient googleApiClient; public GeofenceApiHandler(Context context) { this.context = context; // Create an instance of GoogleAPIClient. googleApiClient = new GoogleApiClient.Builder(context) .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() { @Override public void onConnected(@Nullable Bundle bundle) { Log.d(GeofenceApiHandler.class, "GoogleApiClient connected"); } @Override public void onConnectionSuspended(int i) { Log.d(GeofenceApiHandler.class, "GoogleApiClient connection suspended"); } }) .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() { @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { Log.e(GeofenceApiHandler.class, "GoogleApiClient connection failed"); } }) .addApi(LocationServices.API) .build(); } /** * Creates a Geofence Object with given parameters * * @param id ID of Geofence * @param latitude Latitude of Geofence location * @param longitude Longitude of Geofence location * @param radius Radius in meter of geofence, for best results with WiFi networks this value should be >= 100 * @param expirationDuration ??? * @return Geofence */ public static Geofence createGeofence(String id, double latitude, double longitude, int radius, long expirationDuration) { Geofence geofence = new Geofence.Builder() // Set the request ID of the geofence. This is a string to identify this // geofence. .setRequestId(id) // Set the circular region of this geofence. .setCircularRegion( latitude, longitude, radius ) // Set the expiration duration of the geofence. This geofence gets automatically // removed after this period of time. .setExpirationDuration(expirationDuration) // Delay to wait before DWELL transition happens .setLoiteringDelay(GeofenceConstants.DEFAULT_LOITERING_DELAY) // 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 | Geofence.GEOFENCE_TRANSITION_DWELL) .build(); return geofence; } private static GeofencingRequest getGeofencingRequest(Geofence geofence) { GeofencingRequest.Builder builder = new GeofencingRequest.Builder(); builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER); builder.addGeofence(geofence); return builder.build(); } public void blockingConnect() { googleApiClient.blockingConnect(); } /** * Add Geofence to GeofenceAPI * * @param geofence Geofence */ public void addGeofence(eu.power_switch.google_play_services.geofence.Geofence geofence) { addGeofence(getGeofencingRequest( createGeofence( String.valueOf(geofence.getId()), geofence.getCenterLocation().latitude, geofence.getCenterLocation().longitude, (int) geofence.getRadius(), -1)), getGeofencePendingIntent()); } private void addGeofence(GeofencingRequest geofencingRequest, PendingIntent geofencePendingIntent) { if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager .PERMISSION_GRANTED) { return; } LocationServices.GeofencingApi.addGeofences( googleApiClient, geofencingRequest, geofencePendingIntent ).setResultCallback(new ResultCallback<Status>() { @Override public void onResult(@NonNull Status status) { switch (status.getStatusCode()) { case CommonStatusCodes.SUCCESS: StatusMessageHandler.showInfoMessage(context, R.string.geofence_enabled, Snackbar.LENGTH_SHORT); } Log.d(GeofenceApiHandler.class, status.toString()); } }); } /** * Remove Geofence from GeofenceAPI * * @param geofenceId ID of Geofence */ public void removeGeofence(long geofenceId) { removeGeofence(googleApiClient, String.valueOf(geofenceId)); } private void removeGeofence(GoogleApiClient googleApiClient, final String geofenceId) { ArrayList<String> geofenceIds = new ArrayList<>(); geofenceIds.add(geofenceId); LocationServices.GeofencingApi.removeGeofences( googleApiClient, geofenceIds ).setResultCallback(new ResultCallback<Status>() { @Override public void onResult(@NonNull Status status) { switch (status.getStatusCode()) { case CommonStatusCodes.SUCCESS: StatusMessageHandler.showInfoMessage(context, R.string.geofence_disabled, Snackbar.LENGTH_SHORT); } Log.d(GeofenceApiHandler.class, status.toString()); } }); // Result processed in onResult(). } /** * Remove all Geofences from Google Location Api */ public void removeAllGeofences() { LocationServices.GeofencingApi.removeGeofences( googleApiClient, // This is the same pending intent that was used in addGeofence(). getGeofencePendingIntent() ).setResultCallback(new ResultCallback<Status>() { @Override public void onResult(@NonNull Status status) { switch (status.getStatusCode()) { case CommonStatusCodes.SUCCESS: StatusMessageHandler.showInfoMessage(context, R.string.geofences_disabled, Snackbar .LENGTH_LONG); } Log.d(GeofenceApiHandler.class, status.toString()); } }); // Result processed in onResult(). } private PendingIntent getGeofencePendingIntent() { Intent intent = new Intent(context, GeofenceIntentService.class); // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when // calling addGeofence() and removeAllGeofences(). return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } /** * Connect (async) GoogleApiClient */ public void onStart() { googleApiClient.connect(); } /** * Disconnect (async) GoogleApiClient */ public void onStop() { googleApiClient.disconnect(); } }