1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/fxa/activities/FxAccountSetupTask.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,172 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +package org.mozilla.gecko.fxa.activities; 1.9 + 1.10 +import java.io.UnsupportedEncodingException; 1.11 +import java.util.concurrent.CountDownLatch; 1.12 + 1.13 +import org.mozilla.gecko.background.common.log.Logger; 1.14 +import org.mozilla.gecko.background.fxa.FxAccountClient; 1.15 +import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate; 1.16 +import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse; 1.17 +import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException; 1.18 +import org.mozilla.gecko.background.fxa.PasswordStretcher; 1.19 +import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.InnerRequestDelegate; 1.20 + 1.21 +import android.content.Context; 1.22 +import android.os.AsyncTask; 1.23 + 1.24 +/** 1.25 + * An <code>AsyncTask</code> wrapper around signing up for, and signing in to, a 1.26 + * Firefox Account. 1.27 + * <p> 1.28 + * It's strange to add explicit blocking to callback-threading code, but we do 1.29 + * it here to take advantage of Android's built in support for background work. 1.30 + * We really want to avoid making a threading mistake that brings down the whole 1.31 + * process. 1.32 + */ 1.33 +abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerRequestDelegate<T>> { 1.34 + private static final String LOG_TAG = FxAccountSetupTask.class.getSimpleName(); 1.35 + 1.36 + public interface ProgressDisplay { 1.37 + public void showProgress(); 1.38 + public void dismissProgress(); 1.39 + } 1.40 + 1.41 + protected final Context context; 1.42 + protected final FxAccountClient client; 1.43 + protected final ProgressDisplay progressDisplay; 1.44 + 1.45 + // Initialized lazily. 1.46 + protected byte[] quickStretchedPW; 1.47 + 1.48 + // AsyncTask's are one-time-use, so final members are fine. 1.49 + protected final CountDownLatch latch = new CountDownLatch(1); 1.50 + protected final InnerRequestDelegate<T> innerDelegate = new InnerRequestDelegate<T>(latch); 1.51 + 1.52 + protected final RequestDelegate<T> delegate; 1.53 + 1.54 + public FxAccountSetupTask(Context context, ProgressDisplay progressDisplay, FxAccountClient client, RequestDelegate<T> delegate) { 1.55 + this.context = context; 1.56 + this.client = client; 1.57 + this.delegate = delegate; 1.58 + this.progressDisplay = progressDisplay; 1.59 + } 1.60 + 1.61 + @Override 1.62 + protected void onPreExecute() { 1.63 + if (progressDisplay != null) { 1.64 + progressDisplay.showProgress(); 1.65 + } 1.66 + } 1.67 + 1.68 + @Override 1.69 + protected void onPostExecute(InnerRequestDelegate<T> result) { 1.70 + if (progressDisplay != null) { 1.71 + progressDisplay.dismissProgress(); 1.72 + } 1.73 + 1.74 + // We are on the UI thread, and need to invoke these callbacks here to allow UI updating. 1.75 + if (innerDelegate.failure != null) { 1.76 + delegate.handleFailure(innerDelegate.failure); 1.77 + } else if (innerDelegate.exception != null) { 1.78 + delegate.handleError(innerDelegate.exception); 1.79 + } else { 1.80 + delegate.handleSuccess(result.response); 1.81 + } 1.82 + } 1.83 + 1.84 + @Override 1.85 + protected void onCancelled(InnerRequestDelegate<T> result) { 1.86 + if (progressDisplay != null) { 1.87 + progressDisplay.dismissProgress(); 1.88 + } 1.89 + delegate.handleError(new IllegalStateException("Task was cancelled.")); 1.90 + } 1.91 + 1.92 + protected static class InnerRequestDelegate<T> implements RequestDelegate<T> { 1.93 + protected final CountDownLatch latch; 1.94 + public T response = null; 1.95 + public Exception exception = null; 1.96 + public FxAccountClientRemoteException failure = null; 1.97 + 1.98 + protected InnerRequestDelegate(CountDownLatch latch) { 1.99 + this.latch = latch; 1.100 + } 1.101 + 1.102 + @Override 1.103 + public void handleError(Exception e) { 1.104 + Logger.error(LOG_TAG, "Got exception."); 1.105 + this.exception = e; 1.106 + latch.countDown(); 1.107 + } 1.108 + 1.109 + @Override 1.110 + public void handleFailure(FxAccountClientRemoteException e) { 1.111 + Logger.warn(LOG_TAG, "Got failure."); 1.112 + this.failure = e; 1.113 + latch.countDown(); 1.114 + } 1.115 + 1.116 + @Override 1.117 + public void handleSuccess(T result) { 1.118 + Logger.info(LOG_TAG, "Got success."); 1.119 + this.response = result; 1.120 + latch.countDown(); 1.121 + } 1.122 + } 1.123 + 1.124 + public static class FxAccountCreateAccountTask extends FxAccountSetupTask<LoginResponse> { 1.125 + private static final String LOG_TAG = FxAccountCreateAccountTask.class.getSimpleName(); 1.126 + 1.127 + protected final byte[] emailUTF8; 1.128 + protected final PasswordStretcher passwordStretcher; 1.129 + 1.130 + public FxAccountCreateAccountTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException { 1.131 + super(context, progressDisplay, client, delegate); 1.132 + this.emailUTF8 = email.getBytes("UTF-8"); 1.133 + this.passwordStretcher = passwordStretcher; 1.134 + } 1.135 + 1.136 + @Override 1.137 + protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) { 1.138 + try { 1.139 + client.createAccountAndGetKeys(emailUTF8, passwordStretcher, innerDelegate); 1.140 + latch.await(); 1.141 + return innerDelegate; 1.142 + } catch (Exception e) { 1.143 + Logger.error(LOG_TAG, "Got exception logging in.", e); 1.144 + delegate.handleError(e); 1.145 + } 1.146 + return null; 1.147 + } 1.148 + } 1.149 + 1.150 + public static class FxAccountSignInTask extends FxAccountSetupTask<LoginResponse> { 1.151 + protected static final String LOG_TAG = FxAccountSignInTask.class.getSimpleName(); 1.152 + 1.153 + protected final byte[] emailUTF8; 1.154 + protected final PasswordStretcher passwordStretcher; 1.155 + 1.156 + public FxAccountSignInTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException { 1.157 + super(context, progressDisplay, client, delegate); 1.158 + this.emailUTF8 = email.getBytes("UTF-8"); 1.159 + this.passwordStretcher = passwordStretcher; 1.160 + } 1.161 + 1.162 + @Override 1.163 + protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) { 1.164 + try { 1.165 + client.loginAndGetKeys(emailUTF8, passwordStretcher, innerDelegate); 1.166 + latch.await(); 1.167 + return innerDelegate; 1.168 + } catch (Exception e) { 1.169 + Logger.error(LOG_TAG, "Got exception signing in.", e); 1.170 + delegate.handleError(e); 1.171 + } 1.172 + return null; 1.173 + } 1.174 + } 1.175 +}