Skip to content

Instantly share code, notes, and snippets.

@libindev
Created July 3, 2020 05:10
Show Gist options
  • Save libindev/66a0f7dd967497f7a038ce27981abc96 to your computer and use it in GitHub Desktop.
Save libindev/66a0f7dd967497f7a038ce27981abc96 to your computer and use it in GitHub Desktop.
geofencing
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
import com.google.android.gms.awareness.fence.FenceState;
public class GeofenceBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "GeofenceBroadcastReceiv";
private String ENTER = "com.example.geofencing"+"20";
private String EXIT = "com.example.geofencing"+"10";
private String ENTEROREXIT = "com.example.geofencing"+"30";
private String IN = "com.example.geofencing"+"40";
@Override
public void onReceive(Context context, Intent intent) {
FenceState fenceState = FenceState.extract(intent);
String key = fenceState.getFenceKey();
if (key.equals(ENTER)) {
fenceState.getCurrentState();
} else if (key.equals(EXIT)) {
fenceState.getCurrentState();
} else if (key.equals(ENTEROREXIT)) {
fenceState.getCurrentState();
} else if (key.equals(IN)){
fenceState.getCurrentState();
}else {
fenceState.getCurrentState();
}
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
// Toast.makeText(con text, "Geofence triggered...", Toast.LENGTH_SHORT).show();
// NotificationHelper notificationHelper = new NotificationHelper(context);
/* GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
Log.d(TAG, "onReceive: Error receiving geofence event...");
return;
}
List<Geofence> geofenceList = geofencingEvent.getTriggeringGeofences();
for (Geofence geofence: geofenceList) {
Log.d(TAG, "onReceive: " + geofence.getRequestId());
}
// Location location = geofencingEvent.getTriggeringLocation();
int transitionType = geofencingEvent.getGeofenceTransition();
switch (transitionType) {
case Geofence.GEOFENCE_TRANSITION_ENTER:
Toast.makeText(context, "GEOFENCE_TRANSITION_ENTER", Toast.LENGTH_SHORT).show();
notificationHelper.sendHighPriorityNotification("GEOFENCE_TRANSITION_ENTER", "", MapsActivity.class);
break;
case Geofence.GEOFENCE_TRANSITION_DWELL:
Toast.makeText(context, "GEOFENCE_TRANSITION_DWELL", Toast.LENGTH_SHORT).show();
notificationHelper.sendHighPriorityNotification("GEOFENCE_TRANSITION_DWELL", "", MapsActivity.class);
break;
case Geofence.GEOFENCE_TRANSITION_EXIT:
Toast.makeText(context, "GEOFENCE_TRANSITION_EXIT", Toast.LENGTH_SHORT).show();
notificationHelper.sendHighPriorityNotification("GEOFENCE_TRANSITION_EXIT", "", MapsActivity.class);
break;
}*/
}
}
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.util.Log;
import androidx.annotation.NonNull;
import com.google.android.gms.awareness.Awareness;
import com.google.android.gms.awareness.fence.AwarenessFence;
import com.google.android.gms.awareness.fence.DetectedActivityFence;
import com.google.android.gms.awareness.fence.FenceUpdateRequest;
import com.google.android.gms.awareness.fence.HeadphoneFence;
import com.google.android.gms.awareness.fence.LocationFence;
import com.google.android.gms.awareness.fence.TimeFence;
import com.google.android.gms.awareness.state.HeadphoneState;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofenceStatusCodes;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
public class GeofenceHelper extends ContextWrapper {
private static final String TAG = "GeofenceHelper";
PendingIntent pendingIntent;
private String ENTER = "com.example.geofencing"+"20";
private String EXIT = "com.example.geofencing"+"10";
private String ENTEROREXIT = "com.example.geofencing"+"30";
private String IN = "com.example.geofencing"+"40";
public GeofenceHelper(Context base) {
super(base);
}
public GeofencingRequest getGeofencingRequest(Geofence geofence) {
return new GeofencingRequest.Builder()
.addGeofence(geofence)
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.build();
}
@SuppressLint("MissingPermission")
public void getGeofence(LatLng latLng, double radius) {
/*new Geofence.Builder()
.setCircularRegion(latLng.latitude, latLng.longitude, radius)
.setRequestId(ID)
.setTransitionTypes(transitionTypes)
.setLoiteringDelay(5000)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build();?/*/
// AwarenessFence walkingFence = DetectedActivityFence.during(DetectedActivityFence.STILL);
// AwarenessFence headphoneFence = HeadphoneFence.during(HeadphoneState.PLUGGED_IN);
AwarenessFence locationFenceEnter = LocationFence.entering(latLng.latitude,latLng.longitude,radius);
AwarenessFence locationFenceExit = LocationFence.exiting(latLng.latitude,latLng.longitude,radius);
AwarenessFence in = LocationFence.in(latLng.latitude,latLng.longitude,radius,3*60);
AwarenessFence or = AwarenessFence.and(locationFenceEnter, locationFenceExit);
// Create a combination fence to AND primitive fences.
// return LocationFence.entering(latLng.latitude,latLng.longitude,radius);
/* geofencingClient.addGeofences(geofencingRequest, pendingIntent)
.addOnSuccessListener( new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "onSuccess: Geofence Added...");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
String errorMessage = geofenceHelper.getErrorString(e);
Log.d(TAG, "onFailure: " + errorMessage);
}
});*/
// AwarenessFence geofence = geofenceHelper.getGeofence(GEOFENCE_ID, latLng, radius, Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_DWELL | Geofence.GEOFENCE_TRANSITION_EXIT);
// GeofencingRequest geofencingRequest = geofenceHelper.getGeofencingRequest(geofence);
// PendingIntent pendingIntent = geofenceHelper.getPendingIntent();
Awareness.getFenceClient(this).updateFences(new FenceUpdateRequest.Builder()
// .addFence(ENTER,in, getPendingIntent())
//.addFence(EXIT,locationFenceExit, getPendingIntent())
.addFence(IN,in,getPendingIntent())
.build())
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.i(TAG, "Fence was successfully registered.");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.e(TAG, "Fence could not be registered: " + e);
}
});
}
public PendingIntent getPendingIntent() {
if (pendingIntent != null) {
return pendingIntent;
}
Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 2607, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
public String getErrorString(Exception e) {
if (e instanceof ApiException) {
ApiException apiException = (ApiException) e;
switch (apiException.getStatusCode()) {
case GeofenceStatusCodes
.GEOFENCE_NOT_AVAILABLE:
return "GEOFENCE_NOT_AVAILABLE";
case GeofenceStatusCodes
.GEOFENCE_TOO_MANY_GEOFENCES:
return "GEOFENCE_TOO_MANY_GEOFENCES";
case GeofenceStatusCodes
.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return "GEOFENCE_TOO_MANY_PENDING_INTENTS";
}
}
return e.getLocalizedMessage();
}
}
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ScrollView;
import androidx.fragment.app.Fragment;
/**
* Simple fragment which contains a LogView and uses is to output log data it receives to the screen.
*/
public class LogFragment extends Fragment {
private LogView mLogView;
private ScrollView mScrollView;
public LogFragment() {}
public View inflateViews() {
mScrollView = new ScrollView(getActivity());
ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
mScrollView.setLayoutParams(scrollParams);
mLogView = new LogView(getActivity());
ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
mLogView.setLayoutParams(logParams);
mLogView.setClickable(true);
mLogView.setFocusable(true);
mLogView.setTypeface(Typeface.MONOSPACE);
// Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
int paddingDips = 16;
double scale = getResources().getDisplayMetrics().density;
int paddingPixels = (int) ((paddingDips * (scale)) + .5);
mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
mLogView.setCompoundDrawablePadding(paddingPixels);
mLogView.setGravity(Gravity.BOTTOM);
mLogView.setTextAppearance(getActivity(),
android.R.style.TextAppearance_DeviceDefault_Medium);
mScrollView.addView(mLogView);
return mScrollView;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View result = inflateViews();
mLogView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
});
return result;
}
public LogView getLogView() {
return mLogView;
}
}
import android.app.Activity;
import android.content.Context;
import android.util.*;
import android.widget.TextView;
/** Simple TextView which is used to output log data.
*/
public class LogView extends TextView {
public LogView(Context context) {
super(context);
}
public LogView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LogView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Formats the log data and prints it out to the LogView.
* @param msg The actual message to be logged. The actual message to be logged.
*/
public void println(final String msg) {
// In case this was originally called from an AsyncTask or some other off-UI thread,
// make sure the update occurs within the UI thread.
((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
@Override
public void run() {
// Display the text we just generated within the LogView.
appendToLog(msg);
}
})));
}
/** Outputs the string as a new line of log data in the LogView. */
public void appendToLog(String s) {
append("\n" + s);
}
}
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.awareness.Awareness;
import com.google.android.gms.awareness.fence.AwarenessFence;
import com.google.android.gms.awareness.fence.FenceUpdateRequest;
import com.google.android.gms.awareness.snapshot.DetectedActivityResponse;
import com.google.android.gms.location.ActivityRecognitionResult;
import com.google.android.gms.location.DetectedActivity;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingClient;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleMap.OnMapLongClickListener {
private static final String TAG = "MapsActivity";
private GoogleMap mMap;
private GeofencingClient geofencingClient;
private GeofenceHelper geofenceHelper;
private float GEOFENCE_RADIUS = 200;
private String GEOFENCE_ID = "com.example.geofencing"+"20";
private int FINE_LOCATION_ACCESS_REQUEST_CODE = 10001;
private int BACKGROUND_LOCATION_ACCESS_REQUEST_CODE = 10002;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
// geofencingClient = LocationServices.getGeofencingClient(this);
geofenceHelper = new GeofenceHelper(this);
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Add a marker in Sydney and move the camera
LatLng eiffel = new LatLng(48.8589, 2.29365);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(eiffel, 16));
enableUserLocation();
mMap.setOnMapLongClickListener(this);
}
private void enableUserLocation() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
mMap.setMyLocationEnabled(true);
} else {
//Ask for permission
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
//We need to show user a dialog for displaying why the permission is needed and then ask for the permission...
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, FINE_LOCATION_ACCESS_REQUEST_CODE);
} else {
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, FINE_LOCATION_ACCESS_REQUEST_CODE);
}
}
}
@SuppressLint("MissingPermission")
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == FINE_LOCATION_ACCESS_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//We have the permission
mMap.setMyLocationEnabled(true);
} else {
//We do not have the permission..
}
}
if (requestCode == BACKGROUND_LOCATION_ACCESS_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//We have the permission
Toast.makeText(this, "You can add geofences...", Toast.LENGTH_SHORT).show();
} else {
//We do not have the permission..
Toast.makeText(this, "Background location access is neccessary for geofences to trigger...", Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void onMapLongClick(LatLng latLng) {
if (Build.VERSION.SDK_INT >= 29) {
//We need background permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
handleMapLongClick(latLng);
} else {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {
//We show a dialog and ask for permission
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_ACCESS_REQUEST_CODE);
} else {
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_ACCESS_REQUEST_CODE);
}
}
} else {
handleMapLongClick(latLng);
}
}
private void handleMapLongClick(LatLng latLng) {
mMap.clear();
addMarker(latLng);
addCircle(latLng, GEOFENCE_RADIUS);
addGeofence(latLng, GEOFENCE_RADIUS);
}
@SuppressLint("MissingPermission")
private void addGeofence(LatLng latLng, double radius) {
geofenceHelper. getGeofence(latLng,radius);
}
private void addMarker(LatLng latLng) {
MarkerOptions markerOptions = new MarkerOptions().position(latLng);
mMap.addMarker(markerOptions);
}
private void addCircle(LatLng latLng, float radius) {
CircleOptions circleOptions = new CircleOptions();
circleOptions.center(latLng);
circleOptions.radius(radius);
circleOptions.strokeColor(Color.argb(255, 255, 0,0));
circleOptions.fillColor(Color.argb(64, 255, 0,0));
circleOptions.strokeWidth(4);
mMap.addCircle(circleOptions);
}
}
package com.example.geofencing;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import java.util.Random;
public class NotificationHelper extends ContextWrapper {
private static final String TAG = "NotificationHelper";
public NotificationHelper(Context base) {
super(base);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createChannels();
}
}
private String CHANNEL_NAME = "High priority channel";
private String CHANNEL_ID = "com.example.notifications" + CHANNEL_NAME;
@RequiresApi(api = Build.VERSION_CODES.O)
private void createChannels() {
NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
notificationChannel.enableLights(true);
notificationChannel.enableVibration(true);
notificationChannel.setDescription("this is the description of the channel.");
notificationChannel.setLightColor(Color.RED);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.createNotificationChannel(notificationChannel);
}
public void sendHighPriorityNotification(String title, String body, Class activityName) {
Intent intent = new Intent(this, activityName);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 267, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
// .setContentTitle(title)
// .setContentText(body)
.setSmallIcon(R.drawable.ic_launcher_background)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setStyle(new NotificationCompat.BigTextStyle().setSummaryText("summary").setBigContentTitle(title).bigText(body))
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build();
NotificationManagerCompat.from(this).notify(new Random().nextInt(), notification);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment