Implementing Google Location Services API inside a service - android

I have implemented Google Location Services inside a service, so that I can get location updates in the background (so that updates don't stop when user locks screen, switches fragment, etc.). But I am getting a strange error message that is stopping me from implementing it.
On the line:
"LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);"
It is telling me that 2rd parameter 'this' is not allowed and should be cast to (com.google.android.gms.location.LocationListener). But in every example I've seen this is not the case. When I do cast it, it does not work
Below is my code, trouble is in the onConnected method
public class LocationTrackingService extends Service implements LocationListener, ConnectionCallbacks, OnConnectionFailedListener {
GoogleApiClient googleApiClient = null;
LocationRequest locationRequest;
Location currentLocation;
static final int INTERVAL = 2000;
static final int FASTEST_INTERVAL = 500;
static final int PRIORITY = LocationRequest.PRIORITY_HIGH_ACCURACY;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
setupGoogleApiClient();
createLocationRequest(INTERVAL, FASTEST_INTERVAL, PRIORITY);
googleApiClient.connect();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (!googleApiClient.isConnected()) {
googleApiClient.connect();
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
//TODO maybe dont need this
googleApiClient.disconnect();
super.onDestroy();
}
#Override
public void onLocationChanged(Location location) {
//updating current location
currentLocation = location;
//TODO will be writing directly to database here
//broadcasting intent
Intent publishLocationUpdate = new Intent("location_update");
publishLocationUpdate.putExtra("current_location", currentLocation);
sendBroadcast(publishLocationUpdate);
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
//if location tracking is not enabled
#Override
public void onProviderDisabled(String s) {
Intent toSettings = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
toSettings.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(toSettings);
}
#Override
public void onConnected(#Nullable Bundle bundle) {
//sets location to last known location
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;
}
currentLocation = FusedLocationApi.getLastLocation(googleApiClient);
//request updates
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
// Create an instance of GoogleAPIClient which we call to recieve location information
void setupGoogleApiClient(){
if (googleApiClient == null) {
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
//set request settings, interval: how soon until new request is made, priority affects batterylife (using GPS, netowork, data...)
void createLocationRequest(int interval, int fastestInterval, int priority) {
locationRequest = new LocationRequest();
locationRequest.setInterval(interval);
locationRequest.setFastestInterval(fastestInterval);
locationRequest.setPriority(priority);
//can also use PRIORITY_LOW_POWER, PRIORITY_BALANACED_POWER_ACCURACY, PRIORITY_NO_POWER
}
}
I check the intent in onResume in my fragment, code below:
if(broadcastReceiver == null){
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Location currentLocation;
currentLocation = (Location) intent.getExtras().get("current_location");
currentAltitudeTextView.setText(String.valueOf(currentLocation.getLatitude()));
currentSpeedTextView.setText(String.valueOf(currentLocation.getLongitude()));
}
};
}
context.registerReceiver(broadcastReceiver, new IntentFilter("location_update"));

Related

getting gps data from service in background

I tried to get gps data (speed) when I don't use the app i'm programming.
but always when I close the app it stops asking for gps updates. now I got told, that I have to use a service. so i did, but it still stops asking for updates everytime I close to ui of the app.
here is my code of the service:
package com.example.slartibartfast.kslordered;
public class BackroundService extends Service {
private static float speed;
//initializing the Location Manager and Listener
LocationManager locationManager;
LocationListener locationListener;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#SuppressLint("MissingPermission")
#Override
public void onCreate() {
//Instantiating the device manager an listener
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
//when the location changed
Log.d("Location", ""+location);
Log.d("Float Location", ""+ location.getLongitude() + " " + location.getLatitude());
Log.d("Speed", " "+location.getSpeed());
//initializing the variable speed with the speed number given by the LocationListener
speed = location.getSpeed();
//creating a broadcast reciever
Intent intent = new Intent("speed_update");
intent.putExtra("speed", speed);
//sending speed to main activity
sendBroadcast(intent);
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String s) {
//if gps is disabled, this opens the gps settings
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
};
locationManager.requestLocationUpdates("gps", 5000, 0, locationListener);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
}
and here of my main activity:
package com.example.slartibartfast.kslordered;
public class MainActivity extends AppCompatActivity {
//initializing ui elements
TextView textviewSpeed;
Button button;
//initializing ui BroadcastReciever
private BroadcastReceiver broadcastReceiver;
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//instantiating the ui elements
textviewSpeed = (TextView)findViewById(R.id.textview_speed);
//checking if permission to use gps location is given
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 10);
return;
}else{
}
startService(new Intent(this, BackroundService.class));
}
#Override
protected void onResume() {
super.onResume();
//broadcast reciever gets speed from the backround service
if (broadcastReceiver == null){
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//speed get's set on the textview
textviewSpeed.setText(""+ intent.getExtras().get("speed"));
}
};
}
registerReceiver(broadcastReceiver, new IntentFilter("speed_update"));
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
//asks for the gps user permission
switch (requestCode){
case 10:
if (grantResults.length>0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//(5000);
}
}
}
I think you need to add your code on OnStart instead of OnCreate
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
//when the location changed
Log.d("Location", ""+location);
Log.d("Float Location", ""+ location.getLongitude() + " " + location.getLatitude());
Log.d("Speed", " "+location.getSpeed());
//initializing the variable speed with the speed number given by the LocationListener
speed = location.getSpeed();
//creating a broadcast reciever
Intent intent = new Intent("speed_update");
intent.putExtra("speed", speed);
//sending speed to main activity
sendBroadcast(intent);
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String s) {
//if gps is disabled, this opens the gps settings
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
};
locationManager.requestLocationUpdates("gps", 5000, 0, locationListener);
return START_STICKY;
}

GoogleApiClient onConnected not being called, using in a Service

Was working when I was using GoogleApiClient in an Activity but moved it to a Service and the onConnected is not being called.
public class StepsMonitoringService extends Service implements GoogleApiClient.ConnectionCallbacks {
private GoogleApiClient mClient;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
mClient = new GoogleApiClient.Builder(this).addApi(Fitness.HISTORY_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ))
.addConnectionCallbacks(this).build();
mClient.connect();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
mClient.disconnect();
}
#Override
public void onConnected(Bundle connectionHint) {
// NOT being called!! WHY??
}
#Override
public void onConnectionSuspended(int cause) {
}
}
Any ideas anyone? What am I doing wrong? Has anyone got GoogleApiClient working in a Service?
The service is called from an Activity
public class MainActivity extends FragmentActivity {
private TextView mStepsView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, StepsMonitoringService.class);
startService(intent);
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter("StepMonitoringServiceIntent"));
mStepsView = (TextView) findViewById(R.id.steps);
}
private void displayOnUI(String msg) {
mStepsView.setText(msg + "\n" + mStepsView.getText());
}
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
long steps = intent.getLongExtra("steps", 0);
displayOnUI(steps + " steps");
}
};
}
During debugging I can see the onCreate of the Service gets called, however the onConnected is never called. Nothing special in the logs from what I can see.
First implement these interfaces:
GoogleApiClient.ConnectionCallbacks
GoogleApiClient.OnConnectionFailedListener
Then you will have to add these methods to your class:
public void onConnected(final Bundle bundle)
public void onConnectionSuspended(final int i)
public void onConnectionFailed(final ConnectionResult connectionResult)
As soon as you connect, the OnConnected method will be called. In this method can you do whatever you want, like getting the current location, the location address, add a marker point to map, etc.
But you cannot do anything without establishing a connection to the Google API client.
To connect to the GoogleAPIClient, you can add this method to your class and call it in your onCreate method.
private synchronized void buildGoogleAPIClient(){
googleApiclient = new GoogleApiClient.Builder(getActivity())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
googleApiclient.connect();
Toast.makeText(getActivity(), "connected", Toast.LENGTH_SHORT).show();
}
Add addOnConnectionFailedListener to GoogleApiClient to track the error. As per doc addOnConnectionFailedListener called when there was an error connecting the client to the service.
public class StepsMonitoringService extends Service implements GoogleApiClient.ConnectionCallbacks {
private GoogleApiClient mClient;
#Override
public void onCreate() {
super.onCreate();
mClient = new GoogleApiClient.Builder(this).addApi(Fitness.HISTORY_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ))
.addConnectionCallbacks(this)
//Add Connection Failed Listener to track error.
.addOnConnectionFailedListener(this)
.build();
mClient.connect();
}
#Override
public void onConnected(Bundle connectionHint) {
// NOT being called!! WHY??
}
#Override
public void onConnectionSuspended(int cause) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
//Called called when there was an error connecting the client to the service.
Log.i(LOG_TAG,"onConnectionFailed:"+connectionResult.getErrorCode()+","+connectionResult.getErrorMessage());
}
}
try this.
public class StepsMonitoringService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
/**
* Provides the entry point to Google Play services.
*/
protected GoogleApiClient mClient;
/**
* Builds a GoogleApiClient. Uses the addApi() method to request the
* Fitness API.
*/
protected synchronized void buildGoogleApiClient() {
mClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Fitness.HISTORY_API)
.build();
}
#Override
public void onCreate() {
super.onCreate();
if (mClient == null) {
buildGoogleApiClient();
}
mClient.connect();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onConnected(Bundle connectionHint) {
// NOT being called!! WHY??
}
#Override
public void onConnectionSuspended(int cause) {
mClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// Called called when there was an error connecting the client to the
// service.
Log.i(LOG_TAG,
"onConnectionFailed:" + connectionResult.getErrorCode() + "," + connectionResult.getErrorMessage());
}
}
I had a same issue when I was using useDefaultAccount() to create a client. I then replaced it with setAccountName() and it starts working. I think for some reasons accountpicker doesn't work in service that's why googleapiclient's connect() silently failed since you need specify which account you use for retrieving Fitness info. Noted that you need to have an account picker in your activity and pass the email account to your service in some way.

Initialing GoogleApiClient after boot

I'm registering my app after boot to receive location updates. My boot receiver is starting a service that does the initialization:
#Override
protected void onHandleIntent(Intent intent) {
GoogleApiClient client = _googleApiBuilder.get()
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
client.connect();
}
Sometimes in the onConnected callback method I'm getting exception indication I'm not connected yet. After some research I've encountered this - GoogleApiClient is throwing "GoogleApiClient is not connected yet" AFTER onConnected function getting called
It made me think, does the way I'm initializing google api is correct ? e.g. should I initialize it in a service ?
What is the suggested way to do it in the background ?
Hope it will be helpful to you.
public class LocationService extends Service implements ConnectionCallbacks,
OnConnectionFailedListener, LocationListener {
private static final String TAG = LocationService.class.getSimpleName();
private GoogleApiClient mGoogleApiClient;
#Override
public IBinder onBind(final Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
initGoogleApi();
}
#Override
public int onStartCommand(final Intent intent, final int flags,
final int startId) {
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onLocationChanged(final Location location) {
}
#Override
public void onConnectionFailed(final ConnectionResult result) {
}
#Override
public void onConnected(final Bundle bundale) {
createLocationRequest();
}
#Override
public void onConnectionSuspended(final int arg0) {
}
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
}
protected void createLocationRequest() {
final LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(Constants.INTERVAL);
mLocationRequest.setFastestInterval(Constants.FAST_INTERVAL);
mLocationRequest
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mLocationRequest.setSmallestDisplacement(0);
startLocationUpdates(mLocationRequest);
}
private void initGoogleApi() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API).addApi(ActivityRecognition.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
}
}
Used the following solution instead:
googleApiInstance.blockingConnect(10, TimeUnit.SECONDS);
or in other words instead of running the operation in a different thread (that's what connect is doing), I'm running it in my own thread (I'm using IntentService) and manage the connection life cycle on my own.

How to update GPS Location on App Background to Foreground?

I am using GPS either GPS_PROVIDER or NETWORK_SERVICE_PROVIDER for latitude and longitude . I want to detect when specifically App goes background to foreground (Either By Home button) .
ISSUES:
GPS detected location is not updated from time to time until any app used it so can get the updated location .
Detect the Background to foreground of app and detect location without battery issues .
Any GPS location update time to time without any battery issues.
For get location in background frequently use FusedLocation provider in a android service class.
Fused location provide give more accurate location and consume less power.
public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener,LocationListener{
private static final String TAG = "LocationService";
private static final int LOCATION_INTERVAL = 1000;
private Context mContext;
private LocationRequest locationRequest;
private GoogleApiClient googleApiClient;
private FusedLocationProviderApi fusedLocationProviderApi;
#Override
public IBinder onBind(Intent arg0){
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId){
Log.e(TAG, "onStartCommand");
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onCreate(){
Log.e(TAG, "onCreate");
mContext = this;
getLocation();
}
#Override
public void onDestroy(){
Log.e(TAG, "onDestroy");
super.onDestroy();
try{
if(googleApiClient!=null){
googleApiClient.disconnect();
}
}
catch(Exception e){
e.printStackTrace();
}
}
private void getLocation(){
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(LOCATION_INTERVAL);
locationRequest.setFastestInterval(LOCATION_INTERVAL);
fusedLocationProviderApi = LocationServices.FusedLocationApi;
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
if (googleApiClient != null) {
googleApiClient.connect();
}
}
#Override
public void onConnected(Bundle arg0) {
// Location location = fusedLocationProviderApi.getLastLocation(googleApiClient);
fusedLocationProviderApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
#Override
public void onConnectionSuspended(int arg0) {
}
#Override
public void onResponse(int reqCode, int statusCode, String json) {
}
#Override
public void onCancel(boolean canceled) {
}
#Override
public void onProgressChange(int progress) {
}
#Override
public void onLocationChanged(Location location) {
Toast.makeText(mContext, "Driver location :"+location.getLatitude()+" , "+location.getLongitude(), Toast.LENGTH_SHORT).show();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
}
}
and call service from your activity-
startService(new Intent(mContext,LocationService.class));
hope it will help you.
EDITED
Also add below code to your manifest -
<service
android:name=".LocationService">
</service>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

Google ActivityRecognitionApi not firing any callbacks

GooglePlayServices recently changed from the way you detect the users activity - from using ActivityRecognitionClient to ActivityRecognitionApi. I have followed all the examples I can find but must have missed something.
After making the call to GoogleApiClient.Builder(mContext).addApi(ActivityRecognition.API)...build() I was expecting that one of the connection callback methods would be called. I have logging and breakpoints in all the callback methods but none of them are ever called.
OnReceive() and CallClient() are called as expected and the manifest file includes: uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"
What am I missing? I would love to get to the bottom of this given the amount of time I have wasted so far.
(P.S. It's my own Logging library - it is not part of the issue)
public class BootAtStartupReceiver extends BroadcastReceiver implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener{
private final String TAG = getClass().getName();
private PendingIntent mpIntent;
private static GoogleApiClient mGoogleApiClient;
private Context mContext;
#Override
public void onReceive(Context context, Intent intent) {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onReceive: " + intent.getAction());
if ((intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) || (intent.getAction().equals(BroadcastIntentConstants.ACTIVITY_FIRST_TIME_CALL_SERVICE)))
{
mContext = context;
callClient();
}
}
private void callClient() {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside callClient");
int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(mContext);
if (resp == ConnectionResult.SUCCESS) {
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addApi(ActivityRecognition.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
} else {
Logging.log(Logging.enumLoggingLevel.e, getClass().getName(), "Google play Services are not available.");
}
}
#Override
public void onConnected(Bundle bundle) {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onConnected");
Intent intent = new Intent(mContext, ActivityRecognitionIntentService.class);
mpIntent = PendingIntent.getService(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(mGoogleApiClient, 1000, mpIntent);
}
#Override
public void onDisconnected() {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onDisconnected");
}
#Override
public void onConnectionSuspended(int i) {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onConnectionSuspended");
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onConnectionFailed");
}
}
Are you missing the call to connect() after the build? The callbacks dont fire unless you call connect.
mGoogleApiClient.connect()

Categories

Resources