12

I'm using a Service which implements com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks and com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener

The service is supposed to upload location updates to a server every minute when it's running. I've googled for tutorials but I can't find any good ones for my scenario.

The methods that I don't know how to implement are:

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {

    ...
}

There are some tutorials suggesting to start an activity with connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST); but since this is a Service (not an Activity) I can't use this method. I thought of sending the connectionResult in an Intent to an activity but ConnectionResult is not serializable.

and

@Override
public void onDisconnected() {

    ...
}

Should I just call LocationClient#connect() again in here?

Peter Warbo
  • 11,136
  • 14
  • 98
  • 193

5 Answers5

4

1. In onConnectionFailed():
For "I thought of sending the connectionResult in an Intent to an activity but ConnectionResult is not serializable." I think it can work without that in the following way:

You can return the int ; ErrorCodes or Constants value of ConnectionResult and depending on that value, you can assign further actions, just pass the control to your activity/application.
From:
http://developer.android.com/reference/com/google/android/gms/common/ConnectionResult.html

2. In onDisconnected(),
You can notify the user that "you are no longer receiving location updates" or another custom message depending on your app which would prompt the user to take an action.
If your service enters onDisconnected() for some reason we aren't aware of, calling locationClient.connect() again may not help.

In both scenarios, the idea is to pass the control to your app so somewhere in your activity, it can work as a decision point for the control flow.

Also, you have mentioned "...but I can't find any good ones for my scenario." so describing your requirement a bit precisely may help you more. Will edit my answer accordingly.

If its sending location updates to the server, then passing the control back to your activity/app and prompt user also for action would also help. (eg. Check Settings for Location access services enabled)


Current scenario for anybody looking up this question/answer
LocationClient is no longer found under com.google.android.gms.location, refer:
Android play services 6.5: LocationClient is missing

Community
  • 1
  • 1
Pararth
  • 8,114
  • 4
  • 34
  • 51
  • Point 2 is incorrect. `onDisconnected()` is **not** called after a call to `disconnect()`. See [here](http://stackoverflow.com/q/22426271/2433501). – zelanix Feb 24 '15 at 23:32
  • @zelanix thanks for pointing it out, though its not the whole point that is incorrect, you are correct about the line referring to `onDisconnect()`, i deleted that – Pararth Feb 25 '15 at 05:51
  • No, absolutely - sorry, that was a bit unfairly worded - the rest of the answer looks good. I think that [this solution] (http://stackoverflow.com/a/19433291/2433501) seems like a reasonable way to handle re-connection after `onDisconnected()`. – zelanix Feb 25 '15 at 17:46
  • that's alright, well yes don't think it matters now, LocationClient is deprecated, and interfaces implement `onConnectionFailed()` and `onConnectionSuspended()` – Pararth Feb 26 '15 at 05:36
  • @zelanix are you working with location ? do you access location settings from the app ? [i am trying to achieve this](http://stackoverflow.com/questions/28759454/enabling-location-with-mode-high-accuracy-or-battery-saving-without-user-needing) – Pararth Feb 27 '15 at 10:01
  • No, sorry - I'm surprised Google Maps can do it though. I hope that you find a solution - please post it as an answer if you do. – zelanix Feb 27 '15 at 20:54
2

I'm not sure how it was in the past but right now (Marshmallow) ConnectionResult is Parcelable:

public final class ConnectionResult implements SafeParcelable

Knowing this you can send it in Intent's extras:

@Override
public void onConnectionFailed(final ConnectionResult result) {
    Log.w(LOG_TAG, "Connecting to Google Play Services failed. Result=" + result);
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(new Runnable() {
        @Override
        public void run() {
            Intent intent = new Intent(context, MainActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra(INTENT_EXTRA_CONNECTION_RESULT, connectionResult);
            context.startActivity(intent);
        }
    });
}

Then MainActivity (or any other Activity) can show proper resolutions or dialog messages to the user:

Parcelable connectionResultExtra = activity.getIntent().getParcelableExtra(INTENT_EXTRA_CONNECTION_RESULT);
    if (connectionResultExtra != null) {
        ConnectionResult connectionResult = (ConnectionResult) connectionResultExtra;
        if (connectionResult.hasResolution()) {
            try {
                connectionResult.startResolutionForResult(activity, 1234567890);
            } catch (IntentSender.SendIntentException e) {
                Log.e(LOG_TAG, "Unable to resolve ConnectionResult", e);
            }
        } else {
            int availabilityCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(activity);
            if (availabilityCode != 0) {
                Dialog errorDialog = GoogleApiAvailability.getInstance().getErrorDialog(activity, availabilityCode, 123);
                errorDialog.show();
        }
    }

I hope it helps.

1
  1. The method "OnConnectionFailed()" is called when you call "yourLocationClient.connect()" and the LocationClient fails to connect to Google Play Location Services.

  2. In the method "startResolutionForResult (Activity activity, int requestCode)", the first parameter is an Activity class so the UI related stuff should pop up on the activity itself. You should try giving in the name of the Activity class where you want to show the resolution result. (I am not sure but you can try)

  3. If point 2 does not work, you can always send a broadcast to the activity with an 'int' as an extra. The int here signifies the type of error that you get inside 'connectionResult'.

  4. If you want your Client to be connected all the while, you can call 'onConnected()' inside 'onDisconnected()', although it does not get disconnected until you explicitly call 'disconnect()'.

  5. If you want your service running all the while even if the user closes the app from the application tray, be sure to check this link out.

Most important:

If you are using Google Play Services in your application, You should check for the availability of the services when the application starts for the 1st time. Even before some service starts or you take the user to the Main Activity. You can do this on any blank activity / an activity after registration / after splash.

Community
  • 1
  • 1
geekoraul
  • 2,623
  • 2
  • 21
  • 33
  • Thank you for workaround, shame on google. This question became more actual after google announced Android M where people can disable permissions _after_ installation. – ruX Jun 02 '15 at 14:19
0

Here's a better answer:

ConnectionResult is not parcelable, but it has a constructor that takes an errorCode and a pendingIntent. Both of those are parcelable.

So, in your service:

private void notifyUiFailedConnection(ConnectionResult result) {
    Intent intent = new Intent(FIT_NOTIFY_INTENT);
    intent.putExtra(FIT_EXTRA_NOTIFY_FAILED_STATUS_CODE, result.getErrorCode());
    intent.putExtra(FIT_EXTRA_NOTIFY_FAILED_INTENT, result.getResolution());
    LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}

In your activity:

private BroadcastReceiver mFitStatusReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // Get extra data included in the Intent
        if (intent.hasExtra(GoogleFitService.FIT_EXTRA_NOTIFY_FAILED_STATUS_CODE) &&
                intent.hasExtra(GoogleFitService.FIT_EXTRA_NOTIFY_FAILED_STATUS_CODE)) {
            //Recreate the connection result
            int statusCode = intent.getIntExtra(GoogleFitService.FIT_EXTRA_NOTIFY_FAILED_STATUS_CODE, 0);
            PendingIntent pendingIntent = intent.getParcelableExtra(GoogleFitService.FIT_EXTRA_NOTIFY_FAILED_INTENT);
            ConnectionResult result = new ConnectionResult(statusCode, pendingIntent);
            fitHandleFailedConnection(result);
        }
    }
};
rsteckler
  • 305
  • 2
  • 8
-3

implement onconnection failed listsner in your service and override its method, like this :

public class yourService extends Service implements 
    LocationListener, OnConnectionFailedListener {

@Override
public void onConnectionFailed(ConnectionResult arg0) {

}

}

Vijju
  • 3,458
  • 1
  • 22
  • 20