Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: How to resolve Google API connection fail from a Service?

here is the code provided by the official guide, while this is a snippet causing problems.

@Override
public void onConnectionFailed(ConnectionResult result) {
    if (mResolvingError) {
        // Already attempting to resolve an error.
        return;
    } else if (result.hasResolution()) {
        try {
            mResolvingError = true;
            result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
        } catch (IntentSender.SendIntentException e) {
            // There was an error with the resolution intent. Try again.
            mGoogleApiClient.connect();
        }
    } else {
        // Show dialog using GooglePlayServicesUtil.getErrorDialog()
        mResolvingError = true;
        GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), this, REQUEST_RESOLVE_ERROR)
                .setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialog) {
                        mResolvingError = false;
                    }
                });
    }
}

If I use it in a Service, when you read the variable this passed as argument to those functions, they expect an Activity type. How should I do? It's a Service.

For the same reason I can't get activity result

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_RESOLVE_ERROR) {
    mResolvingError = false;
    if (resultCode == RESULT_OK) {
        // Make sure the app is not already connected or attempting to connect
        if (!mGoogleApiClient.isConnecting() &&
                !mGoogleApiClient.isConnected()) {
            mGoogleApiClient.connect();
        }
    }
}
}
like image 840
user3290180 Avatar asked Jul 09 '15 14:07

user3290180


People also ask

How do I fix the 403 user Rate limit exceeded?

Resolve a 403 error: Project rate limit exceededRaise the per-user quota in the Google Cloud project. For more information, request a quota increase. Batch requests to make fewer API calls. Use exponential backoff to retry the request.

Is GoogleApiClient deprecated?

GoogleApiClient' is deprecated. New! Save questions or answers and organize your favorite content. Learn more.

What is Google API client in Android?

The GoogleApiClient.Builder class provides methods that allow you to specify the Google APIs you want to use and your desired OAuth 2.0 scopes. Here is a code example that creates a GoogleApiClient instance that connects with the Google Drive service: GoogleApiClient mGoogleApiClient = new GoogleApiClient.

What is Google API client?

Google APIs give you programmatic access to Google Maps, Google Drive, YouTube, and many other Google products. To make coding against these APIs easier, Google provides client libraries that can reduce the amount of code you need to write and make your code more robust.


1 Answers

This answer assumes your service is a "started" service. If it is a bound service or intent service, indicate that in a comment and I'll update the description and code included here.

The solution I suggest is to implement the activity shown below to handle the resolution UI. Replace the onConnectionFailed() method in your service with this code to hand off the resolution processing to the ResolverActivity:

@Override
public void onConnectionFailed(ConnectionResult result) {
    Intent i = new Intent(this, ResolverActivity.class);
    i.putExtra(ResolverActivity.CONNECT_RESULT_KEY, result);
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(i);
}

Add the activity shown below to your app. When the connection request in your service fails, the connection result, which is a Parcelable, is passed to the activity. The activity handles the resolution UI and when finished, returns the status to the service as an intent extra. You will need to modify the code in your service's onStartCommand() to examine the extras in the intent to determine if it is being called to start the service for the first time, or to receive resolution status from the ResolverActivity.

An enhancement to this approach would be to post a notification with a PendingIntent for ResolverActivity instead of launching the activity immediately. That would give the user the option of deferring resolution of the connection failure.

public class ResolverActivity extends AppCompatActivity {
    public static final String TAG = "ResolverActivity";

    public static final String CONNECT_RESULT_KEY = "connectResult";

    public static final String CONN_STATUS_KEY = "connectionStatus";
    public static final int CONN_SUCCESS = 1;
    public static final int CONN_FAILED  = 2;
    public static final int CONN_CANCELLED = 3;

    // Request code to use when launching the resolution activity
    private static final int REQUEST_RESOLVE_ERROR = 1111;

    private static final String ERROR_CODE_KEY = "errorCode";
    private static final String DIALOG_FRAG_TAG = "errorDialog";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Log.i(TAG, "onCreate()");

        // No content needed.
        //setContentView(R.layout.activity_main);

        Intent i = getIntent();

        ConnectionResult result = i.getParcelableExtra(CONNECT_RESULT_KEY);

        if (result.hasResolution()) {
            try {
                Log.i(TAG, "Starting error resolution...");
                result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
            } catch (IntentSender.SendIntentException e) {
                // There was an error with the resolution intent.
                sendStatusToService(CONN_FAILED);
                finish();
            }
        } else {
            // Show dialog using GooglePlayServicesUtil.getErrorDialog()
            ErrorDialogFragment.newInstance(result.getErrorCode())
                    .show(getSupportFragmentManager(), DIALOG_FRAG_TAG);
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent result) {

        if (requestCode == REQUEST_RESOLVE_ERROR) {
            if (resultCode == RESULT_OK) {
                Log.i(TAG, "onActivityResult(): Connection problem resolved");
                sendStatusToService(CONN_SUCCESS);
            } else {
                sendStatusToService(CONN_CANCELLED);
                Log.w(TAG, "onActivityResult(): Resolution cancelled");
            }
            // Nothing more to do in this activity
            finish();
        }
    }

    private void sendStatusToService(int status) {
        Intent i = new Intent(this, MyGoogleApiService.class);
        i.putExtra(CONN_STATUS_KEY, status);
        startService(i);
    }

    // Fragment to display an error dialog
    public static class ErrorDialogFragment extends DialogFragment {

        public static ErrorDialogFragment newInstance(int errorCode) {
            ErrorDialogFragment f = new ErrorDialogFragment();
            // Pass the error that should be displayed
            Bundle args = new Bundle();
            args.putInt(ERROR_CODE_KEY, errorCode);
            f.setArguments(args);
            return f;
        }

        @Override
        @NonNull
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            // Get the error code and retrieve the appropriate dialog
            int errorCode = getArguments().getInt(ERROR_CODE_KEY);
            return GooglePlayServicesUtil.getErrorDialog(
                    errorCode, getActivity(), REQUEST_RESOLVE_ERROR);
        }

        @Override
        public void onDismiss(DialogInterface dialog) {
            Log.i(TAG, "Dialog dismissed");
        }
    }
}
like image 84
Bob Snyder Avatar answered Oct 29 '22 19:10

Bob Snyder