I am creating a attendance monitoring app for my campus using geofencing api.Everything else is working smoothly, but I want my app to work in the background.(Similar to a music player). Currently, it works only when the app is open. Here is the Service class code I have used:
package com.app.androidkt.geofencing;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class BackgroundService extends Service{
MainActivity main;
public int onStartCommand(Intent intent, int flags, int startId) {
main.isMonitoring = true;
main.startGeofencing();
main.startLocationMonitor();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
//use this method to communicate with your activity
return null;
}
}
And here is the MainActivity.java:
package com.app.androidkt.geofencing;
import android.Manifest;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
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.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.Circle;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
public class MainActivity extends AppCompatActivity implements
OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener{
private static final String TAG = "MainActivity";
private static final int REQUEST_LOCATION_PERMISSION_CODE = 101;
private GoogleMap googleMap;
private GeofencingRequest geofencingRequest;
public GoogleApiClient googleApiClient;
public boolean isMonitoring = false;
private MarkerOptions markerOptions;
private Marker currentLocationMarker;
private PendingIntent pendingIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_LOCATION_PERMISSION_CODE);
}
}
public void startLocationMonitor() {
Log.d(TAG, "start location monitor");
LocationRequest locationRequest = LocationRequest.create()
.setInterval(2000)
.setFastestInterval(1000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
try {
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, new LocationListener() {
#Override
public void onLocationChanged(Location location) {
if (currentLocationMarker != null) {
currentLocationMarker.remove();
}
markerOptions = new MarkerOptions();
markerOptions.position(new LatLng(location.getLatitude(), location.getLongitude()));
markerOptions.title("Current Location");
currentLocationMarker = googleMap.addMarker(markerOptions);
Log.d(TAG, "Location Change Lat Lng " + location.getLatitude() + " " + location.getLongitude());
}
});
} catch (SecurityException e) {
Log.d(TAG, e.getMessage());
}
}
public void startGeofencing() {
Log.d(TAG, "Start geofencing monitoring call");
pendingIntent = getGeofencePendingIntent();
geofencingRequest = new GeofencingRequest.Builder()
.setInitialTrigger(Geofence.GEOFENCE_TRANSITION_ENTER)
.addGeofence(getGeofence())
.build();
if (!googleApiClient.isConnected()) {
Log.d(TAG, "Google API client not connected");
} else {
try {
LocationServices.GeofencingApi.addGeofences(googleApiClient, geofencingRequest, pendingIntent).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
if (status.isSuccess()) {
Log.d(TAG, "Successfully Geofencing Connected");
} else {
Log.d(TAG, "Failed to add Geofencing " + status.getStatus());
}
}
});
} catch (SecurityException e) {
Log.d(TAG, e.getMessage());
}
}
isMonitoring = true;
invalidateOptionsMenu();
}
#NonNull
public Geofence getGeofence() {
LatLng latLng = Constants.AREA_LANDMARKS.get(Constants.GEOFENCE_ID_STAN_UNI);
return new Geofence.Builder()
.setRequestId(Constants.GEOFENCE_ID_STAN_UNI)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setCircularRegion(latLng.latitude, latLng.longitude, Constants.GEOFENCE_RADIUS_IN_METERS)
.setNotificationResponsiveness(1000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
.build();
}
public PendingIntent getGeofencePendingIntent() {
if (pendingIntent != null) {
return pendingIntent;
}
Intent intent = new Intent(this, GeofenceRegistrationService.class);
return PendingIntent.getService(this, 0, intent, PendingIntent.
FLAG_UPDATE_CURRENT);
}
private void stopGeoFencing() {
pendingIntent = getGeofencePendingIntent();
LocationServices.GeofencingApi.removeGeofences(googleApiClient, pendingIntent)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
if (status.isSuccess())
Log.d(TAG, "Stop geofencing");
else
Log.d(TAG, "Not stop geofencing");
}
});
isMonitoring = false;
invalidateOptionsMenu();
}
#Override
protected void onResume() {
super.onResume();
int response = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(MainActivity.this);
if (response != ConnectionResult.SUCCESS) {
Log.d(TAG, "Google Play Service Not Available");
GoogleApiAvailability.getInstance().getErrorDialog(MainActivity.this, response, 1).show();
} else {
Log.d(TAG, "Google play service available");
}
}
#Override
protected void onStart() {
super.onStart();
googleApiClient.reconnect();
}
#Override
protected void onStop() {
super.onStop();
googleApiClient.disconnect();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.manu_map_activity, menu);
if (isMonitoring) {
menu.findItem(R.id.action_start_monitor).setVisible(false);
menu.findItem(R.id.action_stop_monitor).setVisible(true);
menu.findItem(R.id.startservice).setVisible(true);
} else {
menu.findItem(R.id.action_start_monitor).setVisible(true);
menu.findItem(R.id.action_stop_monitor).setVisible(false);
}
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_start_monitor:
startGeofencing();
break;
case R.id.action_stop_monitor:
stopGeoFencing();
break;
case R.id.startservice:
startService(new Intent(this, BackgroundService.class));
break;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onDestroy() {
super.onDestroy();
}
#Override
public void onMapReady(GoogleMap googleMap) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
this.googleMap = googleMap;
LatLng latLng = Constants.AREA_LANDMARKS.get(Constants.GEOFENCE_ID_STAN_UNI);
googleMap.addMarker(new MarkerOptions().position(latLng).title("Stanford University"));
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 17f));
googleMap.setMyLocationEnabled(true);
Circle circle = googleMap.addCircle(new CircleOptions()
.center(new LatLng(latLng.latitude, latLng.longitude))
.radius(Constants.GEOFENCE_RADIUS_IN_METERS)
.strokeColor(Color.RED)
.strokeWidth(4f));
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.d(TAG, "Google Api Client Connected");
isMonitoring = true;
startGeofencing();
startLocationMonitor();
}
#Override
public void onConnectionSuspended(int i) {
Log.d(TAG, "Google Connection Suspended");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
isMonitoring = false;
Log.e(TAG, "Connection Failed:" + connectionResult.getErrorMessage());
}
}
When I try to run the app in background by clicking the background option i have provided in the app, the app crashes and i get a runtime error saying:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.app.androidkt.geofencing, PID: 24176
java.lang.RuntimeException: Unable to start service com.app.androidkt.geofencing.BackgroundService#52135c5 with Intent { cmp=com.app.androidkt.geofencing/.BackgroundService }: java.lang.NullPointerException: Attempt to write to field 'boolean com.app.androidkt.geofencing.MainActivity.isMonitoring' on a null object reference
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3335)
at android.app.ActivityThread.-wrap21(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1578)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
Caused by: java.lang.NullPointerException: Attempt to write to field 'boolean com.app.androidkt.geofencing.MainActivity.isMonitoring' on a null object reference
at com.app.androidkt.geofencing.BackgroundService.onStartCommand(BackgroundService.java:13)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3318)
at android.app.ActivityThread.-wrap21(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1578)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
Please suggest me changes in my code.
MainActivity main;
is not initialized in your BackgroundService.
Try to implement the interface instead accessing the Activity's method like this.
Check this answer to implement the interface.
Related
This code is not storing latitude and longitude in firebase realtime database please help me I got stuck in between onlocationchanged method latitude and longitude showing in toast but not storing latitude and longitude in firebase realtime database please help me
firebase Database JAVA
package com.track_location.tracking_system;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.FragmentActivity;
import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionDeniedResponse;
import com.karumi.dexter.listener.PermissionGrantedResponse;
import com.karumi.dexter.listener.single.PermissionListener;
public class MapsActivity2 extends FragmentActivity implements OnMapReadyCallback,GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
com.google.android.gms.location.LocationListener {
DatabaseReference reference;
Button btn;
private GoogleMap mMap;
private GoogleApiClient mGoogleApiClient;
private Location mLocation;
private LocationManager mLocationManager;
private LocationRequest mLocationRequest;
private com.google.android.gms.location.LocationListener listener;
private long UPDATE_INTERVAL = 2000;
private long FASTEST_INTERVAL = 5000;
private LocationManager locationManager;
private LatLng latLng;
private boolean isPermission;
private FirebaseUser user;
private FirebaseAuth auth;
String userid,u1,cust,nm;
DatabaseReference ref;
double latitude;
double longitude;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps2);
Intent intent=getIntent();
nm=intent.getStringExtra("userid");
btn=(Button)findViewById(R.id.enable_btn);
auth=FirebaseAuth.getInstance();
user=auth.getCurrentUser();
reference= FirebaseDatabase.getInstance().getReference().child("User");
ref=reference.child(nm);
if(requestSinglePermission()){
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
checkLocation();
}
}
private boolean checkLocation() {
if(!isLocationEnabled()){
showAlert();
}
return isLocationEnabled();
}
private void showAlert() {
final AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setTitle("Enable Location")
.setMessage("Your Locations Settings is set to 'Off'.\nPlease Enable Location to " +
"use this app")
.setPositiveButton("Location Settings", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int paramInt) {
Intent myIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(myIntent);
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
}
});
dialog.show();
}
private boolean isLocationEnabled() {
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) ||
locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
private boolean requestSinglePermission() {
Dexter.withActivity(this)
.withPermission(Manifest.permission.ACCESS_FINE_LOCATION)
.withListener(new PermissionListener() {
#Override
public void onPermissionGranted(PermissionGrantedResponse response) {
isPermission = true;
}
#Override
public void onPermissionDenied(PermissionDeniedResponse response) {
// check for permanent denial of permission
if (response.isPermanentlyDenied()) {
isPermission = false;
}
}
#Override
public void onPermissionRationaleShouldBeShown(com.karumi.dexter.listener.PermissionRequest permission, PermissionToken token) {
}
}).check();
return isPermission;
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
if(latLng!=null){
mMap.addMarker(new MarkerOptions().position(latLng).title("Marker in Current Location"));
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng,14F));
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {
return;
}
startLocationUpdates();
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLocation == null) {
startLocationUpdates();
}
else {
Toast.makeText(this, "Location not Detected", Toast.LENGTH_SHORT).show();
}
}
private void startLocationUpdates() {
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void onLocationChanged(Location location) {
String msg = "Updated Location: " +
Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
Toast.makeText(this, msg+nm, Toast.LENGTH_SHORT).show();
latitude=location.getLatitude();
longitude=location.getLongitude();
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ref.child("Latitude").push().setValue(latitude);
//Toast.makeText(getApplicationContext(),"Latitude : "+latitude,Toast.LENGTH_LONG).show();
ref.child("Longitude").push().setValue(longitude);
}
});
latLng = new LatLng(location.getLatitude(), location.getLongitude());
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
protected void onStart() {
super.onStart();
if(mGoogleApiClient !=null){
mGoogleApiClient.connect();
}
}
#Override
protected void onStop() {
super.onStop();
if(mGoogleApiClient.isConnected()){
mGoogleApiClient.disconnect();
}
}
}
In your current code, the current location is only updated when you click the "enable button".
However, in that code, you are adding a new OnClickListener to that button every time the location is updated. Instead you should define the OnClickListener to publish the current value of latLng (which in the code below I renamed to mLatLng to follow conventions).
// Firebase services
private FirebaseAuth mAuth;
private FirebaseDatabase mDatabase;
// Firebase objects
private FirebaseUser mUser;
private DatabaseReference mUserRef;
// Java objects
private SupportMapFragment mMapFragment;
private LatLng mLatLng;
private String mUserId;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps2);
Intent intent = getIntent();
mUserId = intent.getStringExtra("userid");
mAuth = FirebaseAuth.getInstance();
mUser = mAuth.getCurrentUser(); // unused?
mDatabase = FirebaseDatabase.getInstance();
mUserRef = mDatabase.child("User").child(mUserId);
if(requestSinglePermission()){
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
mMapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mMapFragment.getMapAsync(this);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
checkLocation();
}
final MapsActivity2 self = this;
Button btnEnable = (Button) findViewById(R.id.enable_btn);
btnEnable.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// On click, saves last location to Firebase RTDB
long latitude = self.mLatLng.getLatitude();
long longitude = self.mLatLng.getLongitude();
String pushId = mUserRef.push().getKey();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/Latitude/" + pushId, latitude);
childUpdates.put("/Longitude/" + pushId, longitude);
mUserRef.updateChildren(childUpdates)
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "btnEnable#onClick:onFailure", databaseError.toException());
}
});
}
});
}
#Override
public void onLocationChanged(Location location) {
String msg = "Updated Location: " +
Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
Toast.makeText(this, msg+userId, Toast.LENGTH_SHORT).show();
this.mLatLng = new LatLng(location.getLatitude(), location.getLongitude());
this.mMapFragment.getMapAsync(this);
}
If you wanted to save the current location to the database on every update to the location, you would use:
#Override
public void onLocationChanged(Location location) {
long latitude = location.getLatitude();
long longitude = location.getLongitude();
String msg = "Updated Location: " +
Double.toString(latitude) + "," +
Double.toString(longitude);
Toast.makeText(this, msg+userId, Toast.LENGTH_SHORT).show();
this.mLatLng = new LatLng(latitude, longitude);
String pushId = mUserRef.push().getKey();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/Latitude/" + pushId, latitude);
childUpdates.put("/Longitude/" + pushId, longitude);
mUserRef.updateChildren(childUpdates)
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "onLocationChanged:onFailure", databaseError.toException());
}
});
this.mMapFragment.getMapAsync(this);
}
I would like to retrieve the device position each time the user moves but the onLocationChanged callback does not work. could someone please help me? here is my code of my activity that manages the google map. Please note, I'm using the onLocationChanged from the Google Library com.google.android.gms.location.LocationListener
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.location.LocationManager;
import android.os.AsyncTask;
import android.os.Build;
import android.annotation.TargetApi;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.firebase.geofire.GeoFire;
import com.firebase.geofire.GeoLocation;
import com.firebase.geofire.LocationCallback;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.proper_international.properinternationnal.R;
import com.proper_international.properinternationnal.activity.customer.BookingProviderActivity;
import com.proper_international.properinternationnal.activity.menus.HamburgerMenuProviderActivity;
import com.proper_international.properinternationnal.entities.Nettoyeur;
import com.proper_international.properinternationnal.miscs.UserEnum;
import com.proper_international.properinternationnal.miscs.Utilities;
import com.proper_international.properinternationnal.services.ActionAPIService;
import com.proper_international.properinternationnal.services.FCMNotificationService;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutionException;
public class ProviderToCustomerMapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener {
private GoogleMap mMap;
private Button btnAccept, btnDecline;
FusedLocationProviderClient mFusedLocationClient;
SharedPreferences sharedpreferences;
String latLong, idReserve, from, login;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
LocationRequest mLocationRequest;
Marker mCurrLocationMarker;
private LatLng equipierPosition;
private LocationManager locationManager;
static int MY_REQUEST_CODE = 225;
private String provider_info;
boolean isGPSEnabled, isNetworkEnabled;
// The minimum distance to change updates in meters
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
// The minimum time between updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1; // 1 minute
#TargetApi(Build.VERSION_CODES.M)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!isGooglePlayServicesAvailable()) {
finish();
}
setContentView(R.layout.activity_provider_to_customer_maps);
btnAccept = (Button) findViewById(R.id.btnAccept);
btnDecline = (Button) findViewById(R.id.btnDecline);
sharedpreferences = getSharedPreferences(Utilities.MY_PREFERENCE, Context.MODE_PRIVATE);
if (getIntent() != null) {
latLong = getIntent().getStringExtra("latLng");
idReserve = getIntent().getStringExtra("idReserve");
from = getIntent().getStringExtra("from");
login = getIntent().getStringExtra("login");
}
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
//getting network status
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
runOnClick();
if (!sharedpreferences.getString(Utilities.EXTRA_ROLE, "").equals(UserEnum.Provider.toString())) {
btnDecline.setVisibility(View.INVISIBLE);
btnAccept.setText("Consulter son profile.");
}
btnDecline.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
String result = new declinerReservation().execute().get();
if (result.equals("true"))
Toast.makeText(ProviderToCustomerMapsActivity.this, "Merci!", Toast.LENGTH_LONG).show();
finish();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
});
btnAccept.setOnClickListener(new View.OnClickListener() {
#SuppressLint("MissingPermission")
#TargetApi(Build.VERSION_CODES.M)
#Override
public void onClick(View v) {
if (!sharedpreferences.getString(Utilities.EXTRA_ROLE, "").equals(UserEnum.Customer.toString())) {
try {
String result = new assignerReservation().execute().get();
if (result.equals("true")) {
String latLng = mLastLocation.getLatitude() + "," + mLastLocation.getLongitude();
String title = "Reservation A.";
String body = "Un Eest prêt à vous R.";
//Notification PUSH
boolean notSend = false;
while (notSend == false) {
notSend = new FCMNotificationService().execute(from, title, body, latLng, idReserve, sharedpreferences.getString(Utilities.EXTRA_LOGIN, "")).get();
}
startActivity(new Intent(ProviderToCustomerMapsActivity.this, HamburgerMenuProviderActivity.class));
finish();
} else {
Toast.makeText(ProviderToCustomerMapsActivity.this, "Dommage! Un autre Ea décroché cette O.", Toast.LENGTH_LONG).show();
finish();
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
} else {
Intent intent = new Intent(ProviderToCustomerMapsActivity.this, BookingProviderActivity.class);
String[] chaine = idReserve.split(",");
intent.putExtra("idReserver", chaine[0]);
intent.putExtra("login", chaine[1]);
startActivity(intent);
}
}
});
}
#TargetApi(Build.VERSION_CODES.M)
public void runOnClick() {
// mGoogleApiClient = this;
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
if (ActivityCompat.checkSelfPermission(ProviderToCustomerMapsActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(ProviderToCustomerMapsActivity.this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
} else {
// do request the permission
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_REQUEST_CODE);
}
}
if (ActivityCompat.checkSelfPermission(ProviderToCustomerMapsActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(ProviderToCustomerMapsActivity.this,
Manifest.permission.ACCESS_COARSE_LOCATION)) {
} else {
// do request the permission
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, MY_REQUEST_CODE);
}
}
mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
// Last known location. In some rare situations, it can be null.
if (location != null) {
// Logique pour gérer l'objet d'emplacement
mLastLocation = location;
}
}
});
mFusedLocationClient.getLastLocation().addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception ex) {
Log.e("getLastLocation", "onFailure: "+ex.getMessage());
}
}
);
}
private boolean isGooglePlayServicesAvailable() {
int status = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this);
if (ConnectionResult.SUCCESS == status) {
return true;
} else {
GoogleApiAvailability.getInstance().getErrorDialog(this, status, 0).show();
return false;
}
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
#TargetApi(Build.VERSION_CODES.M)
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
} else {
// do request the permission
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_REQUEST_CODE);
}
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_COARSE_LOCATION)) {
} else {
// do request the permission
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, MY_REQUEST_CODE);
}
}
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
if (sharedpreferences.getString(Utilities.EXTRA_ROLE, "").equals(UserEnum.Customer.toString())) {
btnAccept.setText("Ma liste de R");
btnAccept.setVisibility(View.INVISIBLE);
//String userId = FirebaseAuth.getInstance().getCurrentUser().getUid();
String userId = login;
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("EDisponible");
GeoFire geoFire = new GeoFire(ref);
geoFire.setLocation(userId.replaceAll(".", "_"), new GeoLocation(mLastLocation.getLatitude(), mLastLocation.getLongitude()));
String[] ll = latLong.split(",");
double latitude = Double.parseDouble(ll[0]);
double longitude = Double.parseDouble(ll[1]);
equipierPosition = new LatLng(latitude, longitude);
mMap.addMarker(new MarkerOptions().position(equipierPosition).title("Position de l'e."));
geoFire.getLocation(userId.replaceAll(".", "_"), new LocationCallback() {
#Override
public void onLocationResult(String key, GeoLocation location) {
if (location != null) {
System.out.println(String.format("L'emplacement de la clé %s est [%f,%f]", key, location.latitude, location.longitude));
equipierPosition = new LatLng(location.latitude, location.longitude);
mMap.addMarker(new MarkerOptions().position(equipierPosition).title("Position de l'équipier."));
} else {
Log.d("Pas d'emplacement", String.format("Il n'y a pas d'emplacement pour la clé %s dans GeoFire", key));
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d("Erreur produite", "Une erreur s'est produite lors de l'obtention de l'emplacement GeoFire: " + databaseError);
}
});
} else {
String userIds = login;
DatabaseReference refs = FirebaseDatabase.getInstance().getReference("ClientDisponible");
String[] ll = latLong.split(",");
double latitude = Double.parseDouble(ll[0]);
double longitude = Double.parseDouble(ll[1]);
GeoFire geoFire = new GeoFire(refs);
geoFire.setLocation(userIds.replaceAll(".", "_"), new GeoLocation(latitude, longitude));
equipierPosition = new LatLng(latitude, longitude);
mMap.addMarker(new MarkerOptions().position(equipierPosition).title("Position 0."));
geoFire.getLocation(userIds.replaceAll(".", "_"), new LocationCallback() {
#Override
public void onLocationResult(String key, GeoLocation location) {
if (location != null) {
System.out.println(String.format("L'emplacement de la clé %s est [%f,%f]", key, location.latitude, location.longitude));
equipierPosition = new LatLng(location.latitude, location.longitude);
mMap.addMarker(new MarkerOptions().position(equipierPosition).title("Position 1."));
} else {
Log.d("Pas d'emplacement", String.format("Il n'y a pas d'emplacement pour la clé %s dans GeoFire:" + key));
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d("Erreur obtention", databaseError.getMessage());
}
});
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == MY_REQUEST_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Now user should be able to use camera
} else {
// Your app will not have this permission. Turn off all functions
// that require this permission or it will force close like your
// original question
}
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
mGoogleApiClient.connect();
}
#Override
public void onPause() {
super.onPause();
//stop location updates when Activity is no longer active
if (mFusedLocationClient != null) {
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
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;
}
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
// LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
com.google.android.gms.location.LocationCallback mLocationCallback = new com.google.android.gms.location.LocationCallback(){
#Override
public void onLocationResult(LocationResult locationResult) {
for (Location location : locationResult.getLocations()) {
Log.i("MapsActivity", "Location: " + location.getLatitude() + " " + location.getLongitude());
mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
//Place current location marker
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title("Position actuelle");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
mCurrLocationMarker = mMap.addMarker(markerOptions);
//move map camera
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 11));
}
};
};
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void onResume() {
super.onResume();
runOnClick();
}
#Override
public void onLocationChanged(Location location) {
mLastLocation = location;
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(11));
String userId = login;
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("EDisponible");
GeoFire geoFire = new GeoFire(ref);
geoFire.setLocation(userId.replaceAll(".","_"), new GeoLocation(location.getLatitude(), location.getLongitude()));
}
#Override
protected void onStop() {
super.onStop();
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if(user != null){
String userId = login.replaceAll(".","_");
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("EDisponible");
if (!sharedpreferences.getString(Utilities.EXTRA_ROLE, "").equals(UserEnum.Customer.toString()))
ref = FirebaseDatabase.getInstance().getReference("ClientDisponible");
GeoFire geoFire = new GeoFire(ref);
geoFire.removeLocation(userId);
}
}
}
I was able to solve my problem by adding this line of code in the onConnected method:
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
I had not used LocationServices because FusedLocationApi is deprecated.
I am trying to get users current location using FusedLocationApi using the following code. I am following the guide provided here: https://developer.android.com/training/location/retrieve-current.html
I have tried this so far:
package com.abhishek.locationawareapp;
import android.Manifest;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
LocationRequest mLocationRequest;
protected void createLocationRequest(){
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("Main Activity: ","onCreate");
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();//.addApi(LocationServices.class)
}
//For Location Request
/*LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);*/
}
#Override
protected void onStart() {
mGoogleApiClient.connect();
Log.d("Main Activity: ","onStart");
super.onStart();
}
#Override
protected void onStop() {
Log.d("Main Activity: ","onStop");
mGoogleApiClient.disconnect();
super.onStop();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.d("Main Activity: ","onConnected");
if(Build.VERSION.SDK_INT >=23){
checkLocationPermission();
}else{
locationPermission = true;
Location mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if(mLastLocation !=null){
String mLatitudeText = String.valueOf(mLastLocation.getLatitude());
String mLongitudeText = String.valueOf(mLastLocation.getLongitude());
Log.d("Location: ","mLatitudeText: "+ mLatitudeText +" mLongitudeText: "+ mLongitudeText);
}
}
}
boolean locationPermission = false;
final static int LOC_REQ_CODE = 100;
private void checkLocationPermission(){
int locationPermissionCheck = ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION);
if(locationPermissionCheck == PackageManager.PERMISSION_GRANTED){
locationPermission = true;
Location mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if(mLastLocation !=null){
String mLatitudeText = String.valueOf(mLastLocation.getLatitude());
String mLongitudeText = String.valueOf(mLastLocation.getLongitude());
Log.d("Location: ","mLatitudeText: "+ mLatitudeText +" mLongitudeText: "+ mLongitudeText);
}
}else{
locationPermission = false;
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
LOC_REQ_CODE);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case LOC_REQ_CODE:
if(grantResults.length>0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
locationPermission = true;
Location mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if(mLastLocation !=null){
String mLatitudeText = String.valueOf(mLastLocation.getLatitude());
String mLongitudeText = String.valueOf(mLastLocation.getLongitude());
Log.d("Location: ","mLatitudeText: "+ mLatitudeText +" mLongitudeText: "+ mLongitudeText);
}
}else{
final Snackbar snackBar = Snackbar.make(findViewById(R.id.rl_layout), "Location access is required to get last location.",
Snackbar.LENGTH_INDEFINITE);
snackBar.setAction("Dismiss", new View.OnClickListener() {
#Override
public void onClick(View v) {
checkLocationPermission();
snackBar.dismiss();
}
});
snackBar.show();
}
break;
}
}
#Override
public void onConnectionSuspended(int i) {
Log.d("Main Activity: ","onConnectionSuspended");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.d("Main Activity: ","onConnectionFailed");
}
}
I got the location with gps enabled but once i disable gps, mLastLocation
always returns null. Isn't it possible to get location from FusedLocationApi without using Gps? Please help!!
I've searched for days and days and somehow the answer to why onLocationChanged isn't being called has eluded me. I've read the documentation extensively and I MUST be missing something crucial. I simply want a service that runs in the background, when location has changed, I want to log the location.
Here's my service...
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.support.annotation.Nullable;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
public class BackgroundLocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private final String TAG = ((Object) this).getClass().getSimpleName();
IBinder mBinder = new LocalBinder();
GoogleApiAvailability googleAPI;
PowerManager.WakeLock mWakeLock;
private boolean mInProgress;
private Boolean servicesAvailable = false;
protected GoogleApiClient mGoogleApiClient;
protected LocationRequest mLocationRequest;
private Intent mIntentService;
private PendingIntent mPendingIntent;
public class LocalBinder extends Binder {
public BackgroundLocationService getServerInstance() {
return BackgroundLocationService.this;
}
}
#Override
public void onCreate() {
super.onCreate();
googleAPI = GoogleApiAvailability.getInstance();
mInProgress = false;
mIntentService = new Intent(this,BackgroundLocationService.class);
mPendingIntent = PendingIntent.getService(this, 1, mIntentService, PendingIntent.FLAG_UPDATE_CURRENT);
servicesAvailable = servicesConnected();
/*
* Create a new google api client, using the enclosing class to handle callbacks.
*/
buildGoogleApiClient();
}
private boolean servicesConnected() {
// Check that Google Play services is available
int resultCode = googleAPI.isGooglePlayServicesAvailable(this);
// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode) {
return true;
} else {
return false;
}
}
protected void startLocationUpdates() {
Log.i(TAG, "Started Location Updates");
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mPendingIntent);
}
protected void stopLocationUpdates() {
Log.i(TAG,"Stopped Location Updates");
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, mPendingIntent);
}
protected void createLocationRequest() {
Log.i(TAG, "createLocationRequest()");
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);
mLocationRequest.setFastestInterval(1000);
//mLocationRequest.setMaxWaitTime(10000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
PowerManager mgr = (PowerManager) getSystemService(Context.POWER_SERVICE); //*** added this
if (this.mWakeLock == null) {
mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "aWakeLock"); //*** added this
}
if (!this.mWakeLock.isHeld()) {
mWakeLock.acquire(); //*** added this
}
if (!servicesAvailable || mGoogleApiClient.isConnected() || mInProgress)
return START_STICKY;
if (!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress) {
Log.e(TAG, "Location Client not connected, connecting...");
mInProgress = true;
mGoogleApiClient.connect();
}
Log.e(TAG, "Location Client: onStartCommand");
return START_STICKY;
}
protected synchronized void buildGoogleApiClient() {
Log.i(TAG, "Building GoogleApiClient");
if (mGoogleApiClient == null) {
this.mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
createLocationRequest();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onDestroy() {
// Turn off the request flag
this.mInProgress = false;
if (this.mWakeLock != null) {
this.mWakeLock.release();
this.mWakeLock = null;
}
Log.e(TAG, "Location Client: ON DESTROY");
super.onDestroy();
stopLocationUpdates();
}
#Override
public void onConnected(Bundle bundle) {
startLocationUpdates();
}
#Override
public void onLocationChanged(Location location) {
Log.e(TAG, "Location Receiver [Location Changed]: " + location.getLatitude() + ", " + location.getLongitude());
}
#Override
public void onConnectionSuspended(int i) {
Log.e(TAG, "Location Client: ON CONNECTED");
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
mInProgress = false;
Log.e(TAG, "Location Client: ON CONNECTION FAILED");
if (connectionResult.hasResolution()) {
// If no resolution is available, display an error dialog
} else {
}
}
}
I'm starting the service like this...
Intent BackgroundLocationService = new Intent(this, BackgroundLocationService.class);
startService(BackgroundLocationService);
I have the following permission in the manifest as well...
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
The requestLocationUpdates uses a pendingintent currently which is fired to start the service again. This is not calling the OnLocationchanged callback. Try using the requestLocationUpdates with location listener (3rd parameter). It should call OnLocationchanged.
So i have this code:
package com.entu.bocterapp;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
public class LocationManager implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private Context mContext;
private GoogleApiClient mGoogleApiClient;
private Location mLastLocation;
private LocationRequest mLocationRequest;
public LocationManager(Context context) {
mContext = context;
//
if (checkIfGooglePlayServicesAreAvailable()) {
//Get Access to the google service api
buildGoogleApiClient();
mGoogleApiClient.connect();
} else {
//Use Android Location Services
//TODO:
}
}
public Location getCoarseLocation() {
if (mLastLocation != null) {
return mLastLocation;
} else return null;
}
private synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
private boolean checkIfGooglePlayServicesAreAvailable() {
int errorCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(mContext);
if (errorCode != ConnectionResult.SUCCESS) {
GooglePlayServicesUtil.getErrorDialog(errorCode, (RecentSightings) mContext, 0).show();
return false;
}
return true;
}
#Override
public void onConnected(Bundle bundle) {
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location != null) {
mLastLocation = location;
Toast.makeText(mContext, location.getLongitude() + " , " + location.getLatitude() + " : " + location.getAccuracy(), Toast.LENGTH_LONG).show();
}
}
#Override
public void onConnectionSuspended(int i) {
Toast.makeText(mContext, "suspended", Toast.LENGTH_LONG).show();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
}
I am trying to get location in this class, but onConnected() never gets called(i waited for 1-2 minutes). I went with the debugger, it says google play services are available.
Does anyone know what i'm doing wrong? I'm stuck here for hours, reading everything, and can't get it to work.
Cheers!
You must call
mGoogleApiClient.connect();
try this:
#Override
protected void onStart() {
if(mGoogleApiClient!=null){
mGoogleApiClient.connect();
}
super.onStart();
}
#Override
protected void onStop() {
if(mGoogleApiClient!=null){
if(mGoogleApiClient.isConnected()){
mGoogleApiClient.disconnect();
}
}
super.onStop();
}
I got the same problem just updated my grade version :10.0.1' to
compile 'com.google.android.gms:play-services-location:10.2.1'
it works.