I'm trying to get the current GPS location of a phone inside a android service.
I try to do it like here:
Getting Repeated Current Location inside a Service in android?
My service looks like this:
public class MeasurementService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleApiClient mGoogleApiClient;
LocationRequest mLocationRequest;
private Feedback feedback;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mGoogleApiClient = new GoogleApiClient.Builder(getApplicationContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
feedback = new Feedback();
if (isNetworkAvailable()) {
new MeasuringTask().execute();
}
return Service.START_NOT_STICKY;
}
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager
.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
}
#Override
public void onConnected(Bundle arg0) {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(2000);
...
}
#Override
public void onConnectionSuspended(int arg0) {
}
#Override
public void onDestroy() {
super.onDestroy();
mGoogleApiClient.disconnect();
}
#Override
public void onLocationChanged(Location arg0) {
// TODO Auto-generated method stub
}
private class MeasuringTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
//network access
}
}
I start my service through a broadcast receiver everytime the phone is started.
When I execute the app I get a java.lang.NoClassDefFoundError: packet.MeasurementService
If I try to change this part:
mGoogleApiClient = new GoogleApiClient.Builder(getApplicationContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
To this:
mGoogleApiClient = new GoogleApiClient.Builder(getApplicationContext())
.addConnectionCallbacks(MeasurmentService.class)
.addOnConnectionFailedListener(MeasurmentService.class)
.addApi(LocationServices.API)
.build();
Like recommended in the other post, I get:
The method addConnectionCallbacks(GoogleApiClient.ConnectionCallbacks) in the type GoogleApiClient.Builder is not applicable for the arguments (Class)
Ideas? Thanks a lot!
Make sure the LocationListener your service implemented is from com.google.android.gms.location.
Move the code to onCreate function.
#Override
public void onCreate() {
mGoogleApiClient = new GoogleApiClient.Builder(getApplicationContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
I have a sample application on github, please click here.
I finally figured it out, it was a build error which I wasn't able to resolve.
My solution:
I migrated the project from Eclipse to Android Studio.
Related
I try connecting to the Google API Client to achieve some functionality in my application. But for some reason I cannot connect to the Google API Client And because that I can not continue to use Google services.
After I initialize the GoogleApiClient I check if mGoogleApiClient.isConnected and always get it False and I don't know why. I would appreciate any help. Thanks.
Notice that everything happens on background service.
public class Background extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status> {
private String TAG = "Background";
private GoogleApiClient mGoogleApiClient;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG,"Start");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(ActivityRecognition.API)
.addApi(LocationServices.API)
.build();
if (!mGoogleApiClient.isConnected()) {
Log.e(TAG,"GoogleApiClient not yet connected");
} else {
Log.e(TAG,"GoogleApiClient connected");
}
return Service.START_STICKY;
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.e(TAG, "Connection failed. Error: " + connectionResult.getErrorCode());
}
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.e(TAG, "Successfully added activity detection.");
} else {
Log.e(TAG, "Error: " + status.getStatusMessage());
}
}
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected");
mGoogleApiClient.connect();
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Connection suspended");
mGoogleApiClient.connect();
}
Connect the googleApiClient in onStartCommand of your service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG,"Start");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(ActivityRecognition.API)
.addApi(LocationServices.API)
.build();
if (!mGoogleApiClient.isConnected()) {
Log.e(TAG,"GoogleApiClient not yet connected");
mGoogleApiClient.connect(); // connect it here..
} else {
Log.e(TAG,"GoogleApiClient connected");
}
return Service.START_STICKY;
}
you are not calling .connect() in the right place. You are building a client, and you must call .connect() after that. You are immediately checking if it is connected, which it will never be.
Please add .connect() after .build() in .onStartCommand() and remove this code:
if (!mGoogleApiClient.isConnected()) {
Log.e(TAG,"GoogleApiClient not yet connected");
} else {
Log.e(TAG,"GoogleApiClient connected");
}
Also, remove this since it might get you in an unwanted state:
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected");
// remove this -> mGoogleApiClient.connect();
}
I want to discuss if there is possibility of getting real time current location update as we move, I tried with FusedLocationProviderClient to request for current location update every 2 minutes
What can we do to achieve this, implement detectActivity for walk and request current location update every 2 minutes or less in it?
or there is on location change listener thing in FusedLocationProviderClient? so that we can listen for if there is change in location and get latlng in real time and display in textview in application? the location change listener is available on GoogleMap object but isn't recommended to use now, am I right?
or should i stick to requestupdate of FusedLocationProviderClient?
Thanks beforehand
Also tell me if i move my phone from one room to another, will there be change in latlng?
You can use this class that i created :
public class LocationFetcher implements com.google.android.gms.location.LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
public GoogleApiClient googleApiClient;
Context context;
private LocationRequest locationRequest;
public LocationFetcher(Context context) {
this.context = context;
googleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
locationRequest = new LocationRequest();
}
public void connectGps() {
googleApiClient.connect();
}
public void requestLocationUpdate() {
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[]{Manifest.permission.ACCESS_FINE_LOCATION}, 100);
} else {
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
//Getting location every 3 seconds. You can change this.
locationRequest.setInterval(3000);
locationRequest.setFastestInterval(3000);
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
}
public boolean isConnected() {
return googleApiClient.isConnected();
}
#Override
public void onLocationChanged(Location location) {
//You will get location updates here.
}
#Override
public void onConnected(#Nullable Bundle bundle) {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
builder.setAlwaysShow(true);
PendingResult result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
if (result != null) {
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(LocationSettingsResult locationSettingsResult) {
final Status status = locationSettingsResult.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
requestLocationUpdate();
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
if (status.hasResolution()) {
status.startResolutionForResult((Activity) context, 1000);
}
} catch (IntentSender.SendIntentException e) {
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
break;
}
}
});
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
DialogPopup.getInstance().showLocationSettingsAlert(context);
}
public void removeLocationUpdates() {
if (googleApiClient.isConnected()){
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, this);
}
}
public void disconnectGps() {
googleApiClient.disconnect();
}
}
In onStart of your activity call this :
LocationFetcher locationFetcher = new LocationFetcher(this);
locationFetcher.connectGps();
And in onStop use this:
locationFetcher.disconnectGps();
You will get the location updates in the onLocationChangedMethod of the class.
You have to add this dependency too:
compile 'com.google.android.gms:play-services-location:10.2.1'
Hope this helps.
I have code which is working fine for logout of google apiclient, but it left one activity opened after execution, either can some one tell where should I put finish(); to kill that activity or how can I do whole thing in async task. I tried to do with async but got error as client not connected.
Here is code for logout with class extending to activity:
public class GoogleDriveLogoutBackup extends Activity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = "drive-quickstart";
private GoogleApiClient mGoogleApiClient;
#Override
protected void onStart() {
super.onStart();
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addScope(Drive.SCOPE_APPFOLDER)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
mGoogleApiClient.connect();
}
#Override
public void onConnected(Bundle connectionHint) {
Log.d("Connected","Here");
mGoogleApiClient.clearDefaultAccountAndReconnect();
finish();
}
#Override
public void onConnectionSuspended(int i) {
finish();
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
}
And here is code which I m using for Async class which I giving me error:
public class GoogleDriveLogout extends AsyncTask<Void, Void, Void> {
private static final String TAG = "drive-quickstart";
private GoogleApiClient mGoogleApiClient;
private Context mcontext;
public GoogleDriveLogout(Context context) {
this.mcontext = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(mcontext)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addScope(Drive.SCOPE_APPFOLDER)
.build();
}
mGoogleApiClient.connect();
}
#Override
protected Void doInBackground(Void... params) {
Log.d("Connected", "Here");
mGoogleApiClient.clearDefaultAccountAndReconnect();
return null;
}
}
I able to did it now by using calling ApiClientAsyncTask which is provided by google itself.
I've tried calling this Service in two different ways, but it didn't seem to work.
The first way was:
startService(new Intent(getBaseContext(), LocationService.class));
for which I get an error saying `
Caused by: `java.lang.IllegalStateException: GoogleApiClient is not connected yet.
Then I tried this:
Intent serviceIntent = new Intent();
serviceIntent.setAction("com.parseapp.eseen.eseen.service.LocationService");
startService(serviceIntent);
Also it didn't work, in contrary absolutely nothing happens, nothing shows up in logcat. Can anyone help?
Here's the whole code:
LocationService.class
public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
// LogCat tag
private static final String TAG = LocationService.class.getSimpleName();
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 1000;
private Location mLastLocation;
// Google client to interact with Google API
private GoogleApiClient mGoogleApiClient;
// boolean flag to toggle periodic location updates
private boolean mRequestingLocationUpdates = false;
private LocationRequest mLocationRequest;
// Location updates intervals in sec
private static int UPDATE_INTERVAL = 10000; // 10 sec
private static int FATEST_INTERVAL = 5000; // 5 sec
private static int DISPLACEMENT = 10; // 10 meters
#Override
public void onCreate() {
super.onCreate();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
togglePeriodicLocationUpdates();
}
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FATEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(DISPLACEMENT);
}
private void togglePeriodicLocationUpdates() {
mGoogleApiClient.connect();
if (!mRequestingLocationUpdates) {
mRequestingLocationUpdates = true;
startLocationUpdates();
Log.d(TAG, "Periodic location updates started!");
} else {
mRequestingLocationUpdates = false;
// Stopping the location updates
stopLocationUpdates();
Log.d(TAG, "Periodic location updates stopped!");
}
}
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
}
protected void startLocationUpdates() {
mGoogleApiClient.connect();
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
#Override
public void onConnected(Bundle arg0) {
createLocationRequest();
}
#Override
public void onConnectionSuspended(int arg0) {
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = "
+ result.getErrorCode());
}
#Override
public void onLocationChanged(Location location) {
// Assign the new location
mLastLocation = location;
Toast.makeText(getApplicationContext(), "Location changed!",
Toast.LENGTH_SHORT).show();
}
#Override
public boolean stopService(Intent name) {
return super.stopService(name);
}
SearchActivity.class
button = (Button)findViewById(R.id.buttonPressed);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent serviceIntent = new Intent();
serviceIntent.setAction("com.parseapp.eseen.eseen.service.LocationService");
startService(serviceIntent);
}
});
AndroidManifest.xml
<service android:name=".LocationService">
<intent-filter>
<action android:name=".LocationService"> </action>
</intent-filter>
</service>
Your first attempt to start the service using the class name worked:
startService(new Intent(getBaseContext(), LocationService.class));
The exception occurred after the service started executing. Your code cannot use LocationServices until the GoogleApi connection is successful, namely after onConnected() is called. Your code calls connect() multiple times before getting to startLocationUpdates(), but does not wait for onConnected() to be called. That method is the notification you receive when the connection has been made and LocationServices can be used.
This demo code is for an AsyncTask, not a Service, but gives an idea of how the connection processing can be done using a CountDownLatch.
you package name com.parseapp.eseen.eseen
and You are tryng to call using com.parseapp.eseen.eseen.service.LocationService as action but you mentioned in Manifest as .LocationService that means you should call using com.parseapp.eseen.eseen.LocationService
in startLocationUpdates(); you are calling connect again and requesting api before connecting
request for locationupdates from onConnected method
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
I'm a bit confused in deciding the way i should implement my background custom service class.
What I need :
location updates and activity recognition.
REST API call and the Geofence API.
I'm new to background processing in Android and I'm not sure how to implement this.
Is it possible to make a ThreadPoolExecutor (a task manager class, runnables, etc.) and deal with inter-thread communication ?
If yes,is it possible to listen to location updates inside a Thread class ?
for now, I'm using this library ( Smart-location-lib ) to listen to location updates.
is there a better solution ?
Any help is greatly appreciated !
This is the best way using Google API in background service
And you didn't explain what do you mean by activity recognition?
public class MyLocationService extends Service implements LocationListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
public MyLocationService() {
}
#Override
public void onCreate() {
super.onCreate();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API).
addConnectionCallbacks(this).
addOnConnectionFailedListener(this)
.build();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mGoogleApiClient.connect();
Toast.makeText(this, "Location services started", Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent, flags, startId);
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onLocationChanged(Location location) {
System.out.println("MyLocationService.onLocationChanged");
// TODO with location updateshere
}
#Override
public void onConnected(Bundle bundle) {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(1000); // Update location every second
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
Location loc = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
sendMyLocUpdate(loc, UserProfile.DRIVER);
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
#Override
public void onDestroy() {
Toast.makeText(this, "Location services stopped", Toast.LENGTH_LONG).show();
Location loc = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
sendMyLocUpdate(loc, UserProfile.PASSENGER);
mGoogleApiClient.disconnect();
super.onDestroy();
}
}