| Index: chrome/android/java/src/org/chromium/chrome/browser/externalauth/UserRecoverableErrorHandler.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/UserRecoverableErrorHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/UserRecoverableErrorHandler.java
|
| index 92d10edd286fae2f05900856cd38a73165141b58..ae6cb514d338101921b4b25a25553676a06de7c0 100644
|
| --- a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/UserRecoverableErrorHandler.java
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/UserRecoverableErrorHandler.java
|
| @@ -7,10 +7,12 @@ package org.chromium.chrome.browser.externalauth;
|
| import android.app.Activity;
|
| import android.app.Dialog;
|
| import android.content.Context;
|
| -import android.content.DialogInterface;
|
| +import android.content.DialogInterface.OnCancelListener;
|
|
|
| import com.google.android.gms.common.GooglePlayServicesUtil;
|
|
|
| +import org.chromium.base.ThreadUtils;
|
| +
|
| import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
| /**
|
| @@ -31,106 +33,180 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
| * for a feature that the user is actively trying to access interactively where
|
| * the feature cannot function (or would be severely impaired) unless the
|
| * dependency is satisfied. The dialog will be presented as many times as the
|
| - * user tries to access the feature.
|
| + * user tries to access the feature. A subclass can (and usually should) be
|
| + * created to provide custom handling of the user response to the dialog by
|
| + * overriding {@link ModalDialog#prepareToHandle(Activity, Context, int)},
|
| + * {@link ModalDialog#getRequestCode()} and
|
| + * {@link ModalDialog#getOnCancelListener()} as appropriate. This will allow the
|
| + * code encountering the error to respond to the user's corrective actions (or
|
| + * lack thereof) immediately.
|
| + * <br>
|
| + * If none of these behaviors is suitable, a new behavior can be defined by
|
| + * subclassing this class.
|
| */
|
| -public abstract class UserRecoverableErrorHandler implements Runnable {
|
| +public abstract class UserRecoverableErrorHandler {
|
| + /**
|
| + * Handles the specified error code from Google Play Services.
|
| + * This method must only be called on the UI thread.
|
| + * This method asserts that it is being called on the UI thread, then calls
|
| + * {@link #handle(Context, int)}.
|
| + * @param context the context in which the error was encountered
|
| + * @param errorCode the error code from Google Play Services
|
| + */
|
| + public final void handleError(final Context context, final int errorCode) {
|
| + ThreadUtils.assertOnUiThread();
|
| + handle(context, errorCode);
|
| + }
|
| +
|
| + /**
|
| + * This method is invoked by {@link #handleError(Context, int)} to do the
|
| + * work appropriate for the subclass on the UI thread.
|
| + * The default implementation does nothing.
|
| + * @param context the context in which the error was encountered
|
| + * @param errorCode the error code from Google Play Services
|
| + */
|
| + protected void handle(final Context context, final int errorCode) {
|
| + // Nothing.
|
| + }
|
| +
|
| /**
|
| * A handler that does nothing.
|
| */
|
| public static final class Silent extends UserRecoverableErrorHandler {
|
| - @Override
|
| - public void run() {
|
| - // Do nothing.
|
| - }
|
| + // No special behavior.
|
| }
|
|
|
| /**
|
| - * A handler that displays a System Notification. To avoid repeatedly nagging the user, this
|
| - * is done at most one time per process.
|
| + * A handler that displays a System Notification. To avoid repeatedly
|
| + * nagging the user, this is done at most one time per application
|
| + * lifecycle.
|
| * @see GooglePlayServicesUtil#showErrorNotification(int, Context)
|
| */
|
| public static final class SystemNotification extends UserRecoverableErrorHandler {
|
| /**
|
| - * The error code returned from Google Play Services.
|
| - */
|
| - private final int mErrorCode;
|
| -
|
| - /**
|
| - * The context in which the error was encountered.
|
| - */
|
| - private final Context mContext;
|
| -
|
| - /**
|
| - * Tracks whether the notification has yet been shown.
|
| + * Tracks whether the notification has yet been shown, used to ensure
|
| + * that the notification is shown at most one time per application
|
| + * lifecycle.
|
| */
|
| private static final AtomicBoolean sNotificationShown = new AtomicBoolean(false);
|
|
|
| - /**
|
| - * Create a new System Notification handler for the specified context and error code.
|
| - * @param context the context in which the error was encountered.
|
| - * @param errorCode the error code from Google Play Services.
|
| - */
|
| - public SystemNotification(Context context, int errorCode) {
|
| - mContext = context;
|
| - mErrorCode = errorCode;
|
| - }
|
| -
|
| @Override
|
| - public void run() {
|
| + protected void handle(final Context context, final int errorCode) {
|
| if (!sNotificationShown.getAndSet(true)) {
|
| return;
|
| }
|
| - GooglePlayServicesUtil.showErrorNotification(mErrorCode, mContext);
|
| + GooglePlayServicesUtil.showErrorNotification(errorCode, context);
|
| }
|
| }
|
|
|
| /**
|
| - * A handler that displays a modal dialog. Unlike {@link SystemNotification}, this handler
|
| - * will take action every time it is invoked.
|
| + * A handler that displays a modal dialog. Unlike
|
| + * {@link SystemNotification}, this handler will take action every time it
|
| + * is invoked. Subclasses should override the methods
|
| + * {@link ModalDialog#prepareToHandle(Activity, Context, int)},
|
| + * {@link ModalDialog#getRequestCode()} and
|
| + * {@link ModalDialog#getOnCancelListener()} to provide custom handling of
|
| + * the user response.
|
| * @see GooglePlayServicesUtil#getErrorDialog(int, Activity, int,
|
| * android.content.DialogInterface.OnCancelListener)
|
| */
|
| - public static final class ModalDialog extends UserRecoverableErrorHandler {
|
| + public static class ModalDialog extends UserRecoverableErrorHandler {
|
| /**
|
| - * The error code returned from Google Play Services.
|
| + * Value to be returned from {@link #getRequestCode()} to indicate that
|
| + * no response information is needed from the dialog.
|
| */
|
| - private final int mErrorCode;
|
| + public static final int NO_RESPONSE_REQUIRED = -1;
|
|
|
| /**
|
| - * The activity in which the error was encountered.
|
| + * The activity from which to start the dialog and any subsequent
|
| + * actions, and the activity which will receive the response from those
|
| + * actions.
|
| */
|
| private final Activity mActivity;
|
|
|
| /**
|
| - * The request code given when calling startActivityForResult.
|
| + * Create a new Modal Dialog handler for the specified activity and
|
| + * error code. The specified activity may be used to launch the dialog
|
| + * via
|
| + * {@link Activity#startActivityForResult(android.content.Intent, int)}
|
| + * and also to receive the result via Activity's protected
|
| + * onActivityResult method.
|
| + * @param activity the activity to use
|
| */
|
| - private final int mRequestCode;
|
| + public ModalDialog(Activity activity) {
|
| + mActivity = activity;
|
| + }
|
|
|
| /**
|
| - * The DialogInterface.OnCancelListener to invoke if the dialog is canceled.
|
| + * Returns the activity that was passed to the constructor.
|
| + * @return the activity
|
| */
|
| - private final DialogInterface.OnCancelListener mOnCancelListener;
|
| + protected final Activity getActivity() {
|
| + return mActivity;
|
| + }
|
|
|
| /**
|
| - * Create a new Modal Dialog handler for the specified activity and error code.
|
| - * @param activity the activity in which the dialog is to be displayed.
|
| - * @param errorCode the error code from Google Play Services.
|
| - * @param requestCode the request code given when calling startActivityForResult.
|
| - * @param onCancelListener the DialogInterface.OnCancelListener to invoke if the dialog
|
| - * is canceled.
|
| + * Convenience method for subclasses that is guaranteed to be called
|
| + * immediately prior to {@link #handle(Context, int)} on the UI thread.
|
| + * The default implementation does nothing. Subclasses can override
|
| + * this method to prepare a request code for {@link #getRequestCode()}
|
| + * and an {@link OnCancelListener} for {@link #getOnCancelListener()}
|
| + * on-demand (i.e., when it is known that an error has occurred and the
|
| + * error code is available).
|
| + * @param activity the activity that was passed to the constructor
|
| + * @param context the context in which the error was encountered
|
| + * @param errorCode the error code from Google Play Services
|
| */
|
| - public ModalDialog(Activity activity, int errorCode, int requestCode,
|
| - DialogInterface.OnCancelListener onCancelListener) {
|
| - mActivity = activity;
|
| - mErrorCode = errorCode;
|
| - mRequestCode = requestCode;
|
| - mOnCancelListener = onCancelListener;
|
| + protected void prepareToHandle(
|
| + final Activity activity, final Context context, final int errorCode) {
|
| + // Nothing.
|
| + }
|
| +
|
| + /**
|
| + * Returns an integer request code to pass to
|
| + * {@link Activity#startActivityForResult(android.content.Intent, int)}.
|
| + * If this method returns a positive value, then the dialog will be
|
| + * launched by calling
|
| + * {@link Activity#startActivityForResult(android.content.Intent, int)}
|
| + * on the Activity that was passed to the constructor and upon
|
| + * completion the Activity's protected onActivityResult method will
|
| + * receive the results. The default implementation returns
|
| + * {@link #NO_RESPONSE_REQUIRED} (a negative value), indicating that
|
| + * the dialog can be launched independent of the Activity passed to the
|
| + * constructor and that no response needs to be processed by the
|
| + * Activity. This method is guaranteed to be called only after a call to
|
| + * {@link #prepareToHandle(Activity, Context, int)}.
|
| + * @return the request code
|
| + */
|
| + protected int getRequestCode() {
|
| + return NO_RESPONSE_REQUIRED;
|
| }
|
|
|
| + /**
|
| + * Optionally, returns a {@link OnCancelListener} that should be invoked
|
| + * if the dialog is canceled or null if the activity doesn't care about
|
| + * this event. The default implementation returns null.
|
| + * This method is guaranteed to be called only after a call to
|
| + * {@link #prepareToHandle(Activity, Context, int)}.
|
| + * @return the listener, or null
|
| + */
|
| + protected OnCancelListener getOnCancelListener() {
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Invokes {@link #prepareToHandle(Activity, Context, int)}, gathers
|
| + * the request code and cancel listener from {@link #getRequestCode()}
|
| + * and {@link #getOnCancelListener()} respectively, and displays the
|
| + * dialog in a modal manner.
|
| + * @param context the context in which the error was encountered
|
| + * @param errorCode the error code from Google Play Services
|
| + */
|
| @Override
|
| - public void run() {
|
| + protected final void handle(final Context context, final int errorCode) {
|
| + prepareToHandle(getActivity(), context, errorCode);
|
| Dialog dialog = GooglePlayServicesUtil.getErrorDialog(
|
| - mErrorCode, mActivity, mRequestCode, mOnCancelListener);
|
| + errorCode, getActivity(), getRequestCode(), getOnCancelListener());
|
| dialog.show();
|
| }
|
| }
|
|
|