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 :)
Related
I am trying to implement geofencing in an app. As soon as user enters in the radius of geofence a notification is shown to the user and I have tried the below code but not getting notifications.Latitude and longitude are based on my location inside radius of geofencing.Any help will be appreciated :
MainActivity.java
public class MainActivity extends AppCompatActivity implements LocationListener{
PendingIntent mGeofencePendingIntent;
public static final int CONNECTION_FAILURE_RESOLUTION_REQUEST = 100;
private List<Geofence> mGeofenceList;
private GoogleApiClient mGoogleApiClient;
public static final String TAG = "Activity";
LocationRequest mLocationRequest;
double currentLatitude = 23.0023593, currentLongitude = 72.6665668;
Boolean locationFound;
protected LocationManager locationManager;
protected LocationListener locationListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
mGeofenceList = new ArrayList<Geofence>();
int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resp == ConnectionResult.SUCCESS) {
initGoogleAPIClient();
createGeofences(currentLatitude, currentLongitude);
} else {
Log.e(TAG, "Your Device doesn't support Google Play Services.");
}
// Create the LocationRequest object
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(1000)
.setFastestInterval(1000);
}
}
public void initGoogleAPIClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(connectionAddListener)
.addOnConnectionFailedListener(connectionFailedListener)
.build();
mGoogleApiClient.connect();
}
private GoogleApiClient.ConnectionCallbacks connectionAddListener =
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "onConnected");
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location == null) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, MainActivity.this);
} else {
currentLatitude = location.getLatitude();
currentLongitude = location.getLongitude();
Log.i(TAG, currentLatitude + " WORKS " + currentLongitude);
createGeofences(currentLatitude, currentLongitude);
}
try {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.i(TAG, "Saving Geofence");
} else {
Log.e(TAG, "Registering geofence failed: " + status.getStatusMessage() +
" : " + status.getStatusCode());
}
}
});
} catch (SecurityException securityException) {
Log.e(TAG, "Error");
}
}
#Override
public void onConnectionSuspended(int i) {
Log.e(TAG, "onConnectionSuspended");
}
};
public void createGeofences(double latitude, double longitude) {
String id = UUID.randomUUID().toString();
Geofence fence = new Geofence.Builder()
.setRequestId(id)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
.setCircularRegion(latitude, longitude, 1000)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build();
mGeofenceList.add(fence);
}
private GoogleApiClient.OnConnectionFailedListener connectionFailedListener =
new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.e(TAG, "onConnectionFailed");
}
};
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
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);
}
#Override
public void onLocationChanged(Location location) {
currentLatitude = location.getLatitude();
currentLongitude = location.getLongitude();
Log.i(TAG, "onLocationChanged");
}
}
GeofenceTransitionsIntentService.java
public class GeofenceTransitionsIntentService extends IntentService {
private static final String TAG = "GeofenceTransitions";
public GeofenceTransitionsIntentService() {
super("GeofenceTransitionsIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.i(TAG, "onHandleIntent");
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
//String errorMessage = GeofenceErrorMessages.getErrorString(this,
// geofencingEvent.getErrorCode());
Log.e(TAG, "Goefencing Error " + geofencingEvent.getErrorCode());
return;
}
int geofenceTransition = geofencingEvent.getGeofenceTransition();
Log.i(TAG, "geofenceTransition = " + geofenceTransition + " Enter : " + Geofence.GEOFENCE_TRANSITION_ENTER + "Exit : " + Geofence.GEOFENCE_TRANSITION_EXIT);
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || geofenceTransition == Geofence.GEOFENCE_TRANSITION_DWELL){
showNotification("Entered", "Entered the Location");
}
else if(geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
Log.i(TAG, "Showing Notification...");
showNotification("Exited", "Exited the Location");
} else {
showNotification("Error", "Error");
Log.e(TAG, "Error ");
}
}
public void showNotification(String text, String bigText) {
NotificationManager notificationManager =
(NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingNotificationIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Title")
.setContentText(text)
.setContentIntent(pendingNotificationIntent)
.setStyle(new NotificationCompat.BigTextStyle().bigText(bigText))
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.build();
notificationManager.notify(0, notification);
}
}
Manifest.xml file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="example.com.geofincingdemo">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".GeofenceTransitionsIntentService"
android:exported="true" />
</application>
</manifest>
My GPS is also on with high accuracy and I am running on API Level 23.
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 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.
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'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();
}
}