diff -r 000000000000 -r 6474c204b198 mobile/android/base/fxa/activities/FxAccountSetupTask.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mobile/android/base/fxa/activities/FxAccountSetupTask.java Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,172 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko.fxa.activities; + +import java.io.UnsupportedEncodingException; +import java.util.concurrent.CountDownLatch; + +import org.mozilla.gecko.background.common.log.Logger; +import org.mozilla.gecko.background.fxa.FxAccountClient; +import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate; +import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse; +import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException; +import org.mozilla.gecko.background.fxa.PasswordStretcher; +import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.InnerRequestDelegate; + +import android.content.Context; +import android.os.AsyncTask; + +/** + * An AsyncTask wrapper around signing up for, and signing in to, a + * Firefox Account. + *

+ * It's strange to add explicit blocking to callback-threading code, but we do + * it here to take advantage of Android's built in support for background work. + * We really want to avoid making a threading mistake that brings down the whole + * process. + */ +abstract class FxAccountSetupTask extends AsyncTask> { + private static final String LOG_TAG = FxAccountSetupTask.class.getSimpleName(); + + public interface ProgressDisplay { + public void showProgress(); + public void dismissProgress(); + } + + protected final Context context; + protected final FxAccountClient client; + protected final ProgressDisplay progressDisplay; + + // Initialized lazily. + protected byte[] quickStretchedPW; + + // AsyncTask's are one-time-use, so final members are fine. + protected final CountDownLatch latch = new CountDownLatch(1); + protected final InnerRequestDelegate innerDelegate = new InnerRequestDelegate(latch); + + protected final RequestDelegate delegate; + + public FxAccountSetupTask(Context context, ProgressDisplay progressDisplay, FxAccountClient client, RequestDelegate delegate) { + this.context = context; + this.client = client; + this.delegate = delegate; + this.progressDisplay = progressDisplay; + } + + @Override + protected void onPreExecute() { + if (progressDisplay != null) { + progressDisplay.showProgress(); + } + } + + @Override + protected void onPostExecute(InnerRequestDelegate result) { + if (progressDisplay != null) { + progressDisplay.dismissProgress(); + } + + // We are on the UI thread, and need to invoke these callbacks here to allow UI updating. + if (innerDelegate.failure != null) { + delegate.handleFailure(innerDelegate.failure); + } else if (innerDelegate.exception != null) { + delegate.handleError(innerDelegate.exception); + } else { + delegate.handleSuccess(result.response); + } + } + + @Override + protected void onCancelled(InnerRequestDelegate result) { + if (progressDisplay != null) { + progressDisplay.dismissProgress(); + } + delegate.handleError(new IllegalStateException("Task was cancelled.")); + } + + protected static class InnerRequestDelegate implements RequestDelegate { + protected final CountDownLatch latch; + public T response = null; + public Exception exception = null; + public FxAccountClientRemoteException failure = null; + + protected InnerRequestDelegate(CountDownLatch latch) { + this.latch = latch; + } + + @Override + public void handleError(Exception e) { + Logger.error(LOG_TAG, "Got exception."); + this.exception = e; + latch.countDown(); + } + + @Override + public void handleFailure(FxAccountClientRemoteException e) { + Logger.warn(LOG_TAG, "Got failure."); + this.failure = e; + latch.countDown(); + } + + @Override + public void handleSuccess(T result) { + Logger.info(LOG_TAG, "Got success."); + this.response = result; + latch.countDown(); + } + } + + public static class FxAccountCreateAccountTask extends FxAccountSetupTask { + private static final String LOG_TAG = FxAccountCreateAccountTask.class.getSimpleName(); + + protected final byte[] emailUTF8; + protected final PasswordStretcher passwordStretcher; + + public FxAccountCreateAccountTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate delegate) throws UnsupportedEncodingException { + super(context, progressDisplay, client, delegate); + this.emailUTF8 = email.getBytes("UTF-8"); + this.passwordStretcher = passwordStretcher; + } + + @Override + protected InnerRequestDelegate doInBackground(Void... arg0) { + try { + client.createAccountAndGetKeys(emailUTF8, passwordStretcher, innerDelegate); + latch.await(); + return innerDelegate; + } catch (Exception e) { + Logger.error(LOG_TAG, "Got exception logging in.", e); + delegate.handleError(e); + } + return null; + } + } + + public static class FxAccountSignInTask extends FxAccountSetupTask { + protected static final String LOG_TAG = FxAccountSignInTask.class.getSimpleName(); + + protected final byte[] emailUTF8; + protected final PasswordStretcher passwordStretcher; + + public FxAccountSignInTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate delegate) throws UnsupportedEncodingException { + super(context, progressDisplay, client, delegate); + this.emailUTF8 = email.getBytes("UTF-8"); + this.passwordStretcher = passwordStretcher; + } + + @Override + protected InnerRequestDelegate doInBackground(Void... arg0) { + try { + client.loginAndGetKeys(emailUTF8, passwordStretcher, innerDelegate); + latch.await(); + return innerDelegate; + } catch (Exception e) { + Logger.error(LOG_TAG, "Got exception signing in.", e); + delegate.handleError(e); + } + return null; + } + } +}