I have read various tutorials, forums and the official Google documentation and still cannot understand why my code does not work as expected. There are the relevant parts:
Activity
public class MainMap extends FragmentActivity implements OnMarkerClickListener, OnMapReadyCallback,
ConnectionCallbacks, OnConnectionFailedListener, LocationListener, ActivityCompat.OnRequestPermissionsResultCallback, ResultCallback<Status> {
private static final int REQUEST_ACCESS_FINE_LOCATION = 0;
protected GoogleApiClient mGoogleApiClient;
protected Location mCurrentLocation;
protected LocationRequest mLocationRequest;
private GoogleMap m_map;
private SupportMapFragment m_map_fragment;
protected ArrayList<Geofence> mGeofenceList;
private PendingIntent mGeofencePendingIntent;
private boolean m_geofences_added;
private SharedPreferences m_preferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_map);
m_preferences = this.getSharedPreferences("com.example",Context.MODE_PRIVATE);
// map fragment
m_map_fragment= (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
m_map_fragment.getMapAsync(this);
}
#Override
protected void onStart() {
super.onStart();
// location and geofences
add_location_and_geofences();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
// remove geofences
LocationServices.GeofencingApi.removeGeofences(mGoogleApiClient, getGeofencePendingIntent());
super.onStop();
mGoogleApiClient.disconnect();
}
#Override
public void onConnected(Bundle connectionHint) {
// permissions
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
request_fine_location_permission();
}
// location
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
// geofencing
try {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this);
} catch (SecurityException securityException) {
Log.e(TAG, "Invalid location permission. " +
"You need to use ACCESS_FINE_LOCATION with geofences", securityException);
}
}
public void onResult(Status status) {
if (status.isSuccess()) {
} else {
String errorMessage = GeofenceErrorMessages.getErrorString(this,
status.getStatusCode());
Log.e(TAG, errorMessage);
}
}
private void add_location_and_geofences() {
for (int i =0; i < 3; i++) {
mGeofencePendingIntent = null;
mGeofenceList = new ArrayList<>();
mGeofenceList.add(new Geofence.Builder()
.setRequestId(Integer.toString(i)) // request id is the index so that I can later retrieve it
.setCircularRegion( /* I set coordinates here and a radius of 10meters*/)
.setExpirationDuration(NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_DWELL)
.setLoiteringDelay(4000)
.build());
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(500);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
}
private PendingIntent getGeofencePendingIntent() {
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_DWELL);
builder.addGeofences(mGeofenceList);
return builder.build();
}
}
my Service:
public class GeofenceTransitionsIntentService extends IntentService {
private Intent m_intent;
#Override
public void onCreate() {
super.onCreate();
m_intent = new Intent(this, Guide.class);
}
#Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
String errorMessage = GeofenceErrorMessages.getErrorString(this,
geofencingEvent.getErrorCode());
Log.e(TAG, errorMessage);
} else {
if (debug_mode) {
Log.i(TAG, "something has been received");
}
int geofenceTransition = geofencingEvent.getGeofenceTransition();
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_DWELL) {
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
for (Geofence geofence : triggeringGeofences) {
Log.i(TAG, "INSIDE GEOFENCE");
}
} else {
Log.e(TAG, getString(R.string.geofence_transition_invalid_type, geofenceTransition));
}
}
}
}
and my manifest
<service android:name="com.example.GeofenceTransitionsIntentService" />
With this code geofencing silently fails - my service is never triggered, both using wifi indoors and using 3G/4G networks outdoors.
Are you looking only for dwell events, or enter and exit events? If the latter, set your initial trigger to INITIAL_TRIGGER_ENTER, and the transition types to GEOFENCE_TRANSITION_ENTER| GEOFENCE_TRANSITION_EXIT.
If you are looking for dwell events, you need to stay within the geofence for about 5 minutes to get the initial trigger. When you leave, you won't get any event about it, but once you re-enter it, you'll need to stay within your geofence again for another 5 minutes to get your event.
Related
I'm trying to create geofences without google maps (just service that triggers PendingIntent when user is in geofence area). The problem is that I'm not able to get response when user enters geofence location. Here is my code from service class:
public class GeofenceBackgroundService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener,
ResultCallback<Status> {
private GoogleApiClient googleApiClient;
private GeofencingClient mGeofencingClient;
private LocationRequest locationRequest;
private PendingIntent geoFencePendingIntent;
private final int GEOFENCE_REQ_CODE = 0;
private static final String GEOFENCE_REQ_ID = "My Geofence";
private static final float GEOFENCE_RADIUS = 500.0f;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
/*mGeofencingClient = LocationServices.getGeofencingClient(this);*/
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
googleApiClient.connect();
locationRequest = LocationRequest.create()
.setInterval(10000)
.setFastestInterval(5000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
return START_STICKY;
}
#Override
public void onConnected(Bundle dataBundle) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
Geofence geofence = createGeofence();
GeofencingRequest geofenceRequest = createGeofenceRequest(geofence);
addGeofence(geofenceRequest);
}
#Override
public void onConnectionSuspended(int i) {
googleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
#Override
public void onLocationChanged(Location location) {
if (location != null) {
Log.e("TAG", "Location changed " + location.getLatitude() +" " + location.getLongitude());
}
}
private Geofence createGeofence() {
return new Geofence.Builder()
.setRequestId(GEOFENCE_REQ_ID)
.setCircularRegion(35.3140045, 103.4839695, GEOFENCE_RADIUS)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setNotificationResponsiveness(1000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
.build();
}
private GeofencingRequest createGeofenceRequest(Geofence geofence) {
return new GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.addGeofence(geofence)
.build();
}
private PendingIntent createGeofencePendingIntent() {
if (geoFencePendingIntent != null)
return geoFencePendingIntent;
/*Intent intent = new Intent("com.receive.ACTION_RECEIVE_GEOFENCE");
PendingIntent geoFencePendingIntent = PendingIntent.getBroadcast( getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return geoFencePendingIntent;*/
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
return PendingIntent.getService(this, GEOFENCE_REQ_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private void addGeofence(GeofencingRequest request) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.GeofencingApi.addGeofences(googleApiClient, request, createGeofencePendingIntent()).setResultCallback(this);
}
#Override
public void onResult(#NonNull Status status) {
if ( status.isSuccess() ) {
} else {
}
}
#Override
public void onDestroy() {
super.onDestroy();
googleApiClient.disconnect();
}}
Also I tried to use both IntentService and Broadcast receiver and declared them properly in android manifest file
I am really stuck at this point.Geofence really works fine when app is in forground that is notification comes properly. but when app goes is in background notification not comes.
I want like this when app is in background my geofence never expired and and get notified if user is outside the fence.
Also attached the code below:-
public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener,
ResultCallback<Status> {
protected static final int REQUEST_CHECK_SETTINGS = 0x1;
GoogleApiClient googleApiClient;
private MapFragment mapFragment;
private static final String TAG = MainActivity.class.getSimpleName();
private GoogleMap map;
private Location lastLocation;
private static final String NOTIFICATION_MSG = "NOTIFICATION MSG";
SharedPreferences pref;
SharedPreferences.Editor editor;
public static Intent makeNotificationIntent(Context context, String msg) {
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra(NOTIFICATION_MSG, msg);
return intent;
}
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_geofence);
pref = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
editor = pref.edit();
initGMaps();
createGoogleApi();
}
private void initGMaps() {
//mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
//mapFragment.getMapAsync(this);
}
private void createGoogleApi() {
Log.d(TAG, "createGoogleApi()");
if (googleApiClient == null) {
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
#Override
protected void onStart() {
super.onStart();
googleApiClient.connect();
settingsrequest();
}
public void settingsrequest() {
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(30 * 1000);
locationRequest.setFastestInterval(5 * 1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
builder.setAlwaysShow(true); //this is the key ingredient
PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
final LocationSettingsStates state = result.getLocationSettingsStates();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
// All location settings are satisfied. The client can initialize location
// requests here.
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied. But could be fixed by showing the user
// a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are not satisfied. However, we have no way to fix the
// settings so we won't show the dialog.
break;
}
}
});
}
#Override
protected void onStop() {
super.onStop();
// Disconnect GoogleApiClient when stopping Activity
googleApiClient.disconnect();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
// Check for the integer request code originally supplied to startResolutionForResult().
case REQUEST_CHECK_SETTINGS:
switch (resultCode) {
case Activity.RESULT_OK:
startLocationUpdates();
break;
case Activity.RESULT_CANCELED:
settingsrequest();//keep asking if imp or do whatever
break;
}
break;
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
// googleApiClient.disconnect();
Log.i(TAG, "onConnected()");
getLastKnownLocation();
//recoverGeofenceMarker();
startGeofence();
}
private final int REQ_PERMISSION = 999;
// Check for permission to access Location
private boolean checkPermission() {
Log.d(TAG, "checkPermission()");
// Ask for permission if it wasn't granted yet
return (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED);
}
// Asks for permission
private void askPermission() {
Log.d(TAG, "askPermission()");
ActivityCompat.requestPermissions(
this,
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
REQ_PERMISSION
);
}
private void getLastKnownLocation() {
Log.d(TAG, "getLastKnownLocation()");
if (checkPermission()) {
lastLocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
if (lastLocation != null) {
Log.i(TAG, "LasKnown location. " +
"Long: " + lastLocation.getLongitude() +
" | Lat: " + lastLocation.getLatitude());
writeLastLocation();
startLocationUpdates();
} else {
Log.w(TAG, "No location retrieved yet");
startLocationUpdates();
}
} else askPermission();
}
private void writeActualLocation(Location location) {
//textLat.setText("Lat: " + location.getLatitude());
//textLong.setText("Long: " + location.getLongitude());
markerLocation(new LatLng(location.getLatitude(), location.getLongitude()));
}
private void writeLastLocation() {
writeActualLocation(lastLocation);
}
private Marker locationMarker;
private void markerLocation(LatLng latLng) {
Log.i(TAG, "markerLocation(" + latLng + ")");
String title = latLng.latitude + ", " + latLng.longitude;
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.title(title);
if (map != null) {
if (locationMarker != null)
locationMarker.remove();
locationMarker = map.addMarker(markerOptions);
float zoom = 14f;
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, zoom);
map.animateCamera(cameraUpdate);
}
}
// Start Geofence creation process
private void startGeofence() {
Log.i(TAG, "startGeofence()");
Geofence geofence = createGeofence();
GeofencingRequest geofenceRequest = createGeofenceRequest(geofence);
addGeofence(geofenceRequest);
}
private static final long GEO_DURATION = 60 * 60 * 1000;
private static final String GEOFENCE_REQ_ID = "My Geofence";
private static final float GEOFENCE_RADIUS = 500.0f; // in meters
// Create a Geofence
private Geofence createGeofence() {
Log.d(TAG, "createGeofence");
//Intent i = getIntent();
//double la = i.getDoubleExtra("latitude", 0);
//double lo = i.getDoubleExtra("longitude", 0);
return new Geofence.Builder()
.setRequestId(GEOFENCE_REQ_ID)
.setCircularRegion(18.457532, 73.867746, GEOFENCE_RADIUS)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_EXIT)
.build();
}
// Create a Geofence Request
private GeofencingRequest createGeofenceRequest(Geofence geofence) {
Log.d(TAG, "createGeofenceRequest");
return new GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_EXIT)
.addGeofence(geofence)
.build();
}
private PendingIntent geoFencePendingIntent;
private static final int GEOFENCE_REQ_CODE = 0;
private PendingIntent createGeofencePendingIntent() {
Log.d(TAG, "createGeofencePendingIntent");
if (geoFencePendingIntent != null)
return geoFencePendingIntent;
Intent intent = new Intent("com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE");
return PendingIntent.getBroadcast(
this, GEOFENCE_REQ_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
// Add the created GeofenceRequest to the device's monitoring list
private void addGeofence(GeofencingRequest request) {
Log.d(TAG, "addGeofence");
if (checkPermission())
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
request,
createGeofencePendingIntent()
).setResultCallback(this);
}
#Override
public void onConnectionSuspended(int i) {
Log.w(TAG, "onConnectionSuspended()");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.w(TAG, "onConnectionFailed()");
}
private LocationRequest locationRequest;
// Defined in mili seconds.
// This number in extremely low, and should be used only for debug
private final int UPDATE_INTERVAL = 1000;
private final int FASTEST_INTERVAL = 900;
// Start location Updates
private void startLocationUpdates() {
Log.i(TAG, "startLocationUpdates()");
locationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
if (checkPermission())
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged [" + location + "]");
lastLocation = location;
writeActualLocation(location);
}
#Override
public void onResult(#NonNull Status status) {
Log.i(TAG, "onResult: " + status);
if (status.isSuccess()) {
// saveGeofence();
//drawGeofence();
} else {
// inform about fail
}
}
}
also attached Reciever code:-
public class GeofenceReciever extends BroadcastReceiver {
private static final String TAG = "BootReceiver";
Context contextBootReceiver;
Intent intent;
public static final int GEOFENCE_NOTIFICATION_ID = 0;
SharedPreferences pref;
SharedPreferences.Editor editor;
#Override
public void onReceive(Context context, Intent intent) {
this.contextBootReceiver = context;
this.intent = intent;
pref = PreferenceManager.getDefaultSharedPreferences(context);
editor = pref.edit();
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
// Handling errors
if (geofencingEvent.hasError()) {
String errorMsg = getErrorString(geofencingEvent.getErrorCode());
Log.e(TAG, errorMsg);
return;
}
int geoFenceTransition = geofencingEvent.getGeofenceTransition();
// Check if the transition type is of interest
if (geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
// Get the geofence that were triggered
Log.d("Trnsition", "Exited");
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
String geofenceTransitionDetails = getGeofenceTrasitionDetails(geoFenceTransition, triggeringGeofences);
// Send notification details as a String
//if (feedback.equalsIgnoreCase("F;1;")) {
// String temp = feedback;
sendNotification(geofenceTransitionDetails);
}
}
private String getGeofenceTrasitionDetails(int geoFenceTransition, List<Geofence> triggeringGeofences) {
// get the ID of each geofence triggered
ArrayList<String> triggeringGeofencesList = new ArrayList<>();
for (Geofence geofence : triggeringGeofences) {
triggeringGeofencesList.add(geofence.getRequestId());
}
String status = "Some switches are on";
if (geoFenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER)
System.out.println(status);
return status + TextUtils.join(", ", triggeringGeofencesList);
}
private void sendNotification(String msg) {
//intent = new Intent(contextBootReceiver, MainActivity.class);
//intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
//contextBootReceiver.startActivity(intent);
Log.i(TAG, "sendNotification: " + msg);
// Intent to start the main Activity
Intent notificationIntent = MainActivity.makeNotificationIntent(
contextBootReceiver, msg
);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(contextBootReceiver);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(notificationIntent);
PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Creating and sending Notification
NotificationManager notificatioMng =
(NotificationManager) contextBootReceiver.getSystemService(Context.NOTIFICATION_SERVICE);
notificatioMng.notify(
GEOFENCE_NOTIFICATION_ID,
createNotification(msg, notificationPendingIntent));
}
// Create notification
private Notification createNotification(String msg, PendingIntent notificationPendingIntent) {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(contextBootReceiver);
notificationBuilder
.setSmallIcon(R.drawable.ic_action_location)
.setColor(Color.RED)
.setContentTitle(msg)
.setContentText("Droidhomes Notification!")
.setContentIntent(notificationPendingIntent)
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)
.setAutoCancel(true);
return notificationBuilder.build();
}
private static String getErrorString(int errorCode) {
switch (errorCode) {
case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
return "GeoFence not available";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
return "Too many GeoFences";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return "Too many pending intents";
default:
return "Unknown error.";
}
}
}
Write your service like this:
public class GeoFencingService extends Service{
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//write your notification code here
//use START_STICKY if you want your service keep running else use START_NOT_STICKY
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
//use this method to communicate with your activity
return null;
}
}
for detailed explanation have a look at these two links:
https://developer.android.com/guide/components/services.html
http://www.vogella.com/tutorials/AndroidServices/article.html
Let me know if any more help is required
So Far :-
When user in same(under fence area) it gives notification "user enters in area" is ok.But same user leave fence area its not notified.
This is my code:-
public class MainActivity extends AppCompatActivity implements
GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener,
LocationListener, OnMapReadyCallback, GoogleMap.OnMapClickListener, GoogleMap.OnMarkerClickListener,
ResultCallback<Status>
{
private static final String TAG = MainActivity.class.getSimpleName();
private GoogleMap map;
private GoogleApiClient googleApiClient;
private Location lastLocation;
private TextView textLat, textLong;
private MapFragment mapFragment;
private static final String NOTIFICATION_MSG = "NOTIFICATION MSG";
// Create a Intent send by the notification
public static Intent makeNotificationIntent(Context context, String msg) {
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra(NOTIFICATION_MSG, msg);
return intent;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textLat = (TextView) findViewById(R.id.lat);
textLong = (TextView) findViewById(R.id.lon);
// initialize GoogleMaps
initGMaps();
// create GoogleApiClient
createGoogleApi();
}
// Create GoogleApiClient instance
private void createGoogleApi() {
Log.d(TAG, "createGoogleApi()");
if (googleApiClient == null) {
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
#Override
protected void onStart() {
super.onStart();
// Call GoogleApiClient connection when starting the Activity
googleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
// Disconnect GoogleApiClient when stopping Activity
googleApiClient.disconnect();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.geofence: {
startGeofence();
return true;
}
case R.id.clear: {
clearGeofence();
return true;
}
}
return super.onOptionsItemSelected(item);
}
private final int REQ_PERMISSION = 999;
// Check for permission to access Location
private boolean checkPermission() {
Log.d(TAG, "checkPermission()");
// Ask for permission if it wasn't granted yet
return (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED);
}
// Asks for permission
private void askPermission() {
Log.d(TAG, "askPermission()");
ActivityCompat.requestPermissions(
this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQ_PERMISSION
);
}
// Verify user's response of the permission requested
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
Log.d(TAG, "onRequestPermissionsResult()");
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQ_PERMISSION: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted
getLastKnownLocation();
} else {
// Permission denied
permissionsDenied();
}
break;
}
}
}
// App cannot work without the permissions
private void permissionsDenied() {
Log.w(TAG, "permissionsDenied()");
// TODO close app and warn user
}
// Initialize GoogleMaps
private void initGMaps() {
mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
// Callback called when Map is ready
#Override
public void onMapReady(GoogleMap googleMap) {
Log.d(TAG, "onMapReady()");
map = googleMap;
map.setOnMapClickListener(this);
map.setOnMarkerClickListener(this);
}
#Override
public void onMapClick(LatLng latLng) {
Log.d(TAG, "onMapClick(" + latLng + ")");
//markerForGeofence(latLng);
}
#Override
public boolean onMarkerClick(Marker marker) {
Log.d(TAG, "onMarkerClickListener: " + marker.getPosition());
return false;
}
private LocationRequest locationRequest;
// Defined in mili seconds.
// This number in extremely low, and should be used only for debug
private final int UPDATE_INTERVAL = 1000;
private final int FASTEST_INTERVAL = 900;
// Start location Updates
private void startLocationUpdates() {
Log.i(TAG, "startLocationUpdates()");
locationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
if (checkPermission())
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged [" + location + "]");
lastLocation = location;
writeActualLocation(location);
}
// GoogleApiClient.ConnectionCallbacks connected
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.i(TAG, "onConnected()");
getLastKnownLocation();
recoverGeofenceMarker();
startGeofence();
}
// GoogleApiClient.ConnectionCallbacks suspended
#Override
public void onConnectionSuspended(int i) {
Log.w(TAG, "onConnectionSuspended()");
}
// GoogleApiClient.OnConnectionFailedListener fail
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.w(TAG, "onConnectionFailed()");
}
// Get last known location
private void getLastKnownLocation() {
Log.d(TAG, "getLastKnownLocation()");
if (checkPermission()) {
lastLocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
if (lastLocation != null) {
Log.i(TAG, "LasKnown location. " +
"Long: " + lastLocation.getLongitude() +
" | Lat: " + lastLocation.getLatitude());
writeLastLocation();
startLocationUpdates();
} else {
Log.w(TAG, "No location retrieved yet");
startLocationUpdates();
}
} else askPermission();
}
private void writeActualLocation(Location location) {
textLat.setText("Lat: " + location.getLatitude());
textLong.setText("Long: " + location.getLongitude());
markerLocation(new LatLng(location.getLatitude(), location.getLongitude()));
}
private void writeLastLocation() {
writeActualLocation(lastLocation);
}
private Marker locationMarker;
private void markerLocation(LatLng latLng) {
Log.i(TAG, "markerLocation(" + latLng + ")");
String title = latLng.latitude + ", " + latLng.longitude;
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.title(title);
if (map != null) {
if (locationMarker != null)
locationMarker.remove();
locationMarker = map.addMarker(markerOptions);
float zoom = 14f;
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, zoom);
map.animateCamera(cameraUpdate);
}
}
// Start Geofence creation process
private void startGeofence() {
Log.i(TAG, "startGeofence()");
Geofence geofence = createGeofence();
GeofencingRequest geofenceRequest = createGeofenceRequest(geofence);
addGeofence(geofenceRequest);
}
private static final long GEO_DURATION = 60 * 60 * 1000;
private static final String GEOFENCE_REQ_ID = "My Geofence";
private static final float GEOFENCE_RADIUS = 200.0f; // in meters
// Create a Geofence
private Geofence createGeofence() {
Log.d(TAG, "createGeofence");
return new Geofence.Builder()
.setRequestId(GEOFENCE_REQ_ID)
.setCircularRegion(18.478122, 73.890158, GEOFENCE_RADIUS)
.setExpirationDuration(GEO_DURATION)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_EXIT)
.build();
}
// Create a Geofence Request
private GeofencingRequest createGeofenceRequest(Geofence geofence) {
Log.d(TAG, "createGeofenceRequest");
return new GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.addGeofence(geofence)
.build();
}
private PendingIntent geoFencePendingIntent;
private static final int GEOFENCE_REQ_CODE = 0;
private PendingIntent createGeofencePendingIntent() {
Log.d(TAG, "createGeofencePendingIntent");
if (geoFencePendingIntent != null)
return geoFencePendingIntent;
Intent intent = new Intent(this, GeofenceTrasitionService.class);
return PendingIntent.getService(
this, GEOFENCE_REQ_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
// Add the created GeofenceRequest to the device's monitoring list
private void addGeofence(GeofencingRequest request) {
Log.d(TAG, "addGeofence");
if (checkPermission())
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
request,
createGeofencePendingIntent()
).setResultCallback(this);
}
#Override
public void onResult(#NonNull Status status) {
Log.i(TAG, "onResult: " + status);
if (status.isSuccess()) {
drawGeofence();
} else {
// inform about fail
}
}
// Draw Geofence circle on GoogleMap
private Circle geoFenceLimits;
private void drawGeofence() {
Log.d(TAG, "drawGeofence()");
if (geoFenceLimits != null)
geoFenceLimits.remove();
CircleOptions circleOptions = new CircleOptions()
.center(new LatLng(18.478122, 73.890158))
.strokeColor(Color.argb(50, 70, 70, 70))
.fillColor(Color.argb(100, 150, 150, 150))
.radius(GEOFENCE_RADIUS);
geoFenceLimits = map.addCircle(circleOptions);
}
private final String KEY_GEOFENCE_LAT = "GEOFENCE LATITUDE";
private final String KEY_GEOFENCE_LON = "GEOFENCE LONGITUDE";
// Saving GeoFence marker with prefs mng
private void saveGeofence() {
Log.d(TAG, "saveGeofence()");
SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
// editor.putLong(KEY_GEOFENCE_LAT, Double.doubleToRawLongBits(geoFenceMarker.getPosition().latitude));
// editor.putLong(KEY_GEOFENCE_LON, Double.doubleToRawLongBits(geoFenceMarker.getPosition().longitude));
editor.apply();
}
// Recovering last Geofence marker
private void recoverGeofenceMarker() {
drawGeofence();
}
// Clear Geofence
private void clearGeofence() {
Log.d(TAG, "clearGeofence()");
LocationServices.GeofencingApi.removeGeofences(
googleApiClient,
createGeofencePendingIntent()
).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
if (status.isSuccess()) {
// remove drawing
removeGeofenceDraw();
}
}
});
}
private void removeGeofenceDraw() {
Log.d(TAG, "removeGeofenceDraw()");
}
}
To get notification:-
public class GeofenceTrasitionService extends IntentService {
private static final String TAG = GeofenceTrasitionService.class.getSimpleName();
public static final int GEOFENCE_NOTIFICATION_ID = 0;
public GeofenceTrasitionService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
// Handling errors
if ( geofencingEvent.hasError() ) {
String errorMsg = getErrorString(geofencingEvent.getErrorCode() );
Log.e( TAG, errorMsg );
return;
}
int geoFenceTransition = geofencingEvent.getGeofenceTransition();
// Check if the transition type is of interest
if (geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT ) {
// Get the geofence that were triggered
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
String geofenceTransitionDetails = getGeofenceTrasitionDetails(geoFenceTransition, triggeringGeofences );
// Send notification details as a String
sendNotification( geofenceTransitionDetails );
}
}
private String getGeofenceTrasitionDetails(int geoFenceTransition, List<Geofence> triggeringGeofences) {
// get the ID of each geofence triggered
ArrayList<String> triggeringGeofencesList = new ArrayList<>();
for ( Geofence geofence : triggeringGeofences ) {
triggeringGeofencesList.add( geofence.getRequestId() );
}
String status = null;
if ( geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT )
status = "Exiting ";
return status + TextUtils.join( ", ", triggeringGeofencesList);
}
private void sendNotification( String msg ) {
Log.i(TAG, "sendNotification: " + msg );
// Intent to start the main Activity
Intent notificationIntent = MainActivity.makeNotificationIntent(
getApplicationContext(), msg
);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(notificationIntent);
PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Creating and sending Notification
NotificationManager notificatioMng =
(NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE );
notificatioMng.notify(
GEOFENCE_NOTIFICATION_ID,
createNotification(msg, notificationPendingIntent));
}
// Create notification
private Notification createNotification(String msg, PendingIntent notificationPendingIntent) {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
notificationBuilder
.setSmallIcon(R.drawable.ic_action_location)
.setColor(Color.RED)
.setContentTitle(msg)
.setContentText("Geofence Notification!")
.setContentIntent(notificationPendingIntent)
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)
.setAutoCancel(true);
return notificationBuilder.build();
}
private static String getErrorString(int errorCode) {
switch (errorCode) {
case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
return "GeoFence not available";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
return "Too many GeoFences";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return "Too many pending intents";
default:
return "Unknown error.";
}
}
}
As per tutorial i see:- there are 3 notification trigger
1.Enter 2.Dwell 3.Exit
I dont know how did i get notified when it leave the fence so far as in code i tried Exit.But no luck.
Ok i understand so just need to change the function :-
private GeofencingRequest createGeofenceRequest(Geofence geofence) {
Log.d(TAG, "createGeofenceRequest");
return new GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_EXIT)
.addGeofence(geofence)
.build();
}
Here i did changed My initial trigger with Exit
"GeofencingRequest.INITIAL_TRIGGER_EXIT"
and got perfect output.
This work for both enter and exit
private GeofencingRequest createGeofenceRequest(Geofence geofence) {
return new GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_EXIT|GeofencingRequest.INITIAL_TRIGGER_ENTER)
.addGeofence(geofence)
.build();
I am trying to add geofence when I receive it in FirebaseMessagingService. I am successfully able to add a geofence but for some reason, it doesn't fire. I have tried to debug and see what the problem is. But I simply can't figure out what the problem is. If anyone can point out the mistake. I would highly appreciate it.
This is my manifest
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<service
android:name=".GeofenceTrasitionService"
android:exported="true"/>
<service
android:name=".FirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name=".FirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
Now when I receive that particular message to add a geofence only then I add it in my onReceive().
public class FirebaseMessagingService extends FirebaseMessagingService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.i(TAG, "message_received");
Map<String, String> data = remoteMessage.getData();
String messageType = data.get("messageType");
switch (messageType) {
case "NewLocationAdded": {
if (checkPermission()) {
Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(#io.reactivex.annotations.NonNull CompletableEmitter e) throws Exception {
GEOFENCE_REQ_CODE_STRING = data.get("locationid");
locationName = data.get("locationname");
interval = Long.parseLong(data.get("interval"));
fastestInterval = Long.parseLong(data.get("fastestinterval"));
locationRadius = Long.parseLong(data.get("locationradius"));
SharedPreferences sharedPreferences = getSharedPreferences("UserDetails", MODE_PRIVATE);
DatabaseReference databaseReference = com.google.firebase.database.FirebaseDatabase
.getInstance()
.getReference("Locations" + "/" + sharedPreferences.getString("UserID", "") + "/" + GEOFENCE_REQ_CODE_STRING);
GeoFire geoFire = new GeoFire(databaseReference);
geoFire.getLocation("Location", new LocationCallback() {
#Override
public void onLocationResult(String key, GeoLocation location) {
x = location.latitude;
y = location.longitude;
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
latLng = new LatLng(x, y);
createGoogleApi();
mGoogleApiClient.connect();
}
}).observeOn(Schedulers.io()).subscribeOn(Schedulers.computation())
.subscribe(new DisposableCompletableObserver() {
#Override
public void onComplete() {
}
#Override
public void onError(#io.reactivex.annotations.NonNull Throwable e) {
Log.i(TAG, e.toString());
}
});
} else {
//Show Notitfication To Give Permission
}
break;
}
}
This works as expected. and when my mGoogleApiClient is connected I add my geofence.
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.i(TAG, "Connected to GoogleApiClient");
startLocationUpdates();
Geofence geofence = createGeofence(latLng, locationRadius, GEOFENCE_REQ_CODE_STRING);
GeofencingRequest geofenceRequest = createGeofenceRequest(geofence);
addGeofence(geofenceRequest);
}
I will include the above-written functions for clarity. What they do is pretty staright forward.
// Create GoogleApiClient instance
private void createGoogleApi() {
Log.i(TAG, "createGoogleApi()");
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
// Start location Updates
private void startLocationUpdates() {
Log.i(TAG, "startLocationUpdates()");
locationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(300)
.setFastestInterval(200);
if (checkPermission())
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, locationRequest, this);
}
// Create a Geofence
private Geofence createGeofence(LatLng latLng, float radius, String locationid) {
Log.i(TAG, "createGeofence");
return new Geofence.Builder()
.setRequestId(locationid)
.setCircularRegion(latLng.latitude, latLng.longitude, radius)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER
| Geofence.GEOFENCE_TRANSITION_EXIT | Geofence.GEOFENCE_TRANSITION_DWELL)
.setLoiteringDelay(30)
.build();
}
// Create a Geofence Request
private GeofencingRequest createGeofenceRequest(Geofence geofence) {
Log.i(TAG, "createGeofenceRequest");
return new GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.addGeofence(geofence)
.build();
}
// Add the created GeofenceRequest to the device's monitoring list
private void addGeofence(GeofencingRequest request) {
Log.i(TAG, "addGeofence");
if (checkPermission()) {
LocationServices.GeofencingApi.addGeofences(mGoogleApiClient, request, createGeofencePendingIntent())
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
Log.i(TAG, "onResult: " + status);
if (status.isSuccess()) {
saveGeofence();
// drawGeofence();
} else {
Log.i(TAG, "I failed in addGeofence()");
}
}
});
}
}
private PendingIntent createGeofencePendingIntent() {
Log.i(TAG, "createGeofencePendingIntent");
if (geoFencePendingIntent != null)
return geoFencePendingIntent;
Intent intent = new Intent(this, GeofenceTrasitionService.class);
return PendingIntent.getService(this, GEOFENCE_REQ_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private void saveGeofence() {
Log.i(TAG, "saveGeofence()");
ArrayList<String> stringArrayList = new ArrayList<String>();
SharedPreferences sharedPreferences = getSharedPreferences("Locations", MODE_PRIVATE);
if (sharedPreferences.contains("GeofenceReqIDs")) {
stringArrayList.addAll(sharedPreferences.getStringSet("GeofenceReqIDs", null));
}
SharedPreferences.Editor editor = sharedPreferences.edit();
stringArrayList.add(GEOFENCE_REQ_CODE_STRING);
Set<String> stringSet = new HashSet<String>();
stringSet.addAll(stringArrayList);
editor.putStringSet("GeofenceReqIDs", stringSet);
editor.apply();
}
I know I have shared a lot of code, but I did it for clarity to my problem. I also posted logs. Lemme share them as well.
checkPermission()
createGoogleApi()
Connected to GoogleApiClient
startLocationUpdates()
checkPermission()
createGeofence
createGeofenceRequest
addGeofence
checkPermission()
createGeofencePendingIntent
onLocationChanged [Location[fused 25.314668,55.495936 acc=21 et=+5d3h47m13s84ms]]
onResult: Status{statusCode=SUCCESS, resolution=null}
saveGeofence()
If anyone can point out the problem. I would really appreciate it :)
I'm trying to create an Android application with geofence locations that are loaded from an external API. I use retrofit to make the aysnc calls. The problem is that both the googleApiClient and the external API call are async. So I don't know which one finishes first in order to start the geofences.
If I start the geofences in the onConnected() of the googleApiClient, I might not yet have the LatLng's from the API. But if I start the geofences from the callback of the API, the googleApiClient might not yet have been loaded.
What could I do to handle this problem instead of just doing the async API call in the onConnected() of the googleApiClient. I'm trying to avoid multiple callback levels. Here is my code that currently doesn't work because I think the results of the API are not there yet when the startGeofences() is called:
public class GeofenceHelper implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener, ResultCallback<Status> {
private List<Geofence> mGeofenceList = new ArrayList<>();
private GoogleApiClient googleApiClient;
public GeofenceHelper(Activity context){
this.context = context;
permissionsHelper = new PermissionsHelper(context, REQ_PERMISSION);
buildGoogleApiClient();
geofencePointsRequest();
}
private void startGeofences() {
Log.i(TAG, "startGeofences()");
if (!googleApiClient.isConnected()) {
Log.d(TAG, "Not connected");
return;
}
if (permissionsHelper.checkPermission())
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult()
}
private void geofencePointsRequest() {
GeofenceAreasRequest response = new GeofenceAreasRequest();
response.getAllAreas(new GeofenceAreasResponse() {
#Override
public void onAreasLoaded(List<Point> points, int code) {
Log.i(TAG, "Responsecode: " + String.valueOf(code));
for (int i = 0; i < points.size(); i++) {
mGeofenceList.add(new Geofence.Builder()
.setRequestId(points.get(i).getName())
.setCircularRegion(
points.get(i).getLatitude(),
points.get(i).getLongitude(),
points.get(i).getRadius())
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER
| Geofence.GEOFENCE_TRANSITION_EXIT)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build());
}
}
});
}
private GeofencingRequest getGeofencingRequest() {
Log.d(TAG, "getGeofencingRequest");
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
public void start(){
googleApiClient.connect();
}
public void stop(){
googleApiClient.disconnect();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.i(TAG, "google api connected");
startGeofences();
getLastKnownLocation();
}
}
Try this approach
public class GeofenceHelper implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener, ResultCallback<Status> {
private List<Geofence> mGeofenceList = new ArrayList<>();
private GoogleApiClient googleApiClient;
private List<Point> pointsList = null;
public GeofenceHelper(Activity context) {
this.context = context;
permissionsHelper = new PermissionsHelper(context, REQ_PERMISSION);
// let both work in parallel
buildGoogleApiClient();
geofencePointsRequest();
}
private void startGeofences() {
Log.i(TAG, "startGeofences()");
if (!googleApiClient.isConnected()) {
Log.d(TAG, "Not connected");
return;
}
if (permissionsHelper.checkPermission())
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult()
}
private void registerGeofences() {
if (pointsList != null) {
// populate data in list
for (int i = 0; i < pointsList.size(); i++) {
mGeofenceList.add(new Geofence.Builder()
.setRequestId(pointsList.get(i).getName())
.setCircularRegion(
pointsList.get(i).getLatitude(),
pointsList.get(i).getLongitude(),
pointsList.get(i).getRadius())
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER
| Geofence.GEOFENCE_TRANSITION_EXIT)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build());
}
// this will actually register geofences
startGeofences();
}
}
private void geofencePointsRequest() {
GeofenceAreasRequest response = new GeofenceAreasRequest();
response.getAllAreas(new GeofenceAreasResponse() {
#Override
public void onAreasLoaded(List<Point> points, int code) {
Log.i(TAG, "Responsecode: " + String.valueOf(code));
pointsList = points;
registerGeofences();
}
});
}
private GeofencingRequest getGeofencingRequest() {
Log.d(TAG, "getGeofencingRequest");
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
public void start() {
googleApiClient.connect();
}
public void stop() {
googleApiClient.disconnect();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.i(TAG, "google api connected");
getLastKnownLocation();
registerGeofences();
}
}