I got some problems to keep a location tracking for my Android app.
The service we developed are all working, but depending on the phones and the API level, they are killed soon or later.
My purpose is to notify a user when he is getting out of a certain range, and this is working when the app is running.
This is the service that calculates when the user is in or out of the zone:
public class GeoFenceService extends BaseService {
#Inject
GeoFenceRepository geoFenceRepository;
SettingValueService settingValueService = new SettingValueService();
GeoFence geoFence;
private GeofencingClient mGeofencingClient;
PendingIntent mGeofencePendingIntent;
List<Geofence> mGeofenceList = new ArrayList<>();
public GeoFenceService() {
super();
Injector.getInstance().getAppComponent().inject(this);
}
public Observable<GeoFence> saveGeofence(GeoFence geoFence) {
if (geoFence.getId() == null)
geoFence.setId(CommonMethods.generateUuid());
commitToRealm(geoFence);
if (Application.getHasNetwork())
return geoFenceRepository.saveGeofence(geoFence);
else
return Observable.just(null);
}
public Observable<GeoFence> getGeofence() {
return geoFenceRepository.getGeofence();
}
public GeoFence getGeofenceFromRealm() {
Realm realm = Realm.getDefaultInstance();
RealmQuery<GeoFence> query = realm.where(GeoFence.class);
GeoFence result = query.findFirst();
if (result != null)
return realm.copyFromRealm(result);
return null;
}
public void initGeoFence(Context context) {
SettingValue autoCloking = settingValueService.getSettingByName("auto_clocking");
if (autoCloking != null && autoCloking.getValue().equals("true")) {
if (mGeofencingClient == null)
mGeofencingClient = LocationServices.getGeofencingClient(context);
geoFence = getGeofenceFromRealm();
if (geoFence != null) {
addGeofence(geoFence, context);
}
}
}
#SuppressLint("MissingPermission")
public void addGeofence(GeoFence geofence, Context context) {
mGeofenceList.clear();//only 1 geofence at the same time.
mGeofenceList.add(new Geofence.Builder()
// Set the request ID of the geofence. This is a string to identify this
// geofence.
.setRequestId(geofence.getId())
.setCircularRegion(
geofence.getLatitude(),
geofence.getLongitude(),
(float) geofence.getRadius()
)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setLoiteringDelay(30000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_EXIT | Geofence.GEOFENCE_TRANSITION_DWELL)
.build());
mGeofencingClient.addGeofences(getGeofencingRequest(), getGeofencePendingIntent(context));
}
private PendingIntent getGeofencePendingIntent(Context context) {
// Reuse the PendingIntent if we already have it.
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(context, GeofencingService.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
// calling addGeofences() and removeGeofences().
mGeofencePendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.
FLAG_UPDATE_CURRENT);
return mGeofencePendingIntent;
}
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER | GeofencingRequest.INITIAL_TRIGGER_EXIT);
builder.addGeofences(mGeofenceList);
return builder.build();
}
public void removeGeofence(Context context) {
if (mGeofencingClient != null)
mGeofencingClient.removeGeofences(getGeofencePendingIntent(context));
}
}
Even if this was working in the background we made a service to wake up the GPS of the phone every 60 sec following the advice of this question.
This is the service we made:
public class UpdateLocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private static final String TAG = "UpdateLocationService";
private static final int LOCATION_INTERVAL = 60000;
private Context mContext;
private LocationRequest locationRequest;
private GoogleApiClient googleApiClient;
private FusedLocationProviderApi fusedLocationProviderApi;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onCreate() {
Log.e(TAG, "onCreate");
mContext = this;
getLocation();
}
#Override
public void onDestroy() {
Log.e(TAG, "onDestroy");
super.onDestroy();
try {
if (googleApiClient != null) {
googleApiClient.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void getLocation() {
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(LOCATION_INTERVAL);
locationRequest.setFastestInterval(LOCATION_INTERVAL);
fusedLocationProviderApi = LocationServices.FusedLocationApi;
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
if (googleApiClient != null) {
googleApiClient.connect();
}
}
#Override
public void onConnected(Bundle arg0) {
// Location location =
fusedLocationProviderApi.getLastLocation(googleApiClient);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
fusedLocationProviderApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
#Override
public void onConnectionSuspended(int arg0) {
}
#Override
public void onLocationChanged(Location location) {
Toast.makeText(mContext, "User location :"+location.getLatitude()+" , "+location.getLongitude(), Toast.LENGTH_SHORT).show();
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
}
}
and finally this is the call in our main activity:
if (checkGpsProviderEnabled()) {
geoFenceService.initGeoFence(this);
Intent msgIntent = new Intent(this, GeofencingService.class);
startService(msgIntent);
startService(new Intent(this,UpdateLocationService.class));
}
Of course, we implement the authorization for Localisation and service déclaration in our AndroidManifest
And everything is working fine when the app isn't in the foreground
The foreground is working on some device but not all, and I wanted to know if I can do something more to force our services to run all the time in the background
Thanks in advance
Related
I am a novice in Android development. I tried to develop an Android app which will show a Google Map with a fixed Geofence Area and the current location of the concerned person. Whenever he / she leaves or enters that particular geofence region a notification will be shown. After searching various forums and stackoverflow for ideas I somehow manged to develop the application. But I am now facing the problem that it shows the notfication about the Entry / exit of Geofence area only when the app is open. If it is minimized and swiped out it doesn't run in background. I used GeofenceTransitionsJobIntentService for geofence transition changes. I think that I had done some silly mistake so it's not working in background. So please help me out from this problem.
Here's the full code. Any ideas where I'm going wrong ? Thanks in Advance
My codes:
GeofenceTransitionsJobIntentService.Java
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.
*/
#RequiresApi(api = Build.VERSION_CODES.M)
#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_EXIT) {
// 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 = getGeofenceTransitionDetails(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));
}
}
/**
* Gets transition details and returns them as a formatted string.
*
* #param geofenceTransition The ID of the geofence transition.
* #param triggeringGeofences The geofence(s) triggered.
* #return The transition details formatted as String.
*/
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;
}
/**
* 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) {
// Get an instance of the Notification manager
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Android O requires a Notification Channel.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.app_name);
// Create the channel for the notification
NotificationChannel mChannel =
new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_HIGH);
// Set the Notification Channel for the Notification Manager.
mNotificationManager.createNotificationChannel(mChannel);
}
// Create an explicit content Intent that starts the main Activity.
Intent notificationIntent = new Intent(getApplicationContext(), MapsActivity.class);
// Construct a task stack.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Add the main Activity to the task stack as the parent.
stackBuilder.addParentStack(MapsActivity.class);
// Push the content Intent onto the stack.
stackBuilder.addNextIntent(notificationIntent);
// Get a PendingIntent containing the entire back stack.
PendingIntent notificationPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Get a notification builder that's compatible with platform versions >= 4
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
// Define the notification settings.
builder.setSmallIcon(R.drawable.ic_launcher)
// In a real app, you may want to use a library like Volley
// to decode the Bitmap.
.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher))
.setColor(Color.RED)
.setOngoing(false)
.setPriority(Notification.PRIORITY_DEFAULT)
.setContentTitle(notificationDetails)
.setTicker(notificationDetails)
.setContentText(getString(R.string.geofence_transition_notification_text))
.setContentIntent(notificationPendingIntent);
// Set the Channel ID for Android O.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(CHANNEL_ID); // Channel ID
}
// Dismiss notification once the user touches it.
builder.setAutoCancel(true);
// Issue the notification
mNotificationManager.notify(0, builder.build());
}
/**
* Maps geofence transition types to their human-readable equivalents.
*
* #param transitionType A transition type constant defined in Geofence
* #return A String indicating the type of transition
*/
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);
}
}
}
GeofenceBroadcastReceiver.java
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class GeofenceBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Enqueues a JobIntentService passing the context and intent as parameters
GeofenceTransitionsJobIntentService.enqueueWork(context, intent);
}
}
MapsActivity.java
public class MapsActivity extends AppCompatActivity implements
GoogleMap.OnMyLocationButtonClickListener, OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener, OnCompleteListener<Void>
{
private static final String TAG = MapsActivity.class.getSimpleName();
static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
static final int RADIUS = 500;
private LocationManager locationManager;
private String provider;
private Location location;
private GoogleMap mMap;
private Circle circle;
private PendingIntent geofencePendingIntent;
private GeofencingClient geofencingClient;
private GoogleApiClient googleApiClient;
private boolean isContinue = false;
private boolean isGPS = false;
private LocationRequest locationRequest;
private final int UPDATE_INTERVAL = 2 * 60 * 1000;
private final int FASTEST_INTERVAL = 20 * 1000;
private final int NOTIFICATION_RESPONSIVENESS_TIME = 10000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
geofencingClient = LocationServices.getGeofencingClient(this);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
createGoogleApi();
new GpsUtils(this).turnGPSOn(new GpsUtils.onGpsListener() {
#Override
public void gpsStatus(boolean isGPSEnable) {
// turn on GPS
isGPS = isGPSEnable;
}
});
if (!checkPermissions()) {
requestPermissions();
}
}
#Override
public void onMapReady(GoogleMap googleMap)
{
Log.d(TAG,"onMapReady()");
mMap = googleMap;
mMap.setOnMyLocationButtonClickListener(this);
addGeofence(getMyLocation(), RADIUS);
drawCircle(getMyLocation(), RADIUS);
markerForGeofence(getMyLocation());
}
private void createGoogleApi()
{
if(googleApiClient==null)
{
googleApiClient=new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
#Override
public void onStart() {
super.onStart();
googleApiClient.connect();
if (checkPermissions()) {
// removeGeofence();
addGeofence(getMyLocation(), RADIUS);
// drawCircle(getMyLocation(), RADIUS);
// markerForGeofence(getMyLocation());
} else {
requestPermissions();
}
}
#Override
public void onStop() {
super.onStop();
googleApiClient.disconnect();
}
#Override
public void onConnected(#Nullable Bundle bundle)
{
Log.i(TAG, "onConnected()");
getLastKnownLocation();
addGeofence(getMyLocation(), RADIUS);
drawCircle(getMyLocation(), RADIUS);
markerForGeofence(getMyLocation());
}
#Override
public void onConnectionSuspended(int i)
{
Log.w(TAG, "onConnectionSuspended()");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult)
{
Log.w(TAG, "onConnectionFailed()");
}
// Get last known location
private void getLastKnownLocation() {
Log.d(TAG, "getLastKnownLocation()");
if ( checkPermissions() ) {
location = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
if ( location != null ) {
Log.i(TAG, "LasKnown location. " +
"Long: " + location.getLongitude() +
" | Lat: " + location.getLatitude());
writeLocation();
startLocationUpdates();
} else {
Log.w(TAG, "No location retrieved yet");
startLocationUpdates();
}
}
else requestPermissions();
}
// Start location Updates
private void startLocationUpdates(){
Log.i(TAG, "startLocationUpdates()");
locationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
if ( checkPermissions() )
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged ["+location+"]");
location = location;
writeActualLocation(location);
addGeofence(getMyLocation(), RADIUS);
}
// Write location coordinates on UI
private void writeActualLocation(Location location) {
markerLocation(new LatLng(location.getLatitude(), location.getLongitude()));
}
private void writeLocation() {
writeActualLocation(location);
}
private Marker locationMarker;
// Create a Location Marker
private void markerLocation(LatLng latLng) {
Log.i(TAG, "markerLocation("+latLng+")");
String title = "Your Current Location("+latLng.latitude + ", " + latLng.longitude+")";
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.title(title);
if ( mMap!=null ) {
// Remove the anterior marker
if ( locationMarker != null )
locationMarker.remove();
locationMarker = mMap.addMarker(markerOptions);
float zoom = 14f;
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, zoom);
mMap.animateCamera(cameraUpdate);
}
}
private Marker geoFenceMarker;
// Create a marker for the geofence creation
private void markerForGeofence(LatLng latLng) {
Log.i(TAG, "markerForGeofence("+latLng+")");
String title = "Your Geofence Area("+latLng.latitude + ", " + latLng.longitude+")";
// Define marker options
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE))
.title(title);
if ( mMap!=null ) {
// Remove last geoFenceMarker
if (geoFenceMarker != null)
geoFenceMarker.remove();
geoFenceMarker = mMap.addMarker(markerOptions);
}
}
/**
* Return the current state of the permissions needed.
*/
private boolean checkPermissions() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED )
{
return false;
}
else
{
return true;
}
}
private void requestPermissions() {
boolean shouldProvideRationale =
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION);
boolean shouldProvideRationale1 =
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION);
// Provide an additional rationale to the user. This would happen if the user denied the
// request previously, but didn't check the "Don't ask again" checkbox.
if (shouldProvideRationale || shouldProvideRationale1) {
Log.i(TAG, "Displaying permission rationale to provide additional context.");
Snackbar.make(
findViewById(R.id.activity_main),
R.string.permission_rationale,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.ok, new View.OnClickListener() {
#Override
public void onClick(View view) {
// Request permission
ActivityCompat.requestPermissions(MapsActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
})
.show();
} else {
Log.i(TAG, "Requesting permission");
// Request permission. It's possible this can be auto answered if device policy
// sets the permission in a given state or the user denied the permission
// previously and checked "Never ask again".
ActivityCompat.requestPermissions(MapsActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_BACKGROUND_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
}
// For creating GeoFence.
private Geofence createGeofence(LatLng latLng, int radiusMeters) {
return new Geofence.Builder()
// Set the request ID of the geofence. This is a string to identify this
// geofence.
.setRequestId("1")
.setCircularRegion(latLng.latitude, latLng.longitude, radiusMeters)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setNotificationResponsiveness(NOTIFICATION_RESPONSIVENESS_TIME)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
.build();
}
private GeofencingRequest getGeofencingRequest(LatLng latLng, int radiusMeters) {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_EXIT);
builder.addGeofence(createGeofence(latLng, radiusMeters));
return builder.build();
}
/**
* Callback received when a permissions request has been completed.
*/
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
Log.i(TAG, "onRequestPermissionResult");
if (requestCode == MY_PERMISSIONS_REQUEST_LOCATION) {
if (grantResults.length <= 0) {
// If user interaction was interrupted, the permission request is cancelled and you
// receive empty arrays.
Log.i(TAG, "User interaction was cancelled.");
} else if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED && grantResults[2] == PackageManager.PERMISSION_GRANTED) {
// Permission was granted.
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
getLastKnownLocation();
}
} else {
// Permission denied.
// setButtonsState(false);
Snackbar.make(
findViewById(R.id.activity_main),
R.string.permission_denied_explanation,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.settings, new View.OnClickListener() {
#Override
public void onClick(View view) {
// Build intent that displays the App settings screen.
Intent intent = new Intent();
intent.setAction(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package",
BuildConfig.APPLICATION_ID, null);
intent.setData(uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}).show();
}
}
}
#Override
public boolean onMyLocationButtonClick() {
// Return false so that we don't consume the event and the default behavior still occurs
// (the camera animates to the user's current position).
/* if (circle != null)
circle.remove();
drawCircle(getMyLocation(), RADIUS);*/
return false;
}
private void drawCircle(LatLng latLng, int radius) {
circle = mMap.addCircle(new CircleOptions()
.center(latLng)
.radius(radius)
.strokeWidth(0f)
.fillColor(0x55FF0000));
}
private PendingIntent getGeofencePendingIntent() {
// Reuse the PendingIntent if we already have it.
if (geofencePendingIntent != null) {
return geofencePendingIntent;
}
Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);
geofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return geofencePendingIntent;
}
private void removeGeofence() {
geofencingClient.removeGeofences(getGeofencePendingIntent()).addOnCompleteListener(this);
}
private void addGeofence(LatLng latLng, int radiusMeters) {
geofencingClient.addGeofences(getGeofencingRequest(latLng, radiusMeters), getGeofencePendingIntent())
.addOnCompleteListener(this);
}
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
} else {
}
}
}
Run Foreground service, when App goes to background. This solves your problem.
On Android 8.0 (API level 26) and higher, if an app is running in the background while monitoring a geofence, then the device responds to geofencing events every couple of minutes. To learn how to adapt your app to these response limits, see Background Location Limits.
You might need to run a sticky foreground service for your app to be running continuously.
I have a BroadcastReceiver which is used to receive data from a BLE device. The same code is working fine in an Activity but not in Fragment.
Here is the code:
public class HomeFragment extends Fragment implements LocationListener {
Session session;
TextView textViewName;
TextView textViewSteps;
TextView textViewCalories;
TextView textViewDistance;
TextView textViewFimos;
ImageView imageViewInfo;
public static final String TAG = "StepCounter";
private UARTService mService = null;
private BluetoothDevice evolutionDevice = null;
private static final int UART_PROFILE_CONNECTED = 20;
private static final int UART_PROFILE_DISCONNECTED = 21;
private int mState = UART_PROFILE_DISCONNECTED;
MyDatabase myDatabase;
LocationManager service;
private LocationManager locationManager;
private String provider;
double latitude, longitude;
List<Byte> listBytes = new ArrayList<>();
int rowNumber = 1;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.fragment_home, container, false);
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
init(view);
return view;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
service_init();
}
private void init(View view) {
session = new Session(getActivity());
myDatabase = new MyDatabase(getActivity());
service = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
boolean enabled = service.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!enabled) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
provider = locationManager.getBestProvider(criteria, false);
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
Location location = locationManager.getLastKnownLocation(provider);
// Initialize the location fields
if (location != null) {
System.out.println("Provider " + provider + " has been selected.");
onLocationChanged(location);
}
textViewName = view.findViewById(R.id.textViewName);
textViewSteps = view.findViewById(R.id.textViewSteps);
textViewCalories = view.findViewById(R.id.textViewCalories);
textViewDistance = view.findViewById(R.id.textViewDistance);
textViewFimos = view.findViewById(R.id.textViewFimos);
imageViewInfo = view.findViewById(R.id.imageViewInfo);
try {
textViewName.setText("Hi, " + session.getUser().getUser().getName());
} catch (Exception e) {
}
}
private void service_init() {
System.out.println("---->>>>");
Intent bindIntent = new Intent(getActivity().getApplicationContext(), UARTService.class);
getActivity().bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(UARTStatusChangeReceiver, makeGattUpdateIntentFilter());
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder rawBinder) {
mService = ((UARTService.LocalBinder) rawBinder).getService();
Log.d(TAG, "onServiceConnected mService= " + mService);
if (!mService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
getActivity().finish();
}
}
public void onServiceDisconnected(ComponentName classname) {
mService = null;
}
};
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(UARTService.ACTION_GATT_CONNECTED);
intentFilter.addAction(UARTService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(UARTService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(UARTService.ACTION_DATA_AVAILABLE);
intentFilter.addAction(UARTService.DEVICE_DOES_NOT_SUPPORT_UART);
return intentFilter;
}
private final BroadcastReceiver UARTStatusChangeReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
final Intent mIntent = intent;
//*********************//
if (action.equals(UARTService.ACTION_GATT_CONNECTED)) {
getActivity().runOnUiThread(new Runnable() {
public void run() {
System.out.println("------- Device Connected: " + evolutionDevice.getName() + " - " + evolutionDevice.getAddress());
mState = UART_PROFILE_CONNECTED;
}
});
}
//*********************//
if (action.equals(UARTService.ACTION_GATT_DISCONNECTED)) {
getActivity().runOnUiThread(new Runnable() {
public void run() {
System.out.println("------- Device Disconnected");
mState = UART_PROFILE_DISCONNECTED;
mService.close();
evolutionDevice = null;
}
});
}
//*********************//
if (action.equals(UARTService.ACTION_GATT_SERVICES_DISCOVERED)) {
mService.enableTXNotification();
}
//*********************//
if (action.equals(UARTService.ACTION_DATA_AVAILABLE)) {
final byte[] txValue = intent.getByteArrayExtra(UARTService.EXTRA_DATA);
List<Byte> byteList = Bytes.asList(txValue);
combineArrays(byteList);
}
//*********************//
if (action.equals(UARTService.DEVICE_DOES_NOT_SUPPORT_UART)) {
System.out.println("------- Device doesn't support UART. Disconnecting");
mService.disconnect();
}
}
};
#Override
public void onResume() {
super.onResume();
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
locationManager.requestLocationUpdates(provider, 400, 1, this);
Log.d(TAG, "onResume");
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()");
try {
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(UARTStatusChangeReceiver);
} catch (Exception ignore) {
Log.e(TAG, ignore.toString());
}
getActivity().unbindService(mServiceConnection);
mService.stopSelf();
mService = null;
}
The complete code in the same ay with a few changes in working fine in Activity. Any idea what might be the blocker.? Do I need to do something else in the fragment to receive the data from the Local Broadcast Manager.?
Please try this way :
Create class BroadcastHelper
public class BroadcastHelper {
public static final String BROADCAST_EXTRA_METHOD_NAME = "INPUT_METHOD_CHANGED";
public static final String ACTION_NAME = "hossam";
public static void sendInform(Context context, String method) {
Intent intent = new Intent();
intent.setAction(ACTION_NAME);
intent.putExtra(BROADCAST_EXTRA_METHOD_NAME, method);
try {
context.sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void sendInform(Context context, String method, Intent intent) {
intent.setAction(ACTION_NAME);
intent.putExtra(BROADCAST_EXTRA_METHOD_NAME, method);
try {
context.sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
And in your fragment :
private Receiver receiver;
private boolean isReciverRegistered = false;
#Override
public void onResume() {
super.onResume();
if (receiver == null) {
receiver = new Receiver();
IntentFilter filter = new IntentFilter(BroadcastHelper.ACTION_NAME);
getActivity().registerReceiver(receiver, filter);
isReciverRegistered = true;
}
}
#Override
public void onDestroy() {
if (isReciverRegistered) {
if (receiver != null)
getActivity().unregisterReceiver(receiver);
}
super.onDestroy();
}
private class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
Log.v("r", "receive " + arg1.getStringExtra(BroadcastHelper.BROADCAST_EXTRA_METHOD_NAME));
String methodName = arg1.getStringExtra(BroadcastHelper.BROADCAST_EXTRA_METHOD_NAME);
if (methodName != null && methodName.length() > 0) {
Log.v("receive", methodName);
switch (methodName) {
case "Test":
Toast.makeText(getActivity(), "message", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
}
}
And to send your broadcast this this code :
BroadcastHelper.sendInform(context, "Test");
Or if you want to send data with it use :
Intent intent = new Intent("intent");
intent.putExtra("desc", desc);
intent.putExtra("name", Local_name);
intent.putExtra("code", productCode);
BroadcastHelper.sendInform(getActivity(), "Test" , intent);
I have a fragment where I do something similar. I put my code to setup the service in onCreateView and have a register and unregister in onPause() and onResume. Works good for me.
Can you check modify register receiver in service_init()
as
getActivity().registerReceiver(UARTStatusChangeReceiver, makeGattUpdateIntentFilter());
and for unregisterer receiver
getActivity().unregisterReceiver(UARTStatusChangeReceiver);
I have an app that can capture fotos and send to the server.
I need to get location(lat,lon,alt) everytime i take a foto.
After a lot of research i understood that taking this data requires some time, the gps triangulation must run asyncronous, so i tried to figure out the best way to do this.
After some time, i had the idea, to start a service, everytime i run the aplication, this service will grab the last location everytime, and when i send a foto i will get the last location values.
So i did something like this(Service):
package com.example.afcosta.inesctec.pt.android.services;
import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
private static final String TAG = "BOOMBOOMTESTGPS";
private LocationManager mLocationManager = null;
private static final int LOCATION_INTERVAL = 1000;
private static final float LOCATION_DISTANCE = 10f;
private class LocationListener implements android.location.LocationListener
{
Location mLastLocation;
public LocationListener(String provider)
{
Log.e(TAG, "LocationListener " + provider);
mLastLocation = new Location(provider);
}
#Override
public void onLocationChanged(Location location)
{
Log.e("asd", "onLocationChanged: " + location);
mLastLocation.set(location);
}
#Override
public void onProviderDisabled(String provider)
{
Log.e(TAG, "onProviderDisabled: " + provider);
}
#Override
public void onProviderEnabled(String provider)
{
Log.e(TAG, "onProviderEnabled: " + provider);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
Log.e(TAG, "onStatusChanged: " + provider);
}
}
LocationListener[] mLocationListeners = new LocationListener[] {
new LocationListener(LocationManager.GPS_PROVIDER),
new LocationListener(LocationManager.NETWORK_PROVIDER)
};
#Override
public IBinder onBind(Intent arg0)
{
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.e(TAG, "onStartCommand");
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onCreate()
{
Log.e(TAG, "onCreate");
initializeLocationManager();
try {
mLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
mLocationListeners[1]);
} catch (java.lang.SecurityException ex) {
Log.i(TAG, "fail to request location update, ignore", ex);
} catch (IllegalArgumentException ex) {
Log.d(TAG, "network provider does not exist, " + ex.getMessage());
}
try {
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
mLocationListeners[0]);
} catch (java.lang.SecurityException ex) {
Log.i(TAG, "fail to request location update, ignore", ex);
} catch (IllegalArgumentException ex) {
Log.d(TAG, "gps provider does not exist " + ex.getMessage());
}
}
#Override
public void onDestroy()
{
Log.e(TAG, "onDestroy");
super.onDestroy();
if (mLocationManager != null) {
for (int i = 0; i < mLocationListeners.length; i++) {
try {
mLocationManager.removeUpdates(mLocationListeners[i]);
} catch (Exception ex) {
Log.i(TAG, "fail to remove location listners, ignore", ex);
}
}
}
}
private void initializeLocationManager() {
Log.e(TAG, "initializeLocationManager");
if (mLocationManager == null) {
mLocationManager = (LocationManager) getApplicationContext().getSystemService(this.LOCATION_SERVICE);
}
}
}
and then i call the service when my app runs(at the moment i am testing this just with login(onCreate))
startService(new Intent(this, MyService.class));
i get this logTrace(with red):
`05-22 20:35:39.652 32426-32426/com.example.afcosta.inesctec.pt.android E/BOOMBOOMTESTGPS: LocationListener gps
05-22 20:35:39.652 32426-32426/com.example.afcosta.inesctec.pt.android E/BOOMBOOMTESTGPS: LocationListener network
05-22 20:35:39.652 32426-32426/com.example.afcosta.inesctec.pt.android E/BOOMBOOMTESTGPS: onCreate
05-22 20:35:39.652 32426-32426/com.example.afcosta.inesctec.pt.android E/BOOMBOOMTESTGPS: initializeLocationManager
05-22 20:35:39.657 32426-32426/com.example.afcosta.inesctec.pt.android E/BOOMBOOMTESTGPS: onStartCommand
CHANGES
that was what i tried to do before:
`
public class GoogleLocation implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private double lat;
private double lon;
private double alt;
public double getLat() {
return lat;
}
public void setLat(double lat) {
this.lat = lat;
}
public double getLon() {
return lon;
}
public void setLon(double lon) {
this.lon = lon;
}
public double getAlt() {
return alt;
}
public void setAlt(double alt) {
this.alt = alt;
}
boolean gps_enabled = false;
boolean network_enabled = false;
private Context context;
LocationManager lm;
LocationListener listener;
final int MY_PERMISSION_ACCESS_COURSE_LOCATION = 1;
public GoogleLocation(Context context) {
this.context = context;
}
public void getPosition() {
lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
listener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
setLat(location.getLatitude());
setLon(location.getLongitude());
setAlt(location.getAltitude());
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
location();
}
#Override
public void onProviderDisabled(String provider) {
}
};
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions((Activity) context, new String[] { android.Manifest.permission.ACCESS_COARSE_LOCATION },
MY_PERMISSION_ACCESS_COURSE_LOCATION);
}
}
lm.requestLocationUpdates("gps", 5000, 0, listener);
}
public void location(){
GoogleApiClient googleApiClient = null;
if (googleApiClient == null) {
googleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
googleApiClient.connect();
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(30 * 1000);
locationRequest.setFastestInterval(1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
//**************************
builder.setAlwaysShow(true); //this is the key ingredient
//**************************
PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
final LocationSettingsStates state = result.getLocationSettingsStates();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
// All location settings are satisfied. The client can initialize location
// requests here.
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied. But could be fixed by showing the user
// a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(
(Activity) context, 1000);
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are not satisfied. However, we have no way to fix the
// settings so we won't show the dialog.
break;
}
}
});
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
}
`
i don't get any location, i don't know why, the onlocationchanged never runs, if the location doesn't change i want to get the last.
How can i accomplish that?
Thanks
Best regards
`
You don't need service class as you can get location in activity in which you are taking photos.
So first of all add permissions in manifest file
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
and dependencies in gradle
compile 'com.google.android.gms:play-services:10.2.6'
Then in activity in which you are taking photos
Implement listeners
public class Activity extends AppCompatActivity implements ConnectionCallbacks, OnConnectionFailedListener{
protected Location mLastLocation;
private double Latitude;
private double Longitude;
in onCreate method ask user for location permission and call
buildGoogleApiClient();
and then define buildGoogleApiClient() method
/**
* Builds a GoogleApiClient. Uses the addApi() method to request the LocationServices API.
*/
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
after that implements listener interfaces methods
#Override
public void onConnected(Bundle connectionHint) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLastLocation != null) {
Latitude = mLastLocation.getLatitude();
Longitude = mLastLocation.getLongitude();
}
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
#Override
public void onConnectionSuspended(int cause) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
Log.i(TAG, "Connection suspended");
mGoogleApiClient.connect();
}
then at the end
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
let me know if you don't understand anything
Business scenario:
The objective of business scenario is to update our longitude and latitude to server for an interval of every 15 mins in background
I have used Alaram Manger (Restarting Service when service gets shut down by android os)
i have shared my code below :
public class GoogleClientFusedApiService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private static final String TAG = "LocationService";
private boolean currentlyProcessingLocation = false;
private LocationRequest locationRequest;
private GoogleApiClient googleApiClient;
public static Boolean isRunning = false;
// The minimum time between updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1; // 15 minutes
#Override
public void onCreate() {
super.onCreate();
}
Handler mHandler = new Handler();
Runnable mHandlerTask = new Runnable() {
#Override
public void run() {
if (!isRunning) {
startTracking();
}
mHandler.postDelayed(mHandlerTask, 1000 * 60 * 2);
}
};
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// if we are currently trying to get a location and the alarm manager has called this again,
// no need to start processing a new location.
if (!currentlyProcessingLocation) {
currentlyProcessingLocation = true;
//startTracking();
mHandlerTask.run();
}
//alarm.setAlarm(this);
return START_STICKY;
// return START_NOT_STICKY;
}
private void startTracking() {
Log.d(TAG, "startTracking");
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
if (!googleApiClient.isConnected() || !googleApiClient.isConnecting()) {
googleApiClient.connect();
}
} else {
Log.e(TAG, "unable to connect to google play services.");
}
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onLocationChanged(Location location) {
if (location != null) {
String latitude = String.valueOf(location.getLatitude());
String longtitude = String.valueOf(location.getLongitude());
LocationUpdateServerCall locationUpdateServerCall = new LocationUpdateServerCall(getApplicationContext());
locationUpdateServerCall.pushLocationUpdateServerCall(latitude, longtitude);
Log.e(TAG, "position: " + location.getLatitude() + ", " + location.getLongitude() + " accuracy: " + location.getAccuracy());
// we have our desired accuracy of 500 meters so lets quit this service,
// onDestroy will be called and stop our location uodates
/* if (location.getAccuracy() < 10.0f) {
stopLocationUpdates();
}*/
}
}
private void stopLocationUpdates() {
if (googleApiClient != null && googleApiClient.isConnected()) {
googleApiClient.disconnect();
}
mHandler.removeCallbacks(mHandlerTask);
}
/**
* Called by Location Services when the request to connect the
* client finishes successfully. At this point, you can
* request the current location or start periodic updates
*/
#Override
public void onConnected(Bundle bundle) {
Log.d(TAG, "onConnected");
locationRequest = LocationRequest.create();
locationRequest.setInterval(MIN_TIME_BW_UPDATES); // milliseconds
locationRequest.setFastestInterval(MIN_TIME_BW_UPDATES); // the fastest rate in milliseconds at which your app can handle location updates
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setSmallestDisplacement(10); // distance travelled
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
if (googleApiClient.isConnected()) {
LocationServices.FusedLocationApi.requestLocationUpdates(
googleApiClient, locationRequest, this);
} else {
return;
}
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.e(TAG, "onConnectionFailed");
startTracking();
/* stopLocationUpdates();
stopSelf();*/
}
#Override
public void onConnectionSuspended(int i) {
Log.e(TAG, "GoogleApiClient connection has been suspend");
startTracking();
}
//Start Alarm(Start Location Updates on Background)
#Override
public void onTaskRemoved(Intent rootIntent) {
Intent restartServiceTask = new Intent(getApplicationContext(), this.getClass());
restartServiceTask.setPackage(getPackageName());
PendingIntent restartPendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceTask, PendingIntent.FLAG_ONE_SHOT);
AlarmManager myAlarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
myAlarmService.setRepeating(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime(), 1000 * 60 * 1
, restartPendingIntent);
super.onTaskRemoved(rootIntent);
}
// Canacel Alarm (Stop Location Update)
public void cancelAlarm(Activity context) {
Intent intent = new Intent(context, GoogleClientFusedApiService.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
Advance Thanks
Waiting For Valuable Guidelines
So I am trying to connect to the Google API client, but I am not getting a response from my onConnected method or onConnectionFailed method. Both methods are like so, respectively:
public void onConnected(#Nullable Bundle bundle) {
Log.d(TAG, "OnConnected");
if (PackageManager.PERMISSION_GRANTED ==
(ContextCompat.checkSelfPermission(mParentBase, android.Manifest.permission.ACCESS_FINE_LOCATION)))
{
Log.d(TAG, "Permission Was Granted" );
mMyLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mMyLocation == null) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, requestLocation, mParentIntent);
} else {
Log.d(TAG, mMyLocation.toString());
}
} else {
ActivityCompat.requestPermissions(mParentActivity, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSION_ACCESS_FINE_LOCATION);
Log.d(TAG, "Permission Was Requested" );
}
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.i(TAG, "Connection Failed");
if (connectionResult.hasResolution()) {
try {
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(mParentActivity, CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else {
Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
}
}
I have a public interface that starts the connection to the API:
public void connect()
{
mGoogleApiClient.connect();
Log.d(TAG, "Connection Requested");
}
I can see the above log output file on Android Studio Run Console.
Has anyone else seen this type of problem?
Edit:
Code to build and initialise the client
public myLocation(Context Base, Activity activitiyBase, PendingIntent intent) {
mParentBase = Base;
mParentActivity = activitiyBase;
mParentIntent = intent;
initialLocationService();
}
/**
* Initialize the Location Service and API Client
*/
private void initialLocationService(){
mGoogleApiClient = new GoogleApiClient.Builder(mParentBase)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
requestLocation = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10*1000)
.setFastestInterval(1*1000);
the class implements the following:
public class myLocation implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
ActivityCompat.OnRequestPermissionsResultCallback,
LocationListener
{
OK. I've put together some code that I hope will help you find your problem. I have this code as a working app on a device. I've used a mix of your code with mine. By comparing the differences, you should be able to narrow down your problem. 1st myLocation class...
public class myLocation implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
ActivityCompat.OnRequestPermissionsResultCallback,
LocationListener {
private final static String TAG = "myLocation";
private final static int MY_PERMISSION_ACCESS_FINE_LOCATION = 1;
private final static long ONE_SECOND = 1000;
private final static long UPDATE_INTERVAL = ONE_SECOND;
private final static long FASTEST_UPDATE_INTERVAL = ONE_SECOND;
private GoogleApiClient mGoogleApiClient = null;
Context mParentBase;
Activity mParentActivity;
public myLocation(Context Base, Activity activitiyBase) {
mParentBase = Base;
mParentActivity = activitiyBase;
initialLocationService();
}
// you call this an interface in your question but I'm just
// making it a public method which can be called from Activity
public void connect()
{
mGoogleApiClient.connect();
Log.d(TAG, "Connection Requested");
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.d(TAG, "OnConnected");
if (PackageManager.PERMISSION_GRANTED ==
(ContextCompat.checkSelfPermission(mParentBase,
android.Manifest.permission.ACCESS_FINE_LOCATION)))
{
Log.d(TAG, "Permission Was Granted");
startLocationUpdates();
} else {
ActivityCompat.requestPermissions(mParentActivity,
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSION_ACCESS_FINE_LOCATION);
Log.d(TAG, "Permission Was Requested");
}
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.i(TAG, "Connection Failed");
// just logging for now
}
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String[] permissions, #NonNull int[] grantResults) {
// loading from Android Studio, not going to worry about this now
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Connection Suspended");
// just logging for now, not trying to resolve failure
}
#Override
public void onLocationChanged(Location location) {
Log.i(TAG, "Entered the onLocationChanged() method");
// this calls one or the other private methods that don't
// matter to your problem. I can post them if you like.
if (location != null) {
showLocationInfo(location);
} else {
Log.d(TAG, "Can't get last location");
setAllUnavailable();
}
}
private void initialLocationService() {
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(mParentBase)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
private void locationRequestUpdates(long interval, long fastestInterval, int priority) {
// remove any previous updates
try {
if(mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi
.removeLocationUpdates(mGoogleApiClient, this);
}
} catch (SecurityException e) {
logException("SecurityException", e);
}
// build a new request
LocationRequest locationRequest = new LocationRequest()
.setInterval(interval)
.setFastestInterval(fastestInterval)
.setPriority(priority);
// now send new request
try {
if(mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, locationRequest, this);
}
} catch (SecurityException e) {
logException("SecurityException", e);
}
}
private void startLocationUpdates() {
Location lastLocation = null;
try {
lastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
} catch (SecurityException e) {
logException("SecurityException", e);
}
if (lastLocation != null) {
showLocationInfo(lastLocation);
} else {
Log.d(TAG, "Can't get last location");
setAllUnavailable();
}
locationRequestUpdates(UPDATE_INTERVAL,
FASTEST_UPDATE_INTERVAL,
LocationRequest.PRIORITY_HIGH_ACCURACY);
}
}
In the Activity, in onCreate()...
mMyLocation = new myLocation(getApplicationContext(), this);
and in onStart()...
mMyLocation.connect();
I hope this helps.