|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 package org.mozilla.gecko.fxa.activities; |
|
6 |
|
7 import java.io.UnsupportedEncodingException; |
|
8 import java.util.concurrent.CountDownLatch; |
|
9 |
|
10 import org.mozilla.gecko.background.common.log.Logger; |
|
11 import org.mozilla.gecko.background.fxa.FxAccountClient; |
|
12 import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate; |
|
13 import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse; |
|
14 import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException; |
|
15 import org.mozilla.gecko.background.fxa.PasswordStretcher; |
|
16 import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.InnerRequestDelegate; |
|
17 |
|
18 import android.content.Context; |
|
19 import android.os.AsyncTask; |
|
20 |
|
21 /** |
|
22 * An <code>AsyncTask</code> wrapper around signing up for, and signing in to, a |
|
23 * Firefox Account. |
|
24 * <p> |
|
25 * It's strange to add explicit blocking to callback-threading code, but we do |
|
26 * it here to take advantage of Android's built in support for background work. |
|
27 * We really want to avoid making a threading mistake that brings down the whole |
|
28 * process. |
|
29 */ |
|
30 abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerRequestDelegate<T>> { |
|
31 private static final String LOG_TAG = FxAccountSetupTask.class.getSimpleName(); |
|
32 |
|
33 public interface ProgressDisplay { |
|
34 public void showProgress(); |
|
35 public void dismissProgress(); |
|
36 } |
|
37 |
|
38 protected final Context context; |
|
39 protected final FxAccountClient client; |
|
40 protected final ProgressDisplay progressDisplay; |
|
41 |
|
42 // Initialized lazily. |
|
43 protected byte[] quickStretchedPW; |
|
44 |
|
45 // AsyncTask's are one-time-use, so final members are fine. |
|
46 protected final CountDownLatch latch = new CountDownLatch(1); |
|
47 protected final InnerRequestDelegate<T> innerDelegate = new InnerRequestDelegate<T>(latch); |
|
48 |
|
49 protected final RequestDelegate<T> delegate; |
|
50 |
|
51 public FxAccountSetupTask(Context context, ProgressDisplay progressDisplay, FxAccountClient client, RequestDelegate<T> delegate) { |
|
52 this.context = context; |
|
53 this.client = client; |
|
54 this.delegate = delegate; |
|
55 this.progressDisplay = progressDisplay; |
|
56 } |
|
57 |
|
58 @Override |
|
59 protected void onPreExecute() { |
|
60 if (progressDisplay != null) { |
|
61 progressDisplay.showProgress(); |
|
62 } |
|
63 } |
|
64 |
|
65 @Override |
|
66 protected void onPostExecute(InnerRequestDelegate<T> result) { |
|
67 if (progressDisplay != null) { |
|
68 progressDisplay.dismissProgress(); |
|
69 } |
|
70 |
|
71 // We are on the UI thread, and need to invoke these callbacks here to allow UI updating. |
|
72 if (innerDelegate.failure != null) { |
|
73 delegate.handleFailure(innerDelegate.failure); |
|
74 } else if (innerDelegate.exception != null) { |
|
75 delegate.handleError(innerDelegate.exception); |
|
76 } else { |
|
77 delegate.handleSuccess(result.response); |
|
78 } |
|
79 } |
|
80 |
|
81 @Override |
|
82 protected void onCancelled(InnerRequestDelegate<T> result) { |
|
83 if (progressDisplay != null) { |
|
84 progressDisplay.dismissProgress(); |
|
85 } |
|
86 delegate.handleError(new IllegalStateException("Task was cancelled.")); |
|
87 } |
|
88 |
|
89 protected static class InnerRequestDelegate<T> implements RequestDelegate<T> { |
|
90 protected final CountDownLatch latch; |
|
91 public T response = null; |
|
92 public Exception exception = null; |
|
93 public FxAccountClientRemoteException failure = null; |
|
94 |
|
95 protected InnerRequestDelegate(CountDownLatch latch) { |
|
96 this.latch = latch; |
|
97 } |
|
98 |
|
99 @Override |
|
100 public void handleError(Exception e) { |
|
101 Logger.error(LOG_TAG, "Got exception."); |
|
102 this.exception = e; |
|
103 latch.countDown(); |
|
104 } |
|
105 |
|
106 @Override |
|
107 public void handleFailure(FxAccountClientRemoteException e) { |
|
108 Logger.warn(LOG_TAG, "Got failure."); |
|
109 this.failure = e; |
|
110 latch.countDown(); |
|
111 } |
|
112 |
|
113 @Override |
|
114 public void handleSuccess(T result) { |
|
115 Logger.info(LOG_TAG, "Got success."); |
|
116 this.response = result; |
|
117 latch.countDown(); |
|
118 } |
|
119 } |
|
120 |
|
121 public static class FxAccountCreateAccountTask extends FxAccountSetupTask<LoginResponse> { |
|
122 private static final String LOG_TAG = FxAccountCreateAccountTask.class.getSimpleName(); |
|
123 |
|
124 protected final byte[] emailUTF8; |
|
125 protected final PasswordStretcher passwordStretcher; |
|
126 |
|
127 public FxAccountCreateAccountTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException { |
|
128 super(context, progressDisplay, client, delegate); |
|
129 this.emailUTF8 = email.getBytes("UTF-8"); |
|
130 this.passwordStretcher = passwordStretcher; |
|
131 } |
|
132 |
|
133 @Override |
|
134 protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) { |
|
135 try { |
|
136 client.createAccountAndGetKeys(emailUTF8, passwordStretcher, innerDelegate); |
|
137 latch.await(); |
|
138 return innerDelegate; |
|
139 } catch (Exception e) { |
|
140 Logger.error(LOG_TAG, "Got exception logging in.", e); |
|
141 delegate.handleError(e); |
|
142 } |
|
143 return null; |
|
144 } |
|
145 } |
|
146 |
|
147 public static class FxAccountSignInTask extends FxAccountSetupTask<LoginResponse> { |
|
148 protected static final String LOG_TAG = FxAccountSignInTask.class.getSimpleName(); |
|
149 |
|
150 protected final byte[] emailUTF8; |
|
151 protected final PasswordStretcher passwordStretcher; |
|
152 |
|
153 public FxAccountSignInTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException { |
|
154 super(context, progressDisplay, client, delegate); |
|
155 this.emailUTF8 = email.getBytes("UTF-8"); |
|
156 this.passwordStretcher = passwordStretcher; |
|
157 } |
|
158 |
|
159 @Override |
|
160 protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) { |
|
161 try { |
|
162 client.loginAndGetKeys(emailUTF8, passwordStretcher, innerDelegate); |
|
163 latch.await(); |
|
164 return innerDelegate; |
|
165 } catch (Exception e) { |
|
166 Logger.error(LOG_TAG, "Got exception signing in.", e); |
|
167 delegate.handleError(e); |
|
168 } |
|
169 return null; |
|
170 } |
|
171 } |
|
172 } |