I am not able to add geofence from service class. Below is my code:
GeoFenceService:
package com.example.admin.reminderapp.services;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.util.Log;
import android.widget.Toast;
import com.example.admin.reminderapp.R;
import com.example.admin.reminderapp.database.model.Reminder;
import com.example.admin.reminderapp.geofencing.Constants;
import com.example.admin.reminderapp.geofencing.GeofenceErrorMessages;
import com.example.admin.reminderapp.geofencing.GeofenceTransitionsIntentService;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationServices;
import java.util.ArrayList;
import java.util.List;
public class GeoFenceService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private Context mContext = this;
private IBinder mIBinder = new LocalBinder();
private GoogleApiClient mGoogleApiClient;
public GeoFenceService() {
Log.i(getClass().getName(), "GeoFenceService()");
}
#Override
public IBinder onBind(Intent intent) {
return mIBinder;
}
protected synchronized void buildGoogleApiClient() {
Log.i("GeoFenceService", "buildGoogleApiClient");
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
#Override
public void onCreate() {
super.onCreate();
Log.i("GeoFenceService", "onCreate");
buildGoogleApiClient();
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i("GeoFenceService", "Connected to GoogleApiClient");
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.e("GeoFenceService", "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
#Override
public void onConnectionSuspended(int cause) {
Log.i("GeoFenceService", "Connection suspended");
}
private GeofencingRequest getGeofencingRequest(long reminderId) {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(populateGeofenceList(reminderId));
return builder.build();
}
public List<Geofence> populateGeofenceList(long reminderId) {
List<Geofence> geofenceList = new ArrayList<>();
Reminder reminder = Reminder.load(Reminder.class, reminderId);
Log.i("ReminderService", reminder.getId()+" - "+reminder.toString());
Geofence geofence = new Geofence.Builder()
.setRequestId(String.valueOf(reminderId))
.setCircularRegion(
reminder.getLat(),
reminder.getLat(),
(float) reminder.getKm() * 1000
)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_EXIT)
.build();
geofenceList.add(geofence);
return geofenceList;
}
private PendingIntent getGeofencePendingIntent(long reminderId) {
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
Log.i("ReminderService", intent +"");
// intent.putExtra("ReminderId", reminderId);
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public void addGeofence(long reminderId) {
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(this, getString(R.string.not_connected), Toast.LENGTH_SHORT).show();
return;
}
try {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(reminderId),
getGeofencePendingIntent(reminderId)
).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
if (status.isSuccess()) {
Toast.makeText(
mContext,
"Reminder Added.",
Toast.LENGTH_SHORT
).show();
} else {
String errorMessage = GeofenceErrorMessages.getErrorString(GeoFenceService.this, status.getStatusCode());
Log.e(GeoFenceService.this.getClass().getName(), errorMessage);
}
}
});
} catch (SecurityException securityException) {
Log.e(getClass().getName(), "Invalid location permission. You need to use ACCESS_FINE_LOCATION with geofences");
securityException.printStackTrace();
}
}
public void removeGeofence(long reminderId) {
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(this, getString(R.string.not_connected), Toast.LENGTH_SHORT).show();
return;
}
try {
LocationServices.GeofencingApi.removeGeofences(
mGoogleApiClient,
getGeofencePendingIntent(reminderId)
).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
if (status.isSuccess()) {
Toast.makeText(
mContext,
"Reminder Removed.",
Toast.LENGTH_SHORT
).show();
} else {
String errorMessage = GeofenceErrorMessages.getErrorString(GeoFenceService.this,
status.getStatusCode());
Log.e(GeoFenceService.this.getClass().getName(), errorMessage);
}
}
});
} catch (SecurityException securityException) {
Log.e(getClass().getName(), "Invalid location permission. You need to use ACCESS_FINE_LOCATION with geofences");
securityException.printStackTrace();
}
}
#Override
public void onDestroy() {
super.onDestroy();
mGoogleApiClient.disconnect();
}
public class LocalBinder extends Binder {
public GeoFenceService getService() {
return GeoFenceService.this;
}
}
}
GeoFenceTransitionIntentService:
package com.example.admin.reminderapp.geofencing;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.BitmapFactory;
import android.media.RingtoneManager;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.text.TextUtils;
import android.util.Log;
import com.example.admin.reminderapp.R;
import com.example.admin.reminderapp.activity.HomeActivity;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingEvent;
import java.util.ArrayList;
import java.util.List;
/**
* An {#link IntentService} subclass for handling asynchronous task requests in
* a service on a separate handler thread.
* <p/>
* TODO: Customize class - update intent actions, extra parameters and static
* helper methods.
*/
public class GeofenceTransitionsIntentService extends IntentService {
protected static final String TAG = "GeofenceTransitionsIS";
Boolean isMessageTone, isMessageVibrate;
String messageTone;
public GeofenceTransitionsIntentService() {
super(TAG);
Log.i(TAG, "GeofenceTransitionsIntentService");
}
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate");
}
// #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);
// return;
// }
//
// // Get the transition type.
// int geofenceTransition = geofencingEvent.getGeofenceTransition();
//
// // Test that the reported transition was of interest.
// if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
// geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
//
// // Get the geofences that were triggered. A single event can trigger
// // multiple geofences.
// List triggeringGeofences = geofencingEvent.getTriggeringGeofences();
//
// // Get the transition details as a String.
// String geofenceTransitionDetails = getGeofenceTransitionDetails(
// this,
// geofenceTransition,
// triggeringGeofences
// );
//
// // Send notification and log the transition details.
// sendNotification(geofenceTransitionDetails);
// Log.i(TAG, geofenceTransitionDetails);
// } else {
// // Log the error.
// Log.e(TAG, getString(R.string.geofence_transition_invalid_type,
// geofenceTransition));
// }
// }
#Override
protected void onHandleIntent(Intent intent) {
Log.i(TAG, "Intent");
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
String errorMessage = GeofenceErrorMessages.getErrorString(this,
geofencingEvent.getErrorCode());
Log.e(TAG, errorMessage);
return;
}
int geofenceTransition = geofencingEvent.getGeofenceTransition();
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
String geofenceTransitionDetails = getGeofenceTransitionDetails(
this,
geofenceTransition,
triggeringGeofences
);
sendNotification(geofenceTransitionDetails);
Log.i(TAG, geofenceTransitionDetails);
} else {
// Log the error.
Log.e(TAG, getString(R.string.geofence_transition_invalid_type, geofenceTransition));
}
}
private String getGeofenceTransitionDetails(
Context context,
int geofenceTransition,
List<Geofence> triggeringGeofences) {
String geofenceTransitionString = getTransitionString(geofenceTransition);
ArrayList triggeringGeofencesIdsList = new ArrayList();
for (Geofence geofence : triggeringGeofences) {
triggeringGeofencesIdsList.add(geofence.getRequestId());
}
String triggeringGeofencesIdsString = TextUtils.join(", ", triggeringGeofencesIdsList);
return geofenceTransitionString + ": " + triggeringGeofencesIdsString;
}
private void sendNotification(String notificationDetails) {
int notifyColor = getResources().getColor(R.color.primary);
SharedPreferences prefs = getSharedPreferences("NotificationPrefs", MODE_PRIVATE);
isMessageTone = prefs.getBoolean("is_message_notification", false);
isMessageVibrate = prefs.getBoolean("is_message_vibrate", false);
messageTone = prefs.getString("message_notificationTone", "");
SharedPreferences preferences = getSharedPreferences("Theme", MODE_PRIVATE);
int storedPreference = preferences.getInt("storedInt", 0);
if (storedPreference == 0 || storedPreference == 1) {
notifyColor = getResources().getColor(R.color.primary);
} else if (storedPreference == 2) {
notifyColor = getResources().getColor(R.color.primary_theme2);
} else if (storedPreference == 3) {
notifyColor = getResources().getColor(R.color.primary_theme3);
} else if (storedPreference == 4) {
notifyColor = getResources().getColor(R.color.primary_theme4);
} else if (storedPreference == 5) {
notifyColor = getResources().getColor(R.color.primary_theme5);
}
Intent notificationIntent = new Intent(getApplicationContext(), HomeActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(HomeActivity.class);
stackBuilder.addNextIntent(notificationIntent);
PendingIntent notificationPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
// Define the notification settings.
builder.setSmallIcon(R.drawable.ic_directions_black)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.drawable.ic_directions_black))
.setColor(notifyColor)
.setContentTitle(notificationDetails)
.setContentText(getString(R.string.geofence_transition_notification_text))
.setContentIntent(notificationPendingIntent);
if (isMessageTone) {
if (messageTone.equals("")) {
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
builder.setSound(defaultSoundUri);
} else {
builder.setSound(Uri.parse(messageTone));
}
if (isMessageVibrate) {
builder.setVibrate(new long[]{0, 1000});
}
}
builder.setAutoCancel(true);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, builder.build());
}
private String getTransitionString(int transitionType) {
switch (transitionType) {
case Geofence.GEOFENCE_TRANSITION_ENTER:
return getString(R.string.geofence_transition_entered);
case Geofence.GEOFENCE_TRANSITION_EXIT:
return getString(R.string.geofence_transition_exited);
default:
return getString(R.string.unknown_geofence_transition);
}
}
}
Problem:
I am able to get the toast "Geofence added". But when I am selecting my current location for fencing, its not triggering any notification. Before when I used to do this from activity, it use to trigger the notification if my device location is in fencing which I have added.
Please help me to find the issue.
Thanks.
I have done this way:
I have created GeoFenceObserversationService singleton class.
GeoFenceObserversationService.java:
public class GeoFenceObserversationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status> {
protected static final String TAG = "GeoFenceObserversationService";
protected GoogleApiClient mGoogleApiClient;
protected ArrayList<Geofence> mGeofenceList;
private boolean mGeofencesAdded;
private SharedPreferences mSharedPreferences;
private static GeoFenceObserversationService mInstant;
public static GeoFenceObserversationService getInstant(){
return mInstant;
}
#Override
public void onCreate() {
super.onCreate();
mInstant = this;
mGeofenceList = new ArrayList<Geofence>();
mSharedPreferences = getSharedPreferences(AppConstants.SHARED_PREFERENCES_NAME, MODE_PRIVATE);
mGeofencesAdded = mSharedPreferences.getBoolean(AppConstants.GEOFENCES_ADDED_KEY, false);
buildGoogleApiClient();
}
#Override
public void onDestroy() {
mGoogleApiClient.disconnect();
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
protected void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
#Override
public void onConnected(Bundle connectionHint) {
}
#Override
public void onConnectionFailed(ConnectionResult result) {
}
#Override
public void onConnectionSuspended(int cause) {
}
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
public void addGeofences() {
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(this, getString(R.string.not_connected), Toast.LENGTH_SHORT).show();
return;
}
populateGeofenceList();
if(!mGeofenceList.isEmpty()){
try {
LocationServices.GeofencingApi.addGeofences(mGoogleApiClient, getGeofencingRequest(), getGeofencePendingIntent()).setResultCallback(this);
} catch (SecurityException securityException) {
securityException.printStackTrace();
}
}
}
public void removeGeofences() {
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(this, getString(R.string.not_connected), Toast.LENGTH_SHORT).show();
return;
}
try {
LocationServices.GeofencingApi.removeGeofences(mGoogleApiClient,getGeofencePendingIntent()).setResultCallback(this);
} catch (SecurityException securityException) {
securityException.printStackTrace();
}
}
public void onResult(Status status) {
if (status.isSuccess()) {
mGeofencesAdded = !mGeofencesAdded;
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putBoolean(AppConstants.GEOFENCES_ADDED_KEY, mGeofencesAdded);
editor.apply();
} else {
String errorMessage = AppConstants.getErrorString(this,status.getStatusCode());
Log.i("Geofence", errorMessage);
}
}
private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private void populateGeofenceList() {
mGeofenceList.clear();
List<GeoFencingResponce> geoFenceList = getGeofencesList;
if(geoFenceList!=null&&!geoFenceList.isEmpty()){
for (GeoFencingResponce obj : geoFenceList){
mGeofenceList.add(obj.getGeofence());
Log.i(TAG,"Registered Geofences : " + obj.Id+"-"+obj.Name+"-"+obj.Lattitude+"-"+obj.Longitude);
}
}
}
}
AppConstant:
public static final String SHARED_PREFERENCES_NAME = PACKAGE_NAME + ".SHARED_PREFERENCES_NAME";
public static final String GEOFENCES_ADDED_KEY = PACKAGE_NAME + ".GEOFENCES_ADDED_KEY";
public static final String DETECTED_GEOFENCES = "detected_geofences";
public static final String DETECTED_BEACONS = "detected_beacons";
public static String getErrorString(Context context, int errorCode) {
Resources mResources = context.getResources();
switch (errorCode) {
case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
return mResources.getString(R.string.geofence_not_available);
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
return mResources.getString(R.string.geofence_too_many_geofences);
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return mResources.getString(R.string.geofence_too_many_pending_intents);
default:
return mResources.getString(R.string.unknown_geofence_error);
}
}
Where I started Service ? From Application class
startService(new Intent(getApplicationContext(),GeoFenceObserversationService.class));
How I registered Geofences ?
GeoFenceObserversationService.getInstant().addGeofences();
Hope this will help you.
Related
I'm creating a location based app which gets the current location of the user every 'x' minutes in the background, for that I'm planning to use PeriodicWorkRequest using WorkManager API.
But the thing is the minimum time for repeat interval is 15 minutes, so I thought I could use this Codelab (which uses Broadcast receiver in the pending intent) to get user's location updates, Which of the methods should I be using?
I'm planning to get Latitude and longitude coordinates from an API and create a Geofence with that latitude and longitude using Periodic Work Request Every 15 minutes in the Background, But the thing is I have Android Oreo and my Geofence does not seem to be triggered or I do not get any notification when my App is killed, I only get when app is in background or in the foreground even after I'm using Broadcast receiver for the pending intent in creating Geofence.
Also my periodic work does not seem to run as expected, because I Have put a test notification in the work and it gets executed only when I open the app for the first time and does not work after 15 minutes as it is expected to work, My Main Goal is to Create a periodic work request which runs every 15 minutes in the background, downloads location data from API and creates a geofence with that location, but since my work manager and geofence is not working properly I'm not able to achieve desired results. Any help would be appreciated. Here is the Code I'm using.
MainActivity:
package com.example.rohit.geofencefundo;
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final int LOC_PERM_REQ_CODE = 1;
//meters
private static final int GEOFENCE_RADIUS = 150;
//in milli seconds
private static final int GEOFENCE_EXPIRATION = 600000;
LocationManager locationManager;
android.location.LocationListener locationListener;
LatLng userLocation;
Data data;
private GoogleMap mMap;
private GeofencingClient geofencingClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* geofencingClient = LocationServices.getGeofencingClient(this);
showCurrentLocationOnMap();*/
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.g_map);
mapFragment.getMapAsync(this);
geofencingClient = LocationServices.getGeofencingClient(this);
//addresses = geocoder.getFromLocation(lat, lng, 1);
data = new Data.Builder()
.putString(BackgroundWork.EXTRA_TITLE, "Message from Activity!")
.putString(BackgroundWork.EXTRA_TEXT, "Hi! I have come from activity.")
.build();
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.getUiSettings().setZoomControlsEnabled(true);
mMap.setMinZoomPreference(15);
showCurrentLocationOnMap();
//locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
PeriodicWorkRequest.Builder photoCheckBuilder =
new PeriodicWorkRequest.Builder(BackgroundWork.class, 15,
TimeUnit.MINUTES)
.addTag("notifWorker");
// ...if you want, you can apply constraints to the builder here...
// Create the actual work object:
PeriodicWorkRequest photoCheckWork = photoCheckBuilder.setInputData(data).build();
// Then enqueue the recurring task:
WorkManager.getInstance().enqueue(photoCheckWork);
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng latLng) {
addLocationAlert(latLng.latitude, latLng.longitude);
}
});
}
#SuppressLint("MissingPermission")
private void showCurrentLocationOnMap() {
if (isLocationAccessPermitted()) {
requestLocationAccessPermission();
} else if (mMap != null) {
mMap.setMyLocationEnabled(true);
}
}
/*public void addFence(View view){
addLocationAlert(28.360596,75.5863917); //28.360596 75.5863917 budh bhavan
addLocationAlert( 28.3603219,75.5868534); //ram marg
}*/
/*#SuppressLint("MissingPermission")
private void showCurrentLocationOnMap() {
if (isLocationAccessPermitted()) {
requestLocationAccessPermission();
}
}*/
private boolean isLocationAccessPermitted() {
if (ContextCompat.checkSelfPermission(this,
android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
return true;
} else {
return false;
}
}
private void requestLocationAccessPermission() {
ActivityCompat.requestPermissions(this,
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
LOC_PERM_REQ_CODE);
}
#SuppressLint("MissingPermission")
private void addLocationAlert(double lat, double lng) {
if (isLocationAccessPermitted()) {
requestLocationAccessPermission();
} else {
String key = "" + lat + "-" + lng;
Geofence geofence = getGeofence(lat, lng, key);
/* geofencingClient.addGeofences(getGeofencingRequest(geofence),
getGeofencePendingIntent())
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText(MainActivity.this,
"Location alter has been added",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this,
"Location alter could not be added",
Toast.LENGTH_SHORT).show();
}
}
});*/
geofencingClient.addGeofences(getGeofencingRequest(geofence),
getGeofencePendingIntent())
.addOnSuccessListener(this, new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(MainActivity.this, "added", Toast.LENGTH_SHORT).show();
}
})
.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(MainActivity.this, e.toString(), Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
});
}
}
private void removeLocationAlert() {
if (isLocationAccessPermitted()) {
requestLocationAccessPermission();
} else {
geofencingClient.removeGeofences(getGeofencePendingIntent())
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText(MainActivity.this,
"Location alters have been removed",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this,
"Location alters could not be removed",
Toast.LENGTH_SHORT).show();
}
}
});
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
switch (requestCode) {
case LOC_PERM_REQ_CODE: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
showCurrentLocationOnMap();
Toast.makeText(MainActivity.this,
"Location access permission granted, you try " +
"add or remove location allerts",
Toast.LENGTH_SHORT).show();
}
return;
}
}
}
private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent(this, LocationAlertBroadcastReceiver.class);
return PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private GeofencingRequest getGeofencingRequest(Geofence geofence) {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_DWELL);
builder.addGeofence(geofence);
return builder.build();
}
private Geofence getGeofence(double lat, double lang, String key) {
return new Geofence.Builder()
.setRequestId(key)
.setCircularRegion(lat, lang, GEOFENCE_RADIUS)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_DWELL)
.setLoiteringDelay(10000)
.build();
}
#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.remove_loc_alert:
removeLocationAlert();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
GeofenceTransitionsJobIntentService:
package com.example.rohit.geofencefundo;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.location.Address;
import android.location.Geocoder;
import android.os.Build;
import android.support.v4.app.JobIntentService;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.text.TextUtils;
import android.util.Log;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingEvent;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Random;
public class GeofenceTransitionsJobIntentService extends JobIntentService {
private static final int JOB_ID = 573;
private static final String TAG = "GeofenceTransitionsIS";
private static final String CHANNEL_ID = "channel_01";
/**
* Convenience method for enqueuing work in to this service.
*/
public static void enqueueWork(Context context, Intent intent) {
enqueueWork(context, GeofenceTransitionsJobIntentService.class, JOB_ID, intent);
}
/**
* Handles incoming intents.
* #param intent sent by Location Services. This Intent is provided to Location
* Services (inside a PendingIntent) when addGeofences() is called.
*/
#Override
protected void onHandleWork(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
String errorMessage = GeofenceErrorMessages.getErrorString(this,
geofencingEvent.getErrorCode());
Log.e(TAG, errorMessage);
return;
}
// Get the transition type.
int geofenceTransition = geofencingEvent.getGeofenceTransition();
// Test that the reported transition was of interest.
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geofenceTransition == Geofence.GEOFENCE_TRANSITION_DWELL) {
// Get the geofences that were triggered. A single event can trigger multiple geofences.
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
// Get the transition details as a String.
String geofenceTransitionDetails = getGeofenceTransitionInfo(
triggeringGeofences);
String transitionType = getTransitionString(geofenceTransition);
sendNotification(transitionType, geofenceTransitionDetails);
sendNotification2(geofenceTransitionDetails);
Log.i(TAG, geofenceTransitionDetails);
} else {
// Log the error.
Log.e(TAG, getString(R.string.geofence_transition_invalid_type, geofenceTransition));
}
}
private String getGeofenceTransitionInfo(List<Geofence> triggeringGeofences) {
ArrayList<String> locationNames = new ArrayList<>();
for (Geofence geofence : triggeringGeofences) {
locationNames.add(getLocationName(geofence.getRequestId()));
}
String triggeringLocationsString = TextUtils.join(", ", locationNames);
return triggeringLocationsString;
}
private String getLocationNameGeocoder(double lat, double lng) {
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
List<Address> addresses = null;
try {
addresses = geocoder.getFromLocation(lat,lng, 1);
} catch (Exception ioException) {
Log.e("", "Error in getting location name for the location");
}
if (addresses == null || addresses.size() == 0) {
Log.d("", "no location name");
return null;
} else {
Address address = addresses.get(0);
ArrayList<String> addressInfo = new ArrayList<>();
for (int i = 0; i <= address.getMaxAddressLineIndex(); i++) {
addressInfo.add(address.getAddressLine(i));
}
return TextUtils.join(System.getProperty("line.separator"), addressInfo);
}
}
private String getLocationName(String key) {
String[] strs = key.split("-");
String locationName = null;
if (strs != null && strs.length == 2) {
double lat = Double.parseDouble(strs[0]);
double lng = Double.parseDouble(strs[1]);
locationName = getLocationNameGeocoder(lat, lng);
}
if (locationName != null) {
return locationName;
} else {
return key;
}
}
private String getGeofenceTransitionDetails(
int geofenceTransition,
List<Geofence> triggeringGeofences) {
String geofenceTransitionString = getTransitionString(geofenceTransition);
// Get the Ids of each geofence that was triggered.
ArrayList<String> triggeringGeofencesIdsList = new ArrayList<>();
for (Geofence geofence : triggeringGeofences) {
triggeringGeofencesIdsList.add(geofence.getRequestId());
}
String triggeringGeofencesIdsString = TextUtils.join(", ", triggeringGeofencesIdsList);
return geofenceTransitionString + ": " + triggeringGeofencesIdsString;
}
private void sendNotification(String locTransitionType, String locationDetails) {
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
String NOTIFICATION_CHANNEL_ID = "rohit901";
if(Build.VERSION.SDK_INT >=Build.VERSION_CODES.O){
#SuppressLint("WrongConstant") NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID,"My Notification",NotificationManager.IMPORTANCE_MAX);
notificationChannel.setDescription("rohit901 channel for app test FCM");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{0,1000,500,1000});
notificationChannel.enableVibration(true);
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this,NOTIFICATION_CHANNEL_ID);
notificationBuilder.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSmallIcon(android.support.compat.R.drawable.notification_icon_background)
.setTicker("Hearty365")
.setContentTitle(locTransitionType)
.setContentText(locationDetails)
.setContentInfo("info");
Random random = new Random();
int m = (int) ((new Date().getTime() / 1000L) % Integer.MAX_VALUE);
m += random.nextInt(100) + 1;
notificationManager.notify(m,notificationBuilder.build());
}
private String getTransitionString(int transitionType) {
switch (transitionType) {
case Geofence.GEOFENCE_TRANSITION_ENTER:
return getString(R.string.geofence_transition_entered);
case Geofence.GEOFENCE_TRANSITION_DWELL:
return "dwell at location";
case Geofence.GEOFENCE_TRANSITION_EXIT:
return getString(R.string.geofence_transition_exited);
default:
return getString(R.string.unknown_geofence_transition);
}
}
}
Background Work (Worker Class):
package com.example.rohit.geofencefundo;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.Random;
import androidx.work.Data;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
public class BackgroundWork extends Worker {
public static final String EXTRA_TITLE = "title";
public static final String EXTRA_TEXT = "text";
public static final String EXTRA_OUTPUT_MESSAGE = "output_message";
JSONObject jsonPart;
String result;
private Context mContext;
public BackgroundWork(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
mContext = context;
}
#NonNull
#Override
public Worker.Result doWork() {
//do work and shit
Log.d("work901","work and shit");
String title = getInputData().getString(EXTRA_TITLE);
String text = getInputData().getString(EXTRA_TEXT);
Log.d("work901tit","title from main is "+title);
Data output = new Data.Builder()
.putString(EXTRA_OUTPUT_MESSAGE, "I have come from MyWorker!")
.build();
sendNotification(title,text);
new JsonTask().execute("https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime=2018-10-20&endtime=2018-10-21&latitude=33.9370804&longitude=135.8284085&maxradiuskm=5000");
setOutputData(output);
return Result.SUCCESS;
}
private void sendNotification(String title, String text) {
NotificationManager notificationManager = (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
String NOTIFICATION_CHANNEL_ID = "rohit901";
if(Build.VERSION.SDK_INT >=Build.VERSION_CODES.O){
#SuppressLint("WrongConstant") NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID,"My Notification",NotificationManager.IMPORTANCE_MAX);
notificationChannel.setDescription("rohit901 channel for app test FCM");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{0,1000,500,1000});
notificationChannel.enableVibration(true);
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mContext,NOTIFICATION_CHANNEL_ID);
notificationBuilder.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSmallIcon(android.support.compat.R.drawable.notification_icon_background)
.setTicker("Hearty365")
.setContentTitle(title)
.setContentText(text)
.setContentInfo("info");
Random random = new Random();
int m = (int) ((new Date().getTime() / 1000L) % Integer.MAX_VALUE);
m += random.nextInt(100) + 1;
notificationManager.notify(m,notificationBuilder.build());
}
public class JsonTask extends AsyncTask<String,Void,String> {
#Override
protected void onPreExecute() {
// SHOW THE SPINNER WHILE LOADING FEEDS
//pd.show();
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//Toast.makeText(FeedBackActivity.this, "DOne", Toast.LENGTH_SHORT).show();
Log.d("rohit901",s);
result = s;
try {
JSONObject jsonObject = new JSONObject(result);
String features = jsonObject.getString("features"); //array of features
//JSONObject jsonObject2 = new JSONObject(features);
//String geometry = jsonObject2.getString("geometry"); //array of geometry
//JSONObject jsonObject3 = new JSONObject(geometry);
//String coordinates = jsonObject3.getString("coordinates");
JSONArray arr = new JSONArray(features);
JSONArray locArr;
Log.d("work901Array",arr.toString());
for(int i =0;i<arr.length();i++) {
jsonPart = arr.getJSONObject(i);
//jsonPart2 =
locArr = new JSONArray(jsonPart.getJSONObject("geometry").getString("coordinates"));
Log.d("geo901","Longitude: "+locArr.getString(0)+", Latitude: "+locArr.getString(1));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
protected String doInBackground(String... urls) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(urls[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line+"\n");
Log.d("Response: ", "> " + line); //here u ll get whole response...... :-)
}
return buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
}
Rest of my code is here: GitHub
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=new Intent(context,ActivityExpenseDetails.class);
intent.putExtra("employee_name",expenseArrayList.get(position).getEmployee_name());
intent.putExtra("expense_type",expenseArrayList.get(position).getExpense_type());
intent.putExtra("amount",expenseArrayList.get(position).getAmount());
intent.putExtra("description",expenseArrayList.get(position).getDescription());
context.startActivity(intent);
}
});
I have written an android app which basically allows me to keep track of times and address of GPS coordinates.
I have 3 Lists each corresponding to Lyft, Uber and Other.
But I believe my app starts slowing down my Smart Phone (Samsung Galaxy S7 Edge, with Android O)
can someone look at my code and tell me why is it slowing my smart phone.
My assumption is that, possibly thread synchronization issue.
Attached is my code
1) MainActivity.java
package com.milind.myapp.gpstrackingservice;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.PowerManager;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.ActionMode;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements AddressListener
{
private static final String TAG = MainActivity.class.getSimpleName();
private PowerManager.WakeLock wakeLock;
private TextView labelAddress;
private TextView multiTextLyft;
private TextView multiTextUber;
private TextView multiTextOther;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
labelAddress = findViewById(R.id.label_address);
multiTextLyft = findViewById(R.id.multi_text_lyft);
multiTextUber = findViewById(R.id.multi_text_uber);
multiTextOther = findViewById(R.id.multi_text_other);
if (MyService.isServiceStarted())
{
MyService.getInstance().load(getSharedPrefs());
refreshAllViews();
}
PowerManager powerManager = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "myapp:My Lock");
}
#Override
protected void onStart()
{
super.onStart();
ActivityCompat.requestPermissions(this, new String[]
{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WAKE_LOCK}, 1);
if (!MyService.isServiceStarted())
{
Intent intent = new Intent(this, MyService.class);
intent.setAction(MyService.ACTION_START_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
startForegroundService(intent);
}
else
{
startService(intent);
}
}
}
#Override
public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
if (hasFocus)
{
if (MyService.isServiceStarted())
{
MyService.getInstance().registerAddressListener(this);
}
wakeLock.acquire();
}
else
{
if (MyService.isServiceStarted())
{
MyService.getInstance().unregisterAddressListener(this);
}
wakeLock.release();
}
}
public void onRequestPermissionsResult(int requestCode, String permissions[],
int[] grantResults)
{
switch (requestCode)
{
case 1:
{
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
}
else
{
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
#Override
public void onLocationChanged(Location loc)
{
final String address = MyService.getAddress(this, loc);
final CharSequence text = labelAddress.getText();
if (text.toString().equals(address))
{
return;
}
MyService.getInstance().load(getSharedPrefs());
labelAddress.setText(address);
refreshAllViews();
new Tone().play(880);
}
private void refreshAllViews()
{
runOnUiThread(new Runnable()
{
public void run()
{
refereshEditTextLyft();
refereshEditTextUber();
refereshEditTextOther();
}
});
}
private void refereshEditTextLyft()
{
multiTextLyft.setText(MyService.getInstance().getLyftAddresses());
}
private void refereshEditTextUber()
{
multiTextUber.setText(MyService.getInstance().getUberAddresses());
}
private void refereshEditTextOther()
{
multiTextOther.setText(MyService.getInstance().getOtherAddresses());
}
private SharedPreferences getSharedPrefs()
{
return getSharedPreferences("name", MODE_PRIVATE);
}
public void onLyftButtonClicked(View view)
{
MyService.getInstance().addLyftAddress(labelAddress.getText());
new Tone().play(440);
refereshEditTextLyft();
MyService.getInstance().save(getSharedPrefs());
}
public void onUberButtonClicked(View view)
{
MyService.getInstance().addUberAddress(labelAddress.getText());
new Tone().play(440);
refereshEditTextUber();
MyService.getInstance().save(getSharedPrefs());
}
public void onOtherButtonClicked(View view)
{
MyService.getInstance().addOtherAddress(labelAddress.getText());
new Tone().play(440);
refereshEditTextOther();
MyService.getInstance().save(getSharedPrefs());
}
public void onClearButtonClicked(View view)
{
if (MyService.isServiceStarted())
{
SharedPreferences sharedPreferences = getSharedPrefs();
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.clear();
editor.commit();
MyService.getInstance().clear();
refereshEditTextLyft();
refereshEditTextUber();
refereshEditTextOther();
}
}
public void onDelLyftButtonClicked(View view)
{
MyService.getInstance().delLyftEntry();
new Tone().play(440);
refereshEditTextLyft();
MyService.getInstance().save(getSharedPrefs());
}
public void onDelUberButtonClicked(View view)
{
MyService.getInstance().delUberEntry();
new Tone().play(440);
refereshEditTextUber();
MyService.getInstance().save(getSharedPrefs());
}
public void onDelOtherButtonClicked(View view)
{
MyService.getInstance().delOtherEntry();
new Tone().play(440);
refereshEditTextOther();
MyService.getInstance().save(getSharedPrefs());
}
#Override
protected void onRestart()
{
super.onRestart();
}
#Override
public void onActionModeFinished(ActionMode mode)
{
super.onActionModeFinished(mode);
}
#Override
public void onBackPressed()
{
super.onBackPressed();
}
}
2) The MyService.java
package com.milind.myapp.gpstrackingservice;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class MyService extends Service implements LocationListener
{
private static final String TAG = MyService.class.getSimpleName();
public static final String ACTION_START_SERVICE = "ACTION_START_SERVICE";
public static final String ACTION_STOP_SERVICE = "ACTION_STOP_SERVICE";
public static final String ACTION_UBER = "ACTION_UBER";
public static final String ACTION_LYFT = "ACTION_UBER";
public static final String ACTION_END = "ACTION_END";
public static final String LYFT_PREFIX = "Lyft";
public static final String OTHER_PREFIX = "Other";
public static final String UBER_PREFIX = "Uber";
private static MyService mInstance = null;
private List<AddressListener> listeners = new ArrayList<>();
private List<AddressPoint> lyftAddresses = new ArrayList<>();
private List<AddressPoint> uberAddresses = new ArrayList<>();
private List<AddressPoint> otherAddresses = new ArrayList<>();
private Location mLastLocation;
public MyService()
{
super();
Log.d(TAG, "MyService(): constructor called");
}
public static boolean isServiceStarted()
{
Log.d(TAG, "isServiceStarted()");
return mInstance != null;
}
public static final MyService getInstance()
{
return mInstance;
}
#Override
public IBinder onBind(Intent intent)
{
Log.d(TAG, "onBind(Intent intent)");
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d(TAG, "onStartCommand(Intent, flags, startId) : " + hashCode());
Log.d(TAG, "onStartCommand(...) intent=" + intent + "=" + ", flags=" + flags + ", startId=" + startId);
Log.d(TAG, "onStartCommand(...) isServiceStarted=" + isServiceStarted());
String action = null;
if (intent != null)
{
Log.d(TAG, intent.toString());
action = intent.getAction();
}
else
{
Log.d(TAG, "onStartCommand(...): early return");
return super.onStartCommand(intent, flags, startId);
}
if (isServiceStarted() == false && action == ACTION_START_SERVICE)
{
Log.d(TAG, "onStartCommand(...): Service starting=" + startId);
//startForegroundServivceNotification()
startRunningInForeground();
requestLocationUpdates();
mInstance = this;
Log.d(TAG, "onStartCommand(...): Service started=" + startId);
}
else if (isServiceStarted() == true && action == ACTION_STOP_SERVICE)
{
Log.d(TAG, "onStartCommand(...): Service stopping=" + startId);
stopLocationUpdates();
stopSelf();
Log.d(TAG, "onStartCommand(...): Service stop requested" + startId);
mInstance = null;
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy()
{
Log.d(TAG, "onDestroy(): Service destroyed");
super.onDestroy();
mInstance = null;
}
private void stopLocationUpdates()
{
Log.d(TAG, "stopLocationUpdates()");
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.removeUpdates(this);
}
private void requestLocationUpdates()
{
Log.d(TAG, "requestLocationUpdates()");
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
try
{
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 1500, 0, this);
Log.w(TAG, "requestLocationUpdates(): ended gracefully");
}
catch (SecurityException ex)
{
Log.w(TAG, "requestLocationUpdates(): Exception");
ex.printStackTrace();
}
}
#Override
public void onLocationChanged(Location location)
{
Log.v(TAG, "onLocationChanged(Location location): started, location=" + location.toString());
dispatchLocationChange(location);
mLastLocation = location;
Log.v(TAG, "onLocationChanged: completed");
}
private void dispatchLocationChange(Location loc)
{
Log.v(TAG, "dispatchLocationChange(Location)");
for (AddressListener listener : listeners)
{
listener.onLocationChanged(loc);
}
}
public static String getAddress(Context context, Location loc)
{
Log.v(TAG, "getAddress(Location loc) started");
List<Address> addresses;
Geocoder gcd = new Geocoder(context, Locale.getDefault());
try
{
addresses = gcd.getFromLocation(loc.getLatitude(),
loc.getLongitude(), 1);
String strReturnAddress = "";
if (addresses != null && addresses.size() > 0)
{
final Address address = addresses.get(0);
Log.d(TAG, address.toString());
String addressLines = "";
Log.v(TAG, "Locale: " + address.getLocale());
for (int i = 0; i <= address.getMaxAddressLineIndex(); ++i)
{
Log.v(TAG, "AddressLine " + i + ": " + address.getAddressLine(i));
addressLines += address.getAddressLine(i) + ", ";
Log.v(TAG, "addressLines:" + addressLines);
}
String strAddress =
addressLines
;
Log.v(TAG, "strAddress:" + strAddress);
strReturnAddress = strAddress.substring(0, strAddress.length() - 2);
Log.v(TAG, "strReturnAddress:" + strReturnAddress);
}
Log.d(TAG, "getAddress(Location loc) completed with return=" + strReturnAddress);
return strReturnAddress;
}
catch (IOException e)
{
e.printStackTrace();
Log.d(TAG, "Exception", e);
}
Log.d(TAG, "getAddress(Location loc) completed with return=null");
return "";
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
Log.d(TAG, "onStatusChanged(provider, status, extras): status=" + status + ", extras=" + extras);
}
#Override
public void onProviderEnabled(String provider)
{
Log.d(TAG, "onProviderEnabled(provider) ");
}
#Override
public void onProviderDisabled(String provider)
{
Log.d(TAG, "onProviderDisabled(provider) ");
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
private static void logGetProperties(final String tag, final Object obj)
{
Log.v(tag, "logGetProperties(...)");
Class cls = obj.getClass();
Method[] methods = cls.getMethods();
Log.v(tag, "methods.length = " + methods.length);
for (Method method : methods)
{
String methodName = method.getName();
Log.v(tag, "methodName = " + methodName);
if (methodName.startsWith("get")
&& (method.getParameters() == null || method.getParameters().length == 0)
&& method.getReturnType() != Void.class)
{
try
{
Log.v(tag, methodName + " = " + method.invoke(obj, new Object[0]));
}
catch (Exception ex)
{
Log.e(tag, methodName + " Failed (exception)");
}
}
}
}
public AddressListener registerAddressListener(AddressListener listener)
{
Log.d(TAG, "registerAddressListener(AddressListener)");
if (!listeners.contains(listener))
{
listeners.add(listener);
}
return listener;
}
public AddressListener unregisterAddressListener(AddressListener listener)
{
Log.d(TAG, "unregisterAddressListener(AddressListener)");
if (listeners.contains(listener))
{
listeners.remove(listener);
Log.d(TAG, "unregisterAddressListener(AddressListener): Listener removed");
return listener;
}
Log.d(TAG, "unregisterAddressListener(AddressListener): Listener not found");
return null;
}
public void addLyftAddress(CharSequence text)
{
Log.d(TAG, "addLyftAddress(CharSequence text): text: " + text);
lyftAddresses.add(new AddressPoint(System.currentTimeMillis(), text));
}
public void addUberAddress(CharSequence text)
{
Log.d(TAG, "addUberAddress(CharSequence text): text: " + text);
uberAddresses.add(new AddressPoint(System.currentTimeMillis(), text));
}
public void addOtherAddress(CharSequence text)
{
Log.d(TAG, "addOtherAddress(CharSequence text): text: " + text);
otherAddresses.add(new AddressPoint(System.currentTimeMillis(), text));
}
String getLyftAddresses()
{
return getAddresses(lyftAddresses);
}
String getUberAddresses()
{
return getAddresses(uberAddresses);
}
String getOtherAddresses()
{
return getAddresses(otherAddresses);
}
private String getAddresses(List<AddressPoint> addresses)
{
Log.d(TAG, "getAddresses(List<AddressPoint>)");
String strAddresses = "" + addresses.size() + "\n--------\n";
for (int i = 0; i < addresses.size(); ++i)
{
AddressPoint addresspoint = addresses.get(i);
strAddresses += addresspoint + "\n--------\n";
if ((i % 2) != 0)
{
strAddresses += "\n\n";
}
}
return strAddresses;
}
private void startRunningInForeground()
{
//if more than or equal to 26
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
//if more than 26
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
{
String CHANNEL_ONE_ID = "Package.Service";
String CHANNEL_ONE_NAME = "Screen service";
NotificationChannel notificationChannel = null;
notificationChannel = new NotificationChannel(CHANNEL_ONE_ID,
CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_MIN);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setShowBadge(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (manager != null)
{
manager.createNotificationChannel(notificationChannel);
}
Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground);
Notification notification = new Notification.Builder(getApplicationContext())
.setChannelId(CHANNEL_ONE_ID)
.setContentTitle("Recording data")
.setContentText("App is running background operations")
.setSmallIcon(R.drawable.ic_launcher_background)
.setLargeIcon(icon)
.build();
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
notification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);
startForeground(101, notification);
}
//if version 26
else
{
startForeground(101, updateNotification());
}
}
//if less than version 26
else
{
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("App")
.setContentText("App is running background operations")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setOngoing(true).build();
startForeground(101, notification);
}
}
private Notification updateNotification()
{
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
return new NotificationCompat.Builder(this)
.setContentTitle("Activity log")
.setTicker("Ticker")
.setContentText("app is running background operations")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentIntent(pendingIntent)
.setOngoing(true).build();
}
public void load(final SharedPreferences lSharedPrefs)
{
Log.w(TAG, "load(SharedPreferences): started");
load(lSharedPrefs, lyftAddresses, LYFT_PREFIX);
load(lSharedPrefs, uberAddresses, UBER_PREFIX);
load(lSharedPrefs, otherAddresses, OTHER_PREFIX);
Log.w(TAG, "load(SharedPreferences): completed");
}
private void load(final SharedPreferences lSharedPrefs, final List<AddressPoint> lAddrPoints, final String lPrefix)
{
Log.w(TAG, "load(SharedPreferences, lAddrPoints, lPrefix)");
lAddrPoints.clear();
final int count = lSharedPrefs.getInt(lPrefix + "Count", lAddrPoints.size());
for (int i = 0; i < count; ++i)
{
String address = lSharedPrefs.getString(lPrefix + "Address" + i, null);
final long time = lSharedPrefs.getLong(lPrefix + "Time" + i, 0);
//if address or time is invalid skip to the next entry
if (address == null || time == 0)
{
continue;
}
final AddressPoint addressPoint = new AddressPoint(time, address);
lAddrPoints.add(addressPoint);
}
}
private void save(final SharedPreferences lSharedPrefs, final List<AddressPoint> lAddrPoints, final String lPrefix)
{
Log.w(TAG, "save(SharedPreferences, lAddrPoints, lPrefix)");
SharedPreferences.Editor editor = lSharedPrefs.edit();
final int count = lAddrPoints.size();
//Save the count
editor.putInt(lPrefix + "Count", count);
for (int i = 0; i < count; ++i)
{
//Save the entry
AddressPoint lAddrPoint = lAddrPoints.get(i);
editor.putLong(lPrefix + "Time" + i, lAddrPoint.getTime());
editor.putString(lPrefix + "Address" + i, (String) lAddrPoint.getAddress());
}
Log.w(TAG, "save(sharedFrefs, List, String): commit");
editor.commit();
}
public void save(final SharedPreferences sharedPreferences)
{
Log.w(TAG, "save(SharedPreferences): started");
Log.w(TAG, "save: lyftAddresses");
save(sharedPreferences, lyftAddresses, LYFT_PREFIX);
Log.w(TAG, "save: uberAddresses");
save(sharedPreferences, uberAddresses, UBER_PREFIX);
Log.w(TAG, "save: otherAddresses");
save(sharedPreferences, otherAddresses, OTHER_PREFIX);
Log.w(TAG, "save(SharedPreferences) completed");
}
public void clear()
{
lyftAddresses.clear();
uberAddresses.clear();
otherAddresses.clear();
}
public void delLyftEntry()
{
if (lyftAddresses.size() > 0)
{
lyftAddresses.remove(lyftAddresses.size() - 1);
}
}
public void delUberEntry()
{
if (uberAddresses.size() > 0)
{
uberAddresses.remove(uberAddresses.size() - 1);
}
}
public void delOtherEntry()
{
if (otherAddresses.size() > 0)
{
otherAddresses.remove(otherAddresses.size() - 1);
}
}
}
3) activity_main.xml
4) AndroidManifest.xml
This (likely) isn't a threading issue, in the normal sense of the word. What's happening is you've got a GeoCoder.getFromLocation() call executing on the main thread. Per the documentation:
The returned values may be obtained by means of a network lookup. ...It may be useful to call this method from a thread separate from your primary UI thread.
That means the method could block for several seconds each time it is called. That's more likely if you're driving through an area of spotty cell coverage. Since the method is called with each location update (roughly every 2 seconds), it's understandable that the UI is hanging.
SUGGESTED FIX
Replace your getAddress() function with an AsyncTask, which moves the getFromLocation() call to a background thread (now your app will truly be multithreaded). Something like this should work:
private class GetFromLocationTask extends AsyncTask<Location, Void, List<Address>> {
protected List<Address> doInBackground(Location... locs) {
return gcd.getFromLocation(locs[ 0 ].getLatitude(), locs[ 0 ].getLongitude(), 1);
}
protected void onProgressUpdate(Void... progress) {}
protected void onPostExecute(List<Address> result) {
//execute the remainder of your getAddress() logic here
}
}
Then, execute it using new GetFromLocationTask().execute(location). Call this instead of getAddress(). You don't need to pass a Context to getAddress(), since Service.this will work just as well (it is a Context).
Bonus hint: Note that onLocationChanged() runs on the UI thread, and so does refreshAllViews(). That means your call to runOnUiThread() is superfluous, and it will just execute the given Runnable synchronously.
I am using geofence api for proximity but it is not working properly. some times it gives in range and out range at the same location.
i am also using GPS library to improve accuracy of geofence inrange-outrange but still it is not working properly. i am using below code for geofence :
I am using 300 meters radius for considering inrange-outrange (enter-exit)
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.geofencedemo">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
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>
<activity
android:name=".CheckPermission"
android:screenOrientation="portrait"
android:theme="#style/DialogActivity" />
<receiver
android:name="services.GeofenceTransitionsReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="com.geofencedemo.ACTION_RECEIVE_GEOFENCE" />
<category android:name="com.geofencedemo" />
</intent-filter>
</receiver>
<service
android:name="services.GeofenceTransitionsIntentService"
android:exported="false" />
</application>
MainActivity.java (for registering geofence)
public class MainActivity extends Activity implements com.google.android.gms.location.LocationListener {
private LocationManager locationManager;
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private final float GEOFENCE_RADIUS_IN_METERS = 300;//Meter(s)
private final long GEOFENCE_EXPIRATION_IN_MILLISECONDS = Geofence.NEVER_EXPIRE;
private int GEOFENCE_TRANSITION_ENTER = 1;
private int GEOFENCE_TRANSITION_EXIT = 2;
private List<Geofence> mGeofenceList;
private String geofenceID = "testGeofence";
private SharedPreferences preferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
preferences = getSharedPreferences("ISSKEYGEOFENCE-prefs", MODE_PRIVATE);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Button btnSetLocation = (Button) findViewById(R.id.btn_setlocation);
btnSetLocation.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!isGPSEnabled) {
Toast.makeText(getApplicationContext(), "Please enable Location service to allow set location", Toast.LENGTH_LONG).show();
return;
}
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1){
Log.d("myTag", "check marshmallow permission...");
Intent permissionIntent = new Intent(MainActivity.this, CheckPermission.class);
startActivityForResult(permissionIntent, 1111);
} else {
intGoogleAPI();
}
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 1111:
if (resultCode == RESULT_OK) {
intGoogleAPI();
}
break;
}
}
private void intGoogleAPI() {
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(3000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setFastestInterval(1000);
mGeofenceList = new ArrayList<Geofence>(1);
mGoogleApiClient = new GoogleApiClient.Builder(MainActivity.this).addApi(LocationServices.API).addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(final Bundle bundle) {
if (isServiceConnected()) {
Log.d("myTag", "request for update current location");
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, MainActivity.this);
}
}
#Override
public void onConnectionSuspended(final int cause) {}
}).addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(final ConnectionResult connectionResult) {}
}).build();
mGoogleApiClient.connect();
}
private boolean isServiceConnected() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(MainActivity.this);
return ConnectionResult.SUCCESS == resultCode;
}
#Override
public void onLocationChanged(Location mLastLocation) {
if (isServiceConnected()) {
Log.d("myTag", "request removed location update");
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
try {
addLocation(mLastLocation.getLatitude(), mLastLocation.getLongitude());
} catch (Exception e) {}
}
public void addLocation(final double latitude, final double longitude) {
Log.v("myTag", "set lcation lat: " + latitude);
Log.v("myTag", "set lcation lag: " + longitude);
mGeofenceList.add(new Geofence.Builder().setRequestId(geofenceID).setTransitionTypes(GEOFENCE_TRANSITION_ENTER | GEOFENCE_TRANSITION_EXIT).setCircularRegion(latitude, longitude, GEOFENCE_RADIUS_IN_METERS).setExpirationDuration(GEOFENCE_EXPIRATION_IN_MILLISECONDS).build());
final List<String> GEO_FENCE_ID_LIST = new ArrayList<String>();
GEO_FENCE_ID_LIST.add(geofenceID);
if (mGoogleApiClient != null) {
LocationServices.GeofencingApi.removeGeofences(mGoogleApiClient, GEO_FENCE_ID_LIST).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(final Status status) {
if (status.isSuccess()) {
// successfully removed geofence...
Log.d("myTag", "removed old geofence successfully ");
} else {
Log.d("myTag", "Not removed old geofence");
}
}
});
}
if (mGoogleApiClient != null) {
LocationServices.GeofencingApi.addGeofences(mGoogleApiClient, getGeofencingRequest(), getGeofencePendingIntent()).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(final Status status) {
if (status.isSuccess()) {
// successfully Added geofence...
Log.d("myTag", "New geofence successfully added");
Toast.makeText(getApplicationContext(), "Successfully added geofence", Toast.LENGTH_LONG).show();
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("isinrange", false);
editor.putString("lat", String.valueOf(latitude));
editor.putString("log", String.valueOf(longitude));
editor.apply();
}
try {
if (isServiceConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, MainActivity.this);
}
mGoogleApiClient.disconnect();
} catch (Exception e) {}
}
});
}
}
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_EXIT);
builder.addGeofences(mGeofenceList);
return builder.build();
}
private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent("com.geofencedemo.ACTION_RECEIVE_GEOFENCE");
return PendingIntent.getBroadcast(MainActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
}
GeofenceTransitionsIntentService (Trigger inrange,outrange by geofence)
public class GeofenceTransitionsIntentService extends IntentService implements com.google.android.gms.location.LocationListener {
public GeofenceTransitionsIntentService() {
super("GeofenceTransitionsIntentService");
}
#Override
public void onCreate() {
super.onCreate();
preferences = getSharedPreferences("ISSKEYGEOFENCE-prefs", MODE_PRIVATE);
}
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private boolean isLocationFetched = false;
private String geofenceTransitionIds;
private boolean isInRange = false;
private SharedPreferences preferences;
#Override
protected void onHandleIntent(final Intent intent) {
if (intent.getExtras() != null) {
int geofenceTransitionType = intent.getIntExtra("TransitionType", 4);
geofenceTransitionIds = intent.getStringExtra("TransitionId");
/*final String lat = intent.getStringExtra("TransitionId_lat");
final String log = intent.getStringExtra("TransitionId_log");*/
if (geofenceTransitionIds != null && geofenceTransitionIds.length() > 0) {
switch (geofenceTransitionType) {
case Geofence.GEOFENCE_TRANSITION_ENTER:
geofenceTransitionIds(geofenceTransitionIds, true);
//new IntGoogleApiClient(appStorage, null, true).Intialize();
//processIn(geofenceTransitionIds, lat, log);
break;
case Geofence.GEOFENCE_TRANSITION_EXIT:
geofenceTransitionIds(geofenceTransitionIds, false);
//new IntGoogleApiClient(appStorage, null, true).Intialize();
//processOut(geofenceTransitionIds, lat, log);
break;
}
}
}
}
private void geofenceTransitionIds (String geofenceTransitionIds, boolean isEnteCall) {
if (geofenceTransitionIds != null && geofenceTransitionIds.length() > 0) {
isInRange = isEnteCall;
intGoogleAPI();
}
}
private void intGoogleAPI() {
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(3000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setFastestInterval(1000);
mGoogleApiClient = new GoogleApiClient.Builder(GeofenceTransitionsIntentService.this).addApi(LocationServices.API).addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(final Bundle bundle) {
if (isServiceConnected()) {
// please consider here location permission is already allowed...
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, GeofenceTransitionsIntentService.this);
}
}
#Override
public void onConnectionSuspended(final int cause) {}
}).addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(final ConnectionResult connectionResult) {}
}).build();
mGoogleApiClient.connect();
}
private boolean isServiceConnected() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(GeofenceTransitionsIntentService.this);
return ConnectionResult.SUCCESS == resultCode;
}
#Override
public void onLocationChanged(Location passedLocation) {
if (passedLocation != null && !isLocationFetched) {
if (isServiceConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, GeofenceTransitionsIntentService.this);
}
isLocationFetched = true;
try {
if (geofenceTransitionIds != null && geofenceTransitionIds.length() > 0) {
if (isInRange) {
processIn(geofenceTransitionIds, String.valueOf(passedLocation.getLatitude()), String.valueOf(passedLocation.getLongitude()));
} else {
processOut(geofenceTransitionIds, String.valueOf(passedLocation.getLatitude()), String.valueOf(passedLocation.getLongitude()));
}
}
} catch (Exception e) {}
disconnectGoogleClient();
}
}
private void disconnectGoogleClient() {
try {
if (mGoogleApiClient != null) {
if (isServiceConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, GeofenceTransitionsIntentService.this);
}
mGoogleApiClient.disconnect();
}
} catch (Exception e) {}
}
private void processIn(String passedIds, String lat, String log) {
if (passedIds != null) {
List<String> items = Arrays.asList(passedIds.split("\\s*,\\s*"));
for (String deviceName : items) {
if (deviceName != null) {
boolean isOutRange = preferences.getBoolean("isinrange", false);
if (mappingRadius(true, deviceName, lat, log) && isOutRange) {
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("isinrange", false);
editor.apply();
sendNotification(GeofenceTransitionsIntentService.this, "In range come!", Color.BLACK);
}
}
}
}
}
private void processOut(String passedIds, String lat, String log) {
if (passedIds != null) {
List<String> items = Arrays.asList(passedIds.split("\\s*,\\s*"));
for (String deviceName : items) {
if (deviceName != null) {
boolean isInRange = preferences.getBoolean("isinrange", false);
if (mappingRadius(false, deviceName, lat, log) && !isInRange) {
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("isinrange", true);
editor.apply();
sendNotification(GeofenceTransitionsIntentService.this, "Out range come!", Color.RED);
}
}
}
}
}
private boolean mappingRadius(boolean isInRange, String deviceName, String currentLat, String currentLog) {
final float cLat = Float.parseFloat(currentLat);
final float cLog = Float.parseFloat(currentLog);
Log.d("myTag", "GeofenceTransitionsReceiver lat " + cLat);
Log.d("myTag", "GeofenceTransitionsReceiver log " + cLog);
float appLat;
float appLog;
appLat = Float.parseFloat(preferences.getString("lat", "0.0"));
appLog = Float.parseFloat(preferences.getString("log", "0.0"));
Log.d("myTag", "GeofenceTransitionsReceiver app lat " + appLat);
Log.d("myTag", "GeofenceTransitionsReceiver app log " + appLog);
Location current_latlog = new Location("crntlocation");
current_latlog.setLatitude(appLat);
current_latlog.setLongitude(appLog);
Location new_latlog = new Location("newlocation");
new_latlog.setLatitude(cLat);
new_latlog.setLongitude(cLog);
final double distance = current_latlog.distanceTo(new_latlog);
Log.v("myTag", "GeofenceTransitionsReceiver calculation distance is: " + distance);
//if (distance < 2000) {
if (isInRange) {
if (distance <= 300) { // with in 300 Meters consider as in range...
return true;
} else {
return false;
}
} else {
if (distance >= 300) { // more than 300 Meters consider as out range...
return true;
} else {
return false;
}
}
/*} else {
return false;
}*/
}
private void sendNotification(final Context context, String notificationMessage, int color) {
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addNextIntent(new Intent());
PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setSmallIcon(R.mipmap.ic_launcher).setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher)).setContentTitle(context.getResources().getString(R.string.app_name)).setTicker(notificationMessage).setContentText(notificationMessage).setContentIntent(notificationPendingIntent).setColor(color).setVibrate(new long[] { 1000, 1000, 1000, 1000 }).setAutoCancel(true);
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify((int) System.currentTimeMillis(), builder.build());
}
}
GeofenceTransitionsReceiver (handling/calculate distance after geofence trigger)
public class GeofenceTransitionsReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
String errorMessage = getErrorString(context, geofencingEvent.getErrorCode());
Log.d("myTag", "GeofenceTransitionsReceiver error " +errorMessage);
// sendNotification(context, errorMessage, Color.RED);
return;
}
int geofenceTransition = geofencingEvent.getGeofenceTransition();
Log.d("myTag", "GeofenceTransitionsReceiver " + geofenceTransition);
// for testing....
//sendNotification(context, context.getResources().getString(R.string.geofence_transition_type, geofenceTransition), Color.RED);
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
String geofenceTransitionIds = getGeofenceTransitionIds(triggeringGeofences);
Location triggeringLocation = geofencingEvent.getTriggeringLocation();
Intent serviceIntent = new Intent(context.getApplicationContext(), GeofenceTransitionsIntentService.class);
serviceIntent.putExtra("TransitionType", geofenceTransition);
serviceIntent.putExtra("TransitionId", geofenceTransitionIds);
serviceIntent.putExtra("TransitionId_lat", String.valueOf(triggeringLocation.getLatitude()));
serviceIntent.putExtra("TransitionId_log", String.valueOf(triggeringLocation.getLongitude()));
context.startService(serviceIntent);
} else {
// sendNotification(context,
// context.getResources().getString(R.string.geofence_transition_invalid_type,
// geofenceTransition), Color.RED);
}
}
private String getErrorString(final Context context, int errorCode) {
Resources mResources = context.getResources();
switch (errorCode) {
case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
return "Geofence service is not available now";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
return "Your app has registered too many geofences";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return "You have provided too many PendingIntents to the addGeofences() call";
default:
return "Unknown error: the Geofence service is not available now";
}
}
private String getGeofenceTransitionIds(List<Geofence> triggeringGeofences) {
List<String> triggeringGeofencesIdsList = new ArrayList<String>();
for (Geofence geofence : triggeringGeofences) {
triggeringGeofencesIdsList.add(geofence.getRequestId());
}
return TextUtils.join(",", triggeringGeofencesIdsList);
}
}
Is there anything else we can do to improve accuracy and overcome the problem of inrange outrange at the same location ?
I'm trying to implement Geofence on my APP and the problem is that is not triggering when I'm on the place that I've marked.
The thing that I do is I set the Latitude & Longitude from a Place Picker.
The values that I'm getting are fine because I put it on google maps and the place is the correct one, because I've read many answers that people was setting bad values from lat/long.
I've two classes : GeofenceSingleton.class and GeofenceTransitionsIntentService.
The GeofenceSingleton.class looks like :
public class GeofenceSingleton implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status> {
private GoogleApiClient googleApiClient;
private static GeofenceSingleton _singleInstance;
private static Context appContext;
private static final String ERR_MSG = "Application Context is not set!! " +
"Please call GeofenceSngleton.init() with proper application context";
private PendingIntent mGeofencePendingIntent;
private static ArrayList<Geofence> mGeofenceList;
private GeofenceSingleton() {
if (appContext == null)
throw new IllegalStateException(ERR_MSG);
this.googleApiClient = new GoogleApiClient.Builder(this.appContext)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
this.googleApiClient.connect();
mGeofenceList = new ArrayList<Geofence>();
}
/**
* #param applicationContext
*/
public static void init(Context applicationContext) {
appContext = applicationContext;
}
public static GeofenceSingleton getInstance() {
if (_singleInstance == null)
synchronized (GeofenceSingleton.class) {
if (_singleInstance == null)
_singleInstance = new GeofenceSingleton();
}
return _singleInstance;
}
#Override
public void onConnected(Bundle bundle) {
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
public void addGeofence(Location location, String uid) {
mGeofenceList.add(new Geofence.Builder()
.setRequestId(uid)
.setCircularRegion(
location.getLatitude(),
location.getLongitude(),
500
)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
.setExpirationDuration(1000000)
.build());
}
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
private PendingIntent getGeofencePendingIntent() {
// Reuse the PendingIntent if we already have it.
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(appContext, GeofenceSingleton.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling
// addGeofences() and removeGeofences().
return PendingIntent.getService(appContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public void startGeofencing() {
if (!googleApiClient.isConnected()) {
Toast.makeText(appContext, "API client not connected", Toast.LENGTH_SHORT).show();
return;
}
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
// The GeofenceRequest object.
getGeofencingRequest(),
// A pending intent that that is reused when calling removeGeofences(). This
// pending intent is used to generate an intent when a matched geofence
// transition is observed.
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult().
Toast.makeText(appContext,"Geofencing started", Toast.LENGTH_LONG).show();
}
public void removeGeofence(){
LocationServices.GeofencingApi.removeGeofences(
googleApiClient,
// This is the same pending intent that was used in addGeofences().
getGeofencePendingIntent()
);
}
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
// Update state and save in shared preferences.
Toast.makeText(
appContext,
"YO",
Toast.LENGTH_SHORT
).show();
} else {
Toast.makeText(
appContext,
"NOO",
Toast.LENGTH_SHORT
).show();
}
}
}
And GeofenceTransitionsIntentService
public class GeofenceTransitionsIntentService extends IntentService {
private static final String TAG = "Geofence-Service";
private Handler handler;
SharedPreferences sp;
SharedPreferences.Editor editor;
String EmailName, MessageEmail;
Context mContext;
Boolean EmailSent = false;
public GeofenceTransitionsIntentService() {
super(TAG);
}
#Override
public void onCreate() {
super.onCreate();
this.mContext = this;
sp = PreferenceManager.getDefaultSharedPreferences(this);
handler = new Handler();
}
#Override
protected void onHandleIntent(Intent intent) {
final GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
Log.e(TAG, "Error in geofencing event");
return;
}
// Get the transition type.
final int geofenceTransition = geofencingEvent.getGeofenceTransition();
// Test that the reported transition was of interest.
if (geofenceTransition == 1) {
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "Entered", Toast.LENGTH_SHORT).show();
sendNotification();
}
});
Log.i(TAG, "Entered");
}
else {
// Log the error.
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "Sorry you are out", Toast.LENGTH_SHORT).show();
}
});
Log.e(TAG, String.valueOf(geofenceTransition));
}
}
private void sendNotification() {
Toast.makeText(GeofenceTransitionsIntentService.this, "HEEEEEEEY I'M IN", Toast.LENGTH_SHORT).show();
}
On my MainActivity I've got this :
GeofenceSingleton.init(this); //If I don't call this the class doesn't work
this.geofenceSingleton = GeofenceSingleton.getInstance();
And then I build a Geofence as follows :
Location geofence = new Location("");
geofence.setLatitude(Double.parseDouble(latitude));
geofence.setLongitude(Double.parseDouble(longitude));
geofenceSingleton.addGeofence(geofence, GeofenceKey);
geofenceSingleton.startGeofencing();
NOTES
I've added <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> on my manifest.xml
I declared the service as <service android:name=".GeofenceTransitionsIntentService"/>
And I added this line on my build.gradle : compile 'com.google.android.gms:play-services:7.8.0'
It only shows Toast.makeText(appContext,"YO",Toast.LENGTH_SHORT).show(); that's because status is success, and also shows the Toast.makeText(appContext,"Geofencing started", Toast.LENGTH_LONG).show(); means that it's started.
QUESTION
Why my IntentService is never called?
I tested it putting a Lat/Long of my home and since I'm on it should be triggered, isn't it?
It will never work because what you are doing is
Intent intent = new Intent(appContext, GeofenceSingleton.class);
passing intent to GeofenceSingleton ?
What you need to do is
Intent intent = new Intent(appContext, GeofenceTransitionsIntentService.class);
If your Intent is already constructed with the proper class (see varunkr's answer), you also need to make sure the service is also included in your AndroidManifest.xml.
<application
...
<service android:name=".GeofencingTransitionIntentService" />
Make sure your service and broadcast receive have these property enabled in manifest.
android:enabled="true"
android:exported="true"
I know similar questions have been asked before but answers were not perfect.
I created an app with geofences using the sample code from android developer website. I did not use any shared preferences to store geofences as I am not removing the geofences. I am testing the app from within the geofence, but my smartphone receives notifications every time the app runs and no notifications are observed when the app is killed. Why does this happen? I think I am supposed to receive notifications even when the app is killed.
MainActivity
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drawer_layout);
.....
GeofencingTask myTask = new GeofencingTask();
myTask.execute();
}
private class GeofencingTask extends AsyncTask<String,Void,String> implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(String... params) {
mGoogleApiClient = new GoogleApiClient.Builder(MainActivity.this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
mGeofenceList = new ArrayList<Geofence>();
mGeofenceList.add(new Geofence.Builder()
.setRequestId("1")
.setCircularRegion(
Constants.MyAPP_LOCATION_LATITUDE,
Constants.MyAPP_LOCATION_LONGITUDE,
Constants.MyAPP_RADIUS
)
.setExpirationDuration(Constants.GEOFENCE_EXPIRATION_TIME)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_EXIT)
.build());
return null;
}
protected void onPostExecute(String s) {
if (s == null) {
return;
}
}
#Override
public void onConnected(Bundle bundle) {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
);
Toast.makeText(MainActivity.this, "Starting gps", Toast.LENGTH_SHORT).show();
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(MainActivity.this,
Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception while resolving connection error.", e);
}
} else {
int errorCode = connectionResult.getErrorCode();
Log.e(TAG, "Connection to Google Play services failed with error code " + errorCode);
}
}
}
GeofenceTransitionsIntentService.java
public class GeofenceTransitionsIntentService extends IntentService{
String TAG = "GeofenceTransitionsIntentService";
int geofenceTransition;
public GeofenceTransitionsIntentService() {
super("name");
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
int errorCode = geofencingEvent.getErrorCode();
Log.e(TAG, "Location Services error: " + errorCode);
}
geofenceTransition = geofencingEvent.getGeofenceTransition();
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
// Get the geofences that were triggered. A single event can trigger
// multiple geofences.
List triggeringGeofences = geofencingEvent.getTriggeringGeofences();
// Get the transition details as a String.
String geofenceTransitionDetails = getGeofenceTransitionDetails(
this,
geofenceTransition,
triggeringGeofences
);
Log.i("GeofenceTransitionDetails",geofenceTransitionDetails);
// Send notification and log the transition details.
sendNotification(geofenceTransitionDetails);
sendInOutsTask myTask = new sendInOutsTask();
myTask.execute();
Log.i(TAG, geofenceTransitionDetails);
} else {
// Log the error.
Log.e(TAG, getString(R.string.geofence_transition_invalid_type,
geofenceTransition));
}
}
private String getGeofenceTransitionDetails(
Context context,
int geofenceTransition,
List<Geofence> triggeringGeofences) {
String geofenceTransitionString = getTransitionString(geofenceTransition);
// Get the Ids of each geofence that was triggered.
ArrayList triggeringGeofencesIdsList = new ArrayList();
for (Geofence geofence : triggeringGeofences) {
triggeringGeofencesIdsList.add(geofence.getRequestId());
}
String triggeringGeofencesIdsString = TextUtils.join(", ", triggeringGeofencesIdsList);
return geofenceTransitionString;
}
/**
* Posts a notification in the notification bar when a transition is detected.
* If the user clicks the notification, control goes to the MainActivity.
*/
private void sendNotification(String notificationDetails) {
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(notificationIntent);
PendingIntent notificationPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(R.mipmap.zemoso_logo)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.mipmap.zemoso_logo))
.setColor(Color.RED)
.setContentTitle(notificationDetails)
.setContentText(getString(R.string.geofence_transition_notification_text))
.setContentIntent(notificationPendingIntent);
builder.setAutoCancel(true);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, builder.build());
}
private String getTransitionString(int transitionType) {
switch (transitionType) {
case Geofence.GEOFENCE_TRANSITION_ENTER:
return Constants.WELCOME_NOTIFICATION;
case Geofence.GEOFENCE_TRANSITION_EXIT:
return Constants.EXIT_NOTIFICATION;
default:
return null;
}
}
}
Ok, May be a bit late but I'll post the answer on how I fixed this issue myself. Two things:
1) I was adding the geofences every time I run the MainActivity and geofences API triggers the geofencing event, if you add the geofences when you are already inside the specified geofence (i.e. starting the geofence app when you are already inside the geofence).
So I changed my code in the onConnected method to add the geofences only if they are not added previously. (Implemented a check using Shared preferences)
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected to GoogleApiClient");
SharedPreferences sharedPrefs = MainActivity.this.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE);
String geofencesExist = sharedPrefs.getString("Geofences added", null);
if (geofencesExist == null) {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent(this)
).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
SharedPreferences sharedPrefs = MainActivity.this.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString("Geofences added", "1");
editor.commit();
}
}
});
}
}
2) Turns out the reasons for not receiving notifications when the app is not available were
i) Either I toggled location services in the device(on/off/battery saving/device only/high accuracy) at least once after I added the geofences or,
ii) The device was rebooted.
To overcome this, I have added a broadcast receiver to listen to device reboots and location services toggling. In the receiver, I am adding the geofences again if the device either rebooted or location services toggled.
public class BootReceiver extends BroadcastReceiver implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status> {
private static GoogleApiClient mGoogleApiClient;
private static List<Geofence> mGeofenceList;
private static PendingIntent mGeofencePendingIntent;
private static final String TAG = "BootReceiver";
Context contextBootReceiver;
#Override
public void onReceive(final Context context, Intent intent) {
contextBootReceiver = context;
SharedPreferences sharedPrefs;
SharedPreferences.Editor editor;
if ((intent.getAction().equals("android.location.MODE_CHANGED") && isLocationModeAvailable(contextBootReceiver)) || (intent.getAction().equals("android.location.PROVIDERS_CHANGED") && isLocationServciesAvailable(contextBootReceiver))) {
// isLocationModeAvailable for API >=19, isLocationServciesAvailable for API <19
sharedPrefs = context.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE);
editor = sharedPrefs.edit();
editor.remove("Geofences added");
editor.commit();
if (!isGooglePlayServicesAvailable()) {
Log.i(TAG, "Google Play services unavailable.");
return;
}
mGeofencePendingIntent = null;
mGeofenceList = new ArrayList<Geofence>();
mGeofenceList.add(new Geofence.Builder()
.setRequestId("1")
.setCircularRegion(
Constants.MyAPP_LOCATION_LATITUDE,
Constants.MyAPP_LOCATION_LONGITUDE,
Constants.MyAPP_LOCATION_RADIUS
)
.setExpirationDuration(Constants.GEOFENCE_EXPIRATION_TIME)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_DWELL |
Geofence.GEOFENCE_TRANSITION_EXIT)
.setLoiteringDelay(30000)
.build());
mGoogleApiClient = new GoogleApiClient.Builder(contextBootReceiver)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
}
private boolean isLocationModeAvailable(Context context) {
if (Build.VERSION.SDK_INT >= 19 && getLocationMode(context) != Settings.Secure.LOCATION_MODE_OFF) {
return true;
}
else return false;
}
public boolean isLocationServciesAvailable(Context context) {
if (Build.VERSION.SDK_INT < 19) {
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
return (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) || lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER));
}
else return false;
}
public int getLocationMode(Context context) {
try {
return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
return 0;
}
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected to GoogleApiClient");
SharedPreferences sharedPrefs = contextBootReceiver.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE);
String geofencesExist = sharedPrefs.getString("Geofences added", null);
if (geofencesExist == null) {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent(contextBootReceiver)
).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
SharedPreferences sharedPrefs = contextBootReceiver.getSharedPreferences("GEO_PREFS", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString("Geofences added", "1");
editor.commit();
}
}
});
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult((android.app.Activity) contextBootReceiver,
Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
Log.i(TAG, "Exception while resolving connection error.", e);
}
} else {
int errorCode = connectionResult.getErrorCode();
Log.i(TAG, "Connection to Google Play services failed with error code " + errorCode);
}
}
#Override
public void onResult(Status status) {
}
private boolean isGooglePlayServicesAvailable() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(contextBootReceiver);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, (android.app.Activity) contextBootReceiver,
Constants.PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Log.i(TAG, "This device is not supported.");
}
return false;
}
return true;
}
static GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_DWELL);
builder.addGeofences(mGeofenceList);
return builder.build();
}
static PendingIntent getGeofencePendingIntent(Context context) {
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(context, GeofenceTransitionsIntentService.class);
return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
}
Android Manifest
.
.
.
<receiver
android:name=".BootReceiver"
android:enabled="true"
android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.location.MODE_CHANGED" />
<action android:name="android.location.PROVIDERS_CHANGED" />
</intent-filter>
</receiver>
.
.