I'm trying to implement abstract Activity, whose inheritants would be able to get Location data. I'm strictly following this guide, that seems pretty straightforward.
But after all I have a few problems. Google API should pass location data even if GPS is off, getting this from network data or even passive data from other apps. But in my case it works only with GPS enabled.
Another question is what happens when I turn GPS off/on. In my case after that I can't het any data at all.
Here's the class that makes everything done.
public abstract class LocationProviderActivity extends BaseDrawerActivity
implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private final String TAG = "LOCATION";
GoogleApiClient client;
protected Location location;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (client == null) {
client = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
#Override
protected void onStart() {
client.connect();
Log.i(TAG, "Connected");
super.onStart();
}
#Override
protected void onStop() {
client.disconnect();
Log.i(TAG, "Disconnected");
super.onStop();
}
#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) {
//TODO
return;
}
location = LocationServices.FusedLocationApi.getLastLocation(client);
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Location services connected.");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.i(TAG, "Location services suspended. Please reconnect.");
}
#Override
public void onLocationChanged(Location location) {
}
}
Related
I'm trying to use FusedLocation API in a Background service. I'm getting error on :-
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleAPIClient, mLocationRequest, this);
asking me to cast the 3rd parameter into (cast to com.google.android.gms.location.LocationListener).
I tried to do so and App crashed.I don't have any Idea why this happening or asking to to cast.
full code for the service class is as below:-
public class LocationBgService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleApiClient mGoogleAPIClient;
private LocationRequest mLocationRequest;
private FusedLocationProviderApi mLocationProvider;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
mGoogleAPIClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mLocationProvider = LocationServices.FusedLocationApi;
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(60000);
mLocationRequest.setFastestInterval(15000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mGoogleAPIClient.connect();
return START_STICKY;
}
#Override
public void onConnected(#Nullable Bundle bundle) {
RequestLocationUpdates();
}
private void RequestLocationUpdates() {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleAPIClient, mLocationRequest, this); //getting error here..for casting..!
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void onLocationChanged(Location location) {
Log.d("Background Location ", "::::***********Latitude: " + location.getLatitude() + " Longitude: " + location.getLongitude());
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
}
I searched and found many people are using this same line of code,so why I'm getting this error.
Did I missed something to do or what? please help me with this.Thanks in advance.
You're probably using the older form of the LocationListener. It looks like you're using the one intended for LocationManager rather than the newer LocationServices API.
In your import statements, change
import android.location.LocationListener;
To this
import com.google.android.gms.location.LocationListener;
You'll need to remove the 3 methods at the bottom. They're not used in the newer LocationListener. Also, you may need to clean & do a complete rebuild. Using the new import statement, your code works for me.
I'm trying my hand at making a background service that I'd like to run when the app is closed and terminate when the app is open.
as you can see in the code below, I have a Toast message that is supposed that is supposed to display in onLocationChanged(). I am only seeing that message appear once.
Here is what the permission looks like in the manifest:
<application
...
<activity android:name=".activities.ChatUsersActivity" />
<activity android:name=".activities.RequestsActivity"></activity>
<service android:name=".pops.PopService"
android:exported="false"
android:icon="#drawable/usericonmdpi"/>
</application>
And also, here is my Service extended class:
public class PopService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(2);
Runnable backgroundCollector = new BackgroundPopCollector();
private GoogleApiClient mGoogleApiClient;
LocationRequest mLocationRequest;
Location mLastLocation;
private PopCityCollection cities;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
// Code to execute when the service is first created
super.onCreate();
buildGoogleApiClient();
}
#Override
public void onDestroy() {
super.onDestroy();
threadPoolExecutor.shutdownNow();
}
#Override
public void onLocationChanged(Location location) {
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
UserLocation.setLatitude(location.getLatitude());
UserLocation.setLongitude(location.getLongitude());
Toast.makeText(getBaseContext(), "Latitude is " + location.getLatitude(), Toast.LENGTH_SHORT).show();
System.out.println(UserLocation.getLatitude()+", "+UserLocation.getLongitude()+" --->BACKGROUND!!");
if(cities==null) {
cities = new PopCityCollection(new LatLng(location.getLatitude(), location.getLongitude()));
cities.findMyCity(this);
}
DatabaseReference db = FirebaseDatabase.getInstance().getReference().child("pops");
db.push().setValue("test");
}
#Override
public void onConnected(#Nullable Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(100);
mLocationRequest.setFastestInterval(100);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
if (ContextCompat.checkSelfPermission(this,
android.Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(getApplicationContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId){
threadPoolExecutor.scheduleAtFixedRate(backgroundCollector, 0, 10, TimeUnit.SECONDS);
return START_NOT_STICKY;
}
}
Thank you for any insights you can provide!
-T
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
the above condition will remove the location updates , after first time so remove this code
removeLocationUpdates
Removes all location updates for the given location listener.
My Activity is like this:
public class MainMap extends FragmentActivity implements OnMarkerClickListener, OnMapReadyCallback,
ConnectionCallbacks, OnConnectionFailedListener, LocationListener, ActivityCompat.OnRequestPermissionsResultCallback {
private static final int REQUEST_ACCESS_FINE_LOCATION = 0;
protected GoogleApiClient mGoogleApiClient;
protected Location mCurrentLocation;
protected LocationRequest mLocationRequest;
// ...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(NativeLib.get_location_update_interval_in_mil());
mLocationRequest.setFastestInterval(NativeLib.get_location_fastest_update_interval_in_mil());
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
#Override
protected void onStart() {
if (debug_mode) { Log.i(TAG, "onStart");}
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
if (debug_mode) { Log.i(TAG, "onStop");}
super.onStop();
mGoogleApiClient.disconnect();
}
#Override
public void onConnected(Bundle connectionHint) {
if (debug_mode) { Log.i(TAG, "onConnected");}
// permissions
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
request_fine_location_permission();
}
// location
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
#Override
public void onLocationChanged(Location location) {
// CALL either do_background or do_foreground
}
private void do_background() {
// DO WORK
}
private void do_foreground() {
// DO WORK
}
}
The code works just fine in the foreground - what I want to do is to make sure that location is constantly tracked (even when the app is in the background or the phone is in sleep mode) and launch the appropriate function in my Activity.
I have this app where I need to get a single coarse location (I'm only requesting for android.permission.ACCESS_COARSE_LOCATION) as quickly as possible before starting showing anything (besides a splash screen) to the user.
For some reason(s) my code is not working in some use cases where it needs to request for a location update (if it can't find a last know location).
If Location Services were disabled recently and I enable them back and then launch my app, it might take a lot of time (or not) to get a location fix and it might never happen. In this situation, I usually have to disable the Location Services and enable them back with the quick switch button from the notifications dropdown with the app in the foreground. And it's not immediate either, it takes a few seconds.
Another similar case is where the Location Services are disabled, I open the app and can't get a fix. I open the device settings (placing the app in the background), re-enable Location Services and bring the app back to the foreground. It takes a lot of time to get a location fix sometimes.
Honestly, it's complicated for me to describe the use cases where it usually takes a lot of time to get a fix on location. I've tried many things, constantly disabling/enabling Location services, with the app opened/closed, on the foreground/background. Many things, it just doesn't work consistently.
And given the nature of my app, I really need to get a single location fix as quickly as possible. And since I don't need a precise location (a really rough estimate is fine), I don't understand why it takes so long...
Sorry for the long post, here's my current code:
// BaseActivityLifecycleCallbacks extends Application.ActivityLifecycleCallbacks with default blank methods
public class MyLocation extends BaseActivityLifecycleCallbacks implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
private static final int LOCATION_REQUEST_INTERVAL = 1000; // 1 second
private static final int LOCATION_REQUEST_FASTEST_INTERVAL = 250; // 250 milliseconds
private static final int LOCATION_REQUEST_UPDATE_TIMEOUT = 15000; // 15 seconds
private final Handler mMainHandler;
private final Runnable mExpiredRunnable;
private final GoogleApiClient mGoogleApiClient;
private final LocationRequest mLocationRequest;
private LocationCallback mLocationCallback;
#DebugLog
public MyLocation(Context context) {
mMainHandler = new Handler(Looper.getMainLooper());
mExpiredRunnable = new Runnable() {
#DebugLog
#Override
public void run() {
handleNewOrEmptyLocation(null);
}
};
MyApplication.getInstance().registerActivityLifecycleCallbacks(this);
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
.setInterval(LOCATION_REQUEST_INTERVAL)
.setFastestInterval(LOCATION_REQUEST_FASTEST_INTERVAL);
}
public void requestFusedLocation(#NonNull LocationCallback callback) {
mLocationCallback = callback;
mGoogleApiClient.connect();
}
#DebugLog
#Override
public void onActivityResumed(Activity activity) {
super.onActivityResumed(activity);
if (activity instanceof MainActivity) {
if (!mGoogleApiClient.isConnected() && !mGoogleApiClient.isConnecting() && mLocationCallback != null) {
mGoogleApiClient.connect();
}
}
}
#DebugLog
#Override
public void onActivityPaused(Activity activity) {
super.onActivityPaused(activity);
if (activity instanceof MainActivity) {
if (mGoogleApiClient.isConnected()) {
mMainHandler.removeCallbacks(mExpiredRunnable);
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
}
}
#DebugLog
#Override
// I'm handling permission request some place else...
#SuppressWarnings("MissingPermission")
public void onConnected(#Nullable Bundle bundle) {
Location lastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (lastLocation != null) {
handleNewOrEmptyLocation(lastLocation);
return;
}
// I've disabled this for testing purposes. Sometimes the current 15s timeout is not enough to get a location fix...
//mMainHandler.postDelayed(mExpiredRunnable, LOCATION_REQUEST_UPDATE_TIMEOUT);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
#DebugLog
#Override
public void onLocationChanged(Location location) {
mMainHandler.removeCallbacks(mExpiredRunnable);
handleNewOrEmptyLocation(location);
}
#DebugLog
#Override
public void onConnectionSuspended(int i) {
// TODO: Is there something that needs to be done here?
Timber.e("onConnectionSuspended");
}
#DebugLog
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
// TODO: Is there something that needs to be done here?
Timber.e("onConnectionFailed");
}
#DebugLog
private void handleNewOrEmptyLocation(Location location) {
MyApplication.getInstance().unregisterActivityLifecycleCallbacks(this);
mGoogleApiClient.disconnect();
if (location != null) {
mLocationCallback.onLocationReceived(location);
} else {
mLocationCallback.onEmptyLocation();
}
}
public interface LocationCallback {
void onLocationReceived(Location location);
void onEmptyLocation();
}
}
And this is how it's currently being used:
public class MAinActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyLocation myLocation = new MyLocation(this);
myLocation.requestFusedLocation(new MyLocation.LocationCallback() {
#DebugLog
#Override
public void onLocationReceived(Location location) {
Toast.makeText(MainActivity.this, String.valueOf(location), Toast.LENGTH_SHORT).show();
}
#DebugLog
#Override
public void onEmptyLocation() {
Toast.makeText(MainActivity.this, "HUSTON, WE HAVE A PROBLEM!", Toast.LENGTH_SHORT).show();
finish();
}
});
}
}
To finish and as bonus question... In what circumstances are onConnectionSuspended and onConnectionFailed called? Should I handle these callbacks somehow?
I have following activity which uses GoogleApiClient:
public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener
{
private final String TAG = "My App";
private TextView textView;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v(TAG,"After layout setting");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
textView = (TextView) findViewById(R.id.location);
Log.v(TAG,"After mGoogleClient");
}
#Override
protected void onStart() {
Log.v(TAG,"On Start");
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
Log.v(TAG,"On Stop");
mGoogleApiClient.disconnect();
super.onStop();
}
#Override
public void onConnected(Bundle bundle) {
Log.v(TAG,"on Connected");
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(1000);
Log.v(TAG,"After Setting mLocationRequest");
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.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.
Log.v(TAG,"Checking block");
return;
}
Log.v(TAG,"After Checking block");
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
Log.v(TAG,"After Request Location Updates");
}
#Override
public void onConnectionSuspended(int i) {
Log.v(TAG,"Suspended");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.v(TAG,connectionResult.toString());
}
#Override
public void onLocationChanged(Location location) {
Log.v(TAG,location.toString());
textView.setText(location.toString());
}
}
After running this piece of code I get a message in logcat stating:
ConnectionResult{statusCode=SERVICE_VERSION_UPDATE_REQUIRED, resolution=null, message=null}
Which is due to execution of OnConnectionFailed function ..
How to resolve this problem?
You need to update your Google Play Services. Are you running your code in emulator? If so, try again with higher API level. This code works fine in real device.
It looks like the version of Google Play Services that you're building your app with is higher than the version you currently have installed on your test device, as previously answered here:
When does isGooglePlayServicesAvailable return SERVICE_VERSION_UPDATE_REQUIRED?