Qing Qing - 16 days ago 5
Android Question

How to use a Fragment to start Smartlock saving instead of using an Activity

I just realised that the smartlock api doesnt allow me to pass a Fragment to the ResolvingResultCallbacks object when I was doing refactoring for out android app.

The API only allows me to pass an Activity as the context, which means i need to handle the credentials result in Activity's onActivityResult() method instead of the Fragment's. But in our app's current design, we want the Fragment to handle the smartlock logic.

Here's my code for saving :

Auth.CredentialsApi.save(mSmartLockApiClient, credential).setResultCallback(
new ResolvingResultCallbacks<Status>(mActivity, RC_CREDENTIALS_SAVE) {
@Override
public void onSuccess(Status status) {
mSmartLockSaveCallBack.onSuccess();
}

@Override
public void onUnresolvableFailure(Status status) {

}
});
}


actually for requesting credentials, i had the same issue, the api doesnt provide a way to pass fragment to start the resolution. but i find a workaround:

if (status.hasResolution()) {
mFragment.startIntentSenderForResult(status.getResolution().getIntentSender(), RC_CREDENTIALS_READ, null, 0, 0, 0, null);
}

Answer

I agree that it's disappointing that ResolvingResultCallbacks doesn't directly support fragments, but the implementation is actually pretty simple. Here is a variant that supports fragments:

public abstract class ResolvingResultCallbacks<R extends Result>
    extends ResultCallbacks<R> {
  private static final String TAG = "ResolvingResultCallback";

  private final Fragment mFragment;
  private final int mRequestCode;

  protected ResolvingResultCallbacks(
      @NonNull Fragment fragment, 
      int requestCode) {
    mFragment = fragment;
    mRequestCode = requestCode;
  }

  @Override
  public final void onFailure(@NonNull Status result) {
    if (result.hasResolution()) {
      try {
        mFragment.startIntentSenderForResult(
            result.getResolution().getIntentSender(),
            mRequestCode,
            null, // fillInIntent,
            0, // flagsMask,
            0, // flagsValues
            0, // extraFlags
            null); // options
      } catch (IntentSender.SendIntentException ex) {
        Log.e(TAG, "Failed to start resolution", ex);
        onUnresolvableFailure(
            new Status(CommonStatusCodes.INTERNAL_ERROR));
      }
    } else {
      onUnresolvableFailure(result);
    }
  }

  @Override
  public abstract void onSuccess(@NonNull R result);

  @Override
  public abstract void onUnresolvableFailure(@NonNull Status result);
}

startIntentSenderForResult was only added to the native Fragment type in API v24, so you will likely need to use the support Fragment implementation instead.

I've not tested this, so please do let me know if it works for you.

Comments