|
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.util.concurrent.Executor; |
|
8 import java.util.concurrent.Executors; |
|
9 |
|
10 import org.mozilla.gecko.R; |
|
11 import org.mozilla.gecko.background.common.log.Logger; |
|
12 import org.mozilla.gecko.background.fxa.FxAccountClient; |
|
13 import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate; |
|
14 import org.mozilla.gecko.background.fxa.FxAccountClient20; |
|
15 import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException; |
|
16 import org.mozilla.gecko.fxa.FirefoxAccounts; |
|
17 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; |
|
18 import org.mozilla.gecko.fxa.login.Engaged; |
|
19 import org.mozilla.gecko.fxa.login.State; |
|
20 import org.mozilla.gecko.fxa.login.State.Action; |
|
21 import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper; |
|
22 import org.mozilla.gecko.sync.setup.activities.ActivityUtils; |
|
23 |
|
24 import android.accounts.Account; |
|
25 import android.app.Activity; |
|
26 import android.content.Context; |
|
27 import android.os.Bundle; |
|
28 import android.view.View; |
|
29 import android.view.View.OnClickListener; |
|
30 import android.widget.TextView; |
|
31 import android.widget.Toast; |
|
32 |
|
33 /** |
|
34 * Activity which displays account created successfully screen to the user, and |
|
35 * starts them on the email verification path. |
|
36 */ |
|
37 public class FxAccountConfirmAccountActivity extends FxAccountAbstractActivity implements OnClickListener { |
|
38 private static final String LOG_TAG = FxAccountConfirmAccountActivity.class.getSimpleName(); |
|
39 |
|
40 // Set in onCreate. |
|
41 protected TextView verificationLinkTextView; |
|
42 protected View resendLink; |
|
43 |
|
44 // Set in onResume. |
|
45 protected AndroidFxAccount fxAccount; |
|
46 |
|
47 protected final InnerSyncStatusDelegate syncStatusDelegate = new InnerSyncStatusDelegate(); |
|
48 |
|
49 public FxAccountConfirmAccountActivity() { |
|
50 super(CANNOT_RESUME_WHEN_NO_ACCOUNTS_EXIST); |
|
51 } |
|
52 |
|
53 /** |
|
54 * {@inheritDoc} |
|
55 */ |
|
56 @Override |
|
57 public void onCreate(Bundle icicle) { |
|
58 Logger.debug(LOG_TAG, "onCreate(" + icicle + ")"); |
|
59 |
|
60 super.onCreate(icicle); |
|
61 setContentView(R.layout.fxaccount_confirm_account); |
|
62 |
|
63 verificationLinkTextView = (TextView) ensureFindViewById(null, R.id.verification_link_text, "verification link text"); |
|
64 resendLink = ensureFindViewById(null, R.id.resend_confirmation_email_link, "resend confirmation email link"); |
|
65 resendLink.setOnClickListener(this); |
|
66 |
|
67 View backToBrowsingButton = ensureFindViewById(null, R.id.button, "back to browsing button"); |
|
68 backToBrowsingButton.setOnClickListener(new OnClickListener() { |
|
69 @Override |
|
70 public void onClick(View v) { |
|
71 ActivityUtils.openURLInFennec(v.getContext(), null); |
|
72 setResult(Activity.RESULT_OK); |
|
73 finish(); |
|
74 } |
|
75 }); |
|
76 } |
|
77 |
|
78 @Override |
|
79 public void onResume() { |
|
80 super.onResume(); |
|
81 this.fxAccount = getAndroidFxAccount(); |
|
82 if (fxAccount == null) { |
|
83 Logger.warn(LOG_TAG, "Could not get Firefox Account."); |
|
84 setResult(RESULT_CANCELED); |
|
85 finish(); |
|
86 return; |
|
87 } |
|
88 |
|
89 FxAccountSyncStatusHelper.getInstance().startObserving(syncStatusDelegate); |
|
90 |
|
91 refresh(); |
|
92 |
|
93 fxAccount.requestSync(FirefoxAccounts.NOW); |
|
94 } |
|
95 |
|
96 @Override |
|
97 public void onPause() { |
|
98 super.onPause(); |
|
99 FxAccountSyncStatusHelper.getInstance().stopObserving(syncStatusDelegate); |
|
100 |
|
101 if (fxAccount != null) { |
|
102 fxAccount.requestSync(FirefoxAccounts.SOON); |
|
103 } |
|
104 } |
|
105 |
|
106 protected class InnerSyncStatusDelegate implements FirefoxAccounts.SyncStatusListener { |
|
107 protected final Runnable refreshRunnable = new Runnable() { |
|
108 @Override |
|
109 public void run() { |
|
110 refresh(); |
|
111 } |
|
112 }; |
|
113 |
|
114 @Override |
|
115 public Context getContext() { |
|
116 return FxAccountConfirmAccountActivity.this; |
|
117 } |
|
118 |
|
119 @Override |
|
120 public Account getAccount() { |
|
121 return fxAccount.getAndroidAccount(); |
|
122 } |
|
123 |
|
124 @Override |
|
125 public void onSyncStarted() { |
|
126 Logger.info(LOG_TAG, "Got sync started message; ignoring."); |
|
127 } |
|
128 |
|
129 @Override |
|
130 public void onSyncFinished() { |
|
131 if (fxAccount == null) { |
|
132 return; |
|
133 } |
|
134 Logger.info(LOG_TAG, "Got sync finished message; refreshing."); |
|
135 runOnUiThread(refreshRunnable); |
|
136 } |
|
137 } |
|
138 |
|
139 protected void refresh() { |
|
140 final State state = fxAccount.getState(); |
|
141 final Action neededAction = state.getNeededAction(); |
|
142 switch (neededAction) { |
|
143 case NeedsVerification: |
|
144 // This is what we're here to handle. |
|
145 break; |
|
146 case NeedsPassword: |
|
147 case NeedsUpgrade: |
|
148 case None: |
|
149 default: |
|
150 // We're not in the right place! Redirect to status. |
|
151 Logger.warn(LOG_TAG, "No need to verifiy Firefox Account that needs action " + neededAction.toString() + |
|
152 " (in state " + state.getStateLabel() + ")."); |
|
153 setResult(RESULT_CANCELED); |
|
154 this.redirectToActivity(FxAccountStatusActivity.class); |
|
155 return; |
|
156 } |
|
157 |
|
158 final String email = fxAccount.getEmail(); |
|
159 final String text = getResources().getString(R.string.fxaccount_confirm_account_verification_link, email); |
|
160 verificationLinkTextView.setText(text); |
|
161 |
|
162 boolean resendLinkShouldBeEnabled = ((Engaged) state).getSessionToken() != null; |
|
163 resendLink.setEnabled(resendLinkShouldBeEnabled); |
|
164 resendLink.setClickable(resendLinkShouldBeEnabled); |
|
165 } |
|
166 |
|
167 public static class FxAccountResendCodeTask extends FxAccountSetupTask<Void> { |
|
168 protected static final String LOG_TAG = FxAccountResendCodeTask.class.getSimpleName(); |
|
169 |
|
170 protected final byte[] sessionToken; |
|
171 |
|
172 public FxAccountResendCodeTask(Context context, byte[] sessionToken, FxAccountClient client, RequestDelegate<Void> delegate) { |
|
173 super(context, null, client, delegate); |
|
174 this.sessionToken = sessionToken; |
|
175 } |
|
176 |
|
177 @Override |
|
178 protected InnerRequestDelegate<Void> doInBackground(Void... arg0) { |
|
179 try { |
|
180 client.resendCode(sessionToken, innerDelegate); |
|
181 latch.await(); |
|
182 return innerDelegate; |
|
183 } catch (Exception e) { |
|
184 Logger.error(LOG_TAG, "Got exception signing in.", e); |
|
185 delegate.handleError(e); |
|
186 } |
|
187 return null; |
|
188 } |
|
189 } |
|
190 |
|
191 protected static class ResendCodeDelegate implements RequestDelegate<Void> { |
|
192 public final Context context; |
|
193 |
|
194 public ResendCodeDelegate(Context context) { |
|
195 this.context = context; |
|
196 } |
|
197 |
|
198 @Override |
|
199 public void handleError(Exception e) { |
|
200 Logger.warn(LOG_TAG, "Got exception requesting fresh confirmation link; ignoring.", e); |
|
201 Toast.makeText(context, R.string.fxaccount_confirm_account_verification_link_not_sent, Toast.LENGTH_LONG).show(); |
|
202 } |
|
203 |
|
204 @Override |
|
205 public void handleFailure(FxAccountClientRemoteException e) { |
|
206 handleError(e); |
|
207 } |
|
208 |
|
209 @Override |
|
210 public void handleSuccess(Void result) { |
|
211 Toast.makeText(context, R.string.fxaccount_confirm_account_verification_link_sent, Toast.LENGTH_SHORT).show(); |
|
212 } |
|
213 } |
|
214 |
|
215 public static void resendCode(Context context, AndroidFxAccount fxAccount) { |
|
216 RequestDelegate<Void> delegate = new ResendCodeDelegate(context); |
|
217 |
|
218 byte[] sessionToken; |
|
219 try { |
|
220 sessionToken = ((Engaged) fxAccount.getState()).getSessionToken(); |
|
221 } catch (Exception e) { |
|
222 delegate.handleError(e); |
|
223 return; |
|
224 } |
|
225 if (sessionToken == null) { |
|
226 delegate.handleError(new IllegalStateException("sessionToken should not be null")); |
|
227 return; |
|
228 } |
|
229 |
|
230 Executor executor = Executors.newSingleThreadExecutor(); |
|
231 FxAccountClient client = new FxAccountClient20(fxAccount.getAccountServerURI(), executor); |
|
232 new FxAccountResendCodeTask(context, sessionToken, client, delegate).execute(); |
|
233 } |
|
234 |
|
235 @Override |
|
236 public void onClick(View v) { |
|
237 resendCode(this, fxAccount); |
|
238 } |
|
239 } |