Bug 965366 - Make Firefox Account's StatusActivity checkboxes live. r=rnewman

This commit is contained in:
Nick Alexander 2014-01-30 17:58:56 -08:00
parent cbe3deed81
commit c07cdccfb4
15 changed files with 335 additions and 166 deletions

View File

@ -6,6 +6,7 @@ package org.mozilla.gecko.fxa.activities;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.background.fxa.FxAccountAgeLockoutHelper;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
import org.mozilla.gecko.fxa.authenticator.FxAccountAuthenticator;
import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
@ -130,4 +131,15 @@ public abstract class FxAccountAbstractActivity extends Activity {
}
});
}
/**
* Helper to fetch (unique) Android Firefox Account if one exists, or return null.
*/
protected AndroidFxAccount getAndroidFxAccount() {
Account accounts[] = FxAccountAuthenticator.getFirefoxAccounts(this);
if (accounts.length < 1 || accounts[0] == null) {
return null;
}
return new AndroidFxAccount(this, accounts[0]);
}
}

View File

@ -189,9 +189,7 @@ abstract public class FxAccountAbstractSetupActivity extends FxAccountAbstractAc
successIntent = new Intent(this, FxAccountVerifiedAccountActivity.class);
} else {
successIntent = new Intent(this, FxAccountConfirmAccountActivity.class);
successIntent.putExtra("sessionToken", result.sessionToken);
}
successIntent.putExtra("email", email);
// Per http://stackoverflow.com/a/8992365, this triggers a known bug with
// the soft keyboard not being shown for the started activity. Why, Android, why?
successIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);

View File

@ -13,9 +13,11 @@ import org.mozilla.gecko.background.fxa.FxAccountClient;
import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate;
import org.mozilla.gecko.background.fxa.FxAccountClient20;
import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException;
import org.mozilla.gecko.fxa.FxAccountConstants;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
import org.mozilla.gecko.fxa.login.Engaged;
import org.mozilla.gecko.fxa.login.State;
import org.mozilla.gecko.fxa.login.State.StateLabel;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
@ -27,31 +29,18 @@ import android.widget.Toast;
* Activity which displays account created successfully screen to the user, and
* starts them on the email verification path.
*/
public class FxAccountConfirmAccountActivity extends Activity implements OnClickListener {
protected static final String LOG_TAG = FxAccountConfirmAccountActivity.class.getSimpleName();
public class FxAccountConfirmAccountActivity extends FxAccountAbstractActivity implements OnClickListener {
private static final String LOG_TAG = FxAccountConfirmAccountActivity.class.getSimpleName();
protected byte[] sessionToken;
// Set in onCreate.
protected TextView verificationLinkTextView;
protected View resendLink;
/**
* Helper to find view or error if it is missing.
*
* @param id of view to find.
* @param description to print in error.
* @return non-null <code>View</code> instance.
*/
public View ensureFindViewById(View v, int id, String description) {
View view;
if (v != null) {
view = v.findViewById(id);
} else {
view = findViewById(id);
}
if (view == null) {
String message = "Could not find view " + description + ".";
Logger.error(LOG_TAG, message);
throw new RuntimeException(message);
}
return view;
// Set in onResume.
protected AndroidFxAccount fxAccount;
public FxAccountConfirmAccountActivity() {
super(CANNOT_RESUME_WHEN_NO_ACCOUNTS_EXIST);
}
/**
@ -64,21 +53,36 @@ public class FxAccountConfirmAccountActivity extends Activity implements OnClick
super.onCreate(icicle);
setContentView(R.layout.fxaccount_confirm_account);
if (getIntent() != null && getIntent().getExtras() != null) {
Bundle extras = getIntent().getExtras();
TextView verificationLinkTextView = (TextView) ensureFindViewById(null, R.id.verification_link_text, "verification link text");
String text = getResources().getString(R.string.fxaccount_confirm_account_verification_link, extras.getString("email"));
verificationLinkTextView.setText(text);
sessionToken = extras.getByteArray("sessionToken");
}
View resendLink = ensureFindViewById(null, R.id.resend_confirmation_email_link, "resend confirmation email link");
verificationLinkTextView = (TextView) ensureFindViewById(null, R.id.verification_link_text, "verification link text");
resendLink = ensureFindViewById(null, R.id.resend_confirmation_email_link, "resend confirmation email link");
resendLink.setOnClickListener(this);
}
if (sessionToken == null) {
resendLink.setEnabled(false);
resendLink.setClickable(false);
@Override
public void onResume() {
super.onResume();
this.fxAccount = getAndroidFxAccount();
if (fxAccount == null) {
Logger.warn(LOG_TAG, "Could not get Firefox Account.");
setResult(RESULT_CANCELED);
finish();
return;
}
State state = fxAccount.getState();
if (state.getStateLabel() != StateLabel.Engaged) {
Logger.warn(LOG_TAG, "Cannot confirm Firefox Account in state: " + state.getStateLabel());
setResult(RESULT_CANCELED);
finish();
return;
}
final String email = fxAccount.getEmail();
final String text = getResources().getString(R.string.fxaccount_confirm_account_verification_link, email);
verificationLinkTextView.setText(text);
boolean resendLinkShouldBeEnabled = ((Engaged) state).getSessionToken() != null;
resendLink.setEnabled(resendLinkShouldBeEnabled);
resendLink.setClickable(resendLinkShouldBeEnabled);
}
public static class FxAccountResendCodeTask extends FxAccountSetupTask<Void> {
@ -105,11 +109,17 @@ public class FxAccountConfirmAccountActivity extends Activity implements OnClick
}
}
protected class ResendCodeDelegate implements RequestDelegate<Void> {
protected static class ResendCodeDelegate implements RequestDelegate<Void> {
public final Context context;
public ResendCodeDelegate(Context context) {
this.context = context;
}
@Override
public void handleError(Exception e) {
Logger.warn(LOG_TAG, "Got exception requesting fresh confirmation link; ignoring.", e);
Toast.makeText(getApplicationContext(), R.string.fxaccount_confirm_account_verification_link_not_sent, Toast.LENGTH_LONG).show();
Toast.makeText(context, R.string.fxaccount_confirm_account_verification_link_not_sent, Toast.LENGTH_LONG).show();
}
@Override
@ -119,20 +129,32 @@ public class FxAccountConfirmAccountActivity extends Activity implements OnClick
@Override
public void handleSuccess(Void result) {
Toast.makeText(getApplicationContext(), R.string.fxaccount_confirm_account_verification_link_sent, Toast.LENGTH_SHORT).show();
Toast.makeText(context, R.string.fxaccount_confirm_account_verification_link_sent, Toast.LENGTH_SHORT).show();
}
}
protected void resendCode(byte[] sessionToken) {
String serverURI = FxAccountConstants.DEFAULT_AUTH_SERVER_ENDPOINT;
RequestDelegate<Void> delegate = new ResendCodeDelegate();
public static void resendCode(Context context, AndroidFxAccount fxAccount) {
RequestDelegate<Void> delegate = new ResendCodeDelegate(context);
byte[] sessionToken;
try {
sessionToken = ((Engaged) fxAccount.getState()).getSessionToken();
} catch (Exception e) {
delegate.handleError(e);
return;
}
if (sessionToken == null) {
delegate.handleError(new IllegalStateException("sessionToken should not be null"));
return;
}
Executor executor = Executors.newSingleThreadExecutor();
FxAccountClient client = new FxAccountClient20(serverURI, executor);
new FxAccountResendCodeTask(this, sessionToken, client, delegate).execute();
FxAccountClient client = new FxAccountClient20(fxAccount.getAccountServerURI(), executor);
new FxAccountResendCodeTask(context, sessionToken, client, delegate).execute();
}
@Override
public void onClick(View v) {
resendCode(sessionToken);
resendCode(this, fxAccount);
}
}

View File

@ -4,38 +4,67 @@
package org.mozilla.gecko.fxa.activities;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.mozilla.gecko.R;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.fxa.FxAccountConstants;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
import org.mozilla.gecko.fxa.authenticator.FxAccountAuthenticator;
import org.mozilla.gecko.fxa.login.Married;
import org.mozilla.gecko.fxa.login.State;
import org.mozilla.gecko.sync.SyncConfiguration;
import android.accounts.Account;
import android.content.ContentResolver;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
import android.widget.ViewFlipper;
/**
* Activity which displays account status.
*/
public class FxAccountStatusActivity extends FxAccountAbstractActivity {
protected static final String LOG_TAG = FxAccountStatusActivity.class.getSimpleName();
public class FxAccountStatusActivity extends FxAccountAbstractActivity implements OnClickListener {
private static final String LOG_TAG = FxAccountStatusActivity.class.getSimpleName();
// When a checkbox is toggled, wait 5 seconds (for other checkbox actions)
// before trying to sync. Should we quit the activity before the sync request
// happens, that's okay: the runnable will run if the UI thread is still
// around to service it, and since we're not updating any UI, we'll just
// schedule the sync as usual. See also comment below about garbage
// collection.
private static final long DELAY_IN_MILLISECONDS_BEFORE_REQUESTING_SYNC = 5 * 1000;
// Set in onCreate.
protected TextView syncStatusTextView;
protected ViewFlipper connectionStatusViewFlipper;
protected View connectionStatusUnverifiedView;
protected View connectionStatusSignInView;
protected TextView emailTextView;
protected CheckBox bookmarksCheckBox;
protected CheckBox historyCheckBox;
protected CheckBox passwordsCheckBox;
protected CheckBox tabsCheckBox;
// Used to post delayed sync requests.
protected Handler handler;
// Set in onResume.
protected AndroidFxAccount fxAccount;
// Member variable so that re-posting pushes back the already posted instance.
// This Runnable references the fxAccount above, so it is not specific a
// single account. (That is, it does not capture a single account instance.)
protected Runnable requestSyncRunnable;
public FxAccountStatusActivity() {
super(CANNOT_RESUME_WHEN_NO_ACCOUNTS_EXIST);
}
@ -58,8 +87,42 @@ public class FxAccountStatusActivity extends FxAccountAbstractActivity {
launchActivityOnClick(connectionStatusSignInView, FxAccountUpdateCredentialsActivity.class);
connectionStatusUnverifiedView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
FxAccountConfirmAccountActivity.resendCode(getApplicationContext(), fxAccount);
launchActivity(FxAccountConfirmAccountActivity.class);
}
});
emailTextView = (TextView) findViewById(R.id.email);
bookmarksCheckBox = (CheckBox) findViewById(R.id.bookmarks_checkbox);
historyCheckBox = (CheckBox) findViewById(R.id.history_checkbox);
passwordsCheckBox = (CheckBox) findViewById(R.id.passwords_checkbox);
tabsCheckBox = (CheckBox) findViewById(R.id.tabs_checkbox);
bookmarksCheckBox.setOnClickListener(this);
historyCheckBox.setOnClickListener(this);
passwordsCheckBox.setOnClickListener(this);
tabsCheckBox.setOnClickListener(this);
handler = new Handler(); // Attached to current (UI) thread.
// Runnable is not specific to one Firefox Account. This runnable will keep
// a reference to this activity alive, but we expect posted runnables to be
// serviced very quickly, so this is not an issue.
requestSyncRunnable = new Runnable() {
@Override
public void run() {
if (fxAccount == null) {
return;
}
Logger.info(LOG_TAG, "Requesting a sync sometime soon.");
// Request a sync, but not necessarily an immediate sync.
ContentResolver.requestSync(fxAccount.getAndroidAccount(), BrowserContract.AUTHORITY, Bundle.EMPTY);
// SyncAdapter.requestImmediateSync(fxAccount.getAndroidAccount(), null);
}
};
if (FxAccountConstants.LOG_PERSONAL_INFORMATION) {
createDebugButtons();
}
@ -68,41 +131,55 @@ public class FxAccountStatusActivity extends FxAccountAbstractActivity {
@Override
public void onResume() {
super.onResume();
this.fxAccount = getAndroidFxAccount();
if (fxAccount == null) {
Logger.warn(LOG_TAG, "Could not get Firefox Account.");
setResult(RESULT_CANCELED);
finish();
return;
}
refresh();
}
protected void setCheckboxesEnabled(boolean enabled) {
bookmarksCheckBox.setEnabled(enabled);
historyCheckBox.setEnabled(enabled);
passwordsCheckBox.setEnabled(enabled);
tabsCheckBox.setEnabled(enabled);
}
protected void showNeedsUpgrade() {
syncStatusTextView.setText(R.string.fxaccount_status_sync);
connectionStatusViewFlipper.setVisibility(View.VISIBLE);
connectionStatusViewFlipper.setDisplayedChild(0);
setCheckboxesEnabled(false);
}
protected void showNeedsPassword() {
syncStatusTextView.setText(R.string.fxaccount_status_sync);
connectionStatusViewFlipper.setVisibility(View.VISIBLE);
connectionStatusViewFlipper.setDisplayedChild(1);
setCheckboxesEnabled(false);
}
protected void showNeedsVerification() {
syncStatusTextView.setText(R.string.fxaccount_status_sync);
connectionStatusViewFlipper.setVisibility(View.VISIBLE);
connectionStatusViewFlipper.setDisplayedChild(2);
setCheckboxesEnabled(false);
}
protected void showConnected() {
syncStatusTextView.setText(R.string.fxaccount_status_sync_enabled);
connectionStatusViewFlipper.setVisibility(View.GONE);
setCheckboxesEnabled(true);
}
protected void refresh(Account account) {
if (account == null) {
redirectToActivity(FxAccountGetStartedActivity.class);
return;
}
emailTextView.setText(account.name);
protected void refresh() {
emailTextView.setText(fxAccount.getEmail());
// Interrogate the Firefox Account's state.
AndroidFxAccount fxAccount = new AndroidFxAccount(this, account);
State state = fxAccount.getState();
switch (state.getNeededAction()) {
case NeedsUpgrade:
@ -117,17 +194,82 @@ public class FxAccountStatusActivity extends FxAccountAbstractActivity {
default:
showConnected();
}
updateSelectedEngines();
}
protected void refresh() {
Account accounts[] = FxAccountAuthenticator.getFirefoxAccounts(this);
if (accounts.length < 1) {
refresh(null);
protected void updateSelectedEngines() {
try {
SharedPreferences syncPrefs = fxAccount.getSyncPrefs();
Map<String, Boolean> engines = SyncConfiguration.getUserSelectedEngines(syncPrefs);
if (engines != null) {
bookmarksCheckBox.setChecked(engines.containsKey("bookmarks") && engines.get("bookmarks"));
historyCheckBox.setChecked(engines.containsKey("history") && engines.get("history"));
passwordsCheckBox.setChecked(engines.containsKey("passwords") && engines.get("passwords"));
tabsCheckBox.setChecked(engines.containsKey("tabs") && engines.get("tabs"));
return;
}
// We don't have user specified preferences. Perhaps we have seen a meta/global?
Set<String> enabledNames = SyncConfiguration.getEnabledEngineNames(syncPrefs);
if (enabledNames != null) {
bookmarksCheckBox.setChecked(enabledNames.contains("bookmarks"));
historyCheckBox.setChecked(enabledNames.contains("history"));
passwordsCheckBox.setChecked(enabledNames.contains("passwords"));
tabsCheckBox.setChecked(enabledNames.contains("tabs"));
return;
}
// Okay, we don't have userSelectedEngines or enabledEngines. That means
// the user hasn't specified to begin with, we haven't specified here, and
// we haven't already seen, Sync engines. We don't know our state, so
// let's check everything (the default) and disable everything.
bookmarksCheckBox.setChecked(true);
historyCheckBox.setChecked(true);
passwordsCheckBox.setChecked(true);
tabsCheckBox.setChecked(true);
setCheckboxesEnabled(false);
} catch (Exception e) {
Logger.warn(LOG_TAG, "Got exception getting engines to select; ignoring.", e);
return;
}
refresh(accounts[0]);
}
@Override
public void onClick(View view) {
if (view == bookmarksCheckBox ||
view == historyCheckBox ||
view == passwordsCheckBox ||
view == tabsCheckBox) {
saveEngineSelections();
}
}
protected void saveEngineSelections() {
Map<String, Boolean> engineSelections = new HashMap<String, Boolean>();
engineSelections.put("bookmarks", bookmarksCheckBox.isChecked());
engineSelections.put("history", historyCheckBox.isChecked());
engineSelections.put("passwords", passwordsCheckBox.isChecked());
engineSelections.put("tabs", tabsCheckBox.isChecked());
Logger.info(LOG_TAG, "Persisting engine selections: " + engineSelections.toString());
try {
// No GlobalSession.config, so store directly to prefs. We'd like to do
// this on a background thread to avoid IO on the main thread and strict
// mode warnings, but all in good time.
SyncConfiguration.storeSelectedEnginesToPrefs(fxAccount.getSyncPrefs(), engineSelections);
requestDelayedSync();
} catch (Exception e) {
Logger.warn(LOG_TAG, "Got exception persisting selected engines; ignoring.", e);
return;
}
}
protected void requestDelayedSync() {
Logger.info(LOG_TAG, "Posting a delayed request for a sync sometime soon.");
handler.removeCallbacks(requestSyncRunnable);
handler.postDelayed(requestSyncRunnable, DELAY_IN_MILLISECONDS_BEFORE_REQUESTING_SYNC);
}
protected void createDebugButtons() {
if (!FxAccountConstants.LOG_PERSONAL_INFORMATION) {
@ -141,7 +283,7 @@ public class FxAccountStatusActivity extends FxAccountAbstractActivity {
final LinearLayout debugButtonsView = new LinearLayout(this);
debugButtonsView.setOrientation(LinearLayout.VERTICAL);
debugButtonsView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
debugButtonsView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
existingUserView.addView(debugButtonsView, existingUserView.getChildCount());
Button button;
@ -163,13 +305,7 @@ public class FxAccountStatusActivity extends FxAccountAbstractActivity {
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Logger.info(LOG_TAG, "Dumping account details.");
Account accounts[] = FxAccountAuthenticator.getFirefoxAccounts(FxAccountStatusActivity.this);
if (accounts.length < 1) {
return;
}
AndroidFxAccount account = new AndroidFxAccount(FxAccountStatusActivity.this, accounts[0]);
account.dump();
fxAccount.dump();
}
});
@ -180,13 +316,9 @@ public class FxAccountStatusActivity extends FxAccountAbstractActivity {
@Override
public void onClick(View v) {
Logger.info(LOG_TAG, "Syncing.");
Account accounts[] = FxAccountAuthenticator.getFirefoxAccounts(FxAccountStatusActivity.this);
if (accounts.length < 1) {
return;
}
final Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
ContentResolver.requestSync(accounts[0], BrowserContract.AUTHORITY, extras);
ContentResolver.requestSync(fxAccount.getAndroidAccount(), BrowserContract.AUTHORITY, extras);
// No sense refreshing, since the sync will complete in the future.
}
});
@ -197,16 +329,11 @@ public class FxAccountStatusActivity extends FxAccountAbstractActivity {
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Account accounts[] = FxAccountAuthenticator.getFirefoxAccounts(FxAccountStatusActivity.this);
if (accounts.length < 1) {
return;
}
AndroidFxAccount account = new AndroidFxAccount(FxAccountStatusActivity.this, accounts[0]);
State state = account.getState();
State state = fxAccount.getState();
try {
Married married = (Married) state;
Logger.info(LOG_TAG, "Moving to Cohabiting state: Forgetting certificate.");
account.setState(married.makeCohabitingState());
fxAccount.setState(married.makeCohabitingState());
refresh();
} catch (ClassCastException e) {
Logger.info(LOG_TAG, "Not in Married state; can't forget certificate.");
@ -222,13 +349,8 @@ public class FxAccountStatusActivity extends FxAccountAbstractActivity {
@Override
public void onClick(View v) {
Logger.info(LOG_TAG, "Moving to Separated state: Forgetting password.");
Account accounts[] = FxAccountAuthenticator.getFirefoxAccounts(FxAccountStatusActivity.this);
if (accounts.length < 1) {
return;
}
AndroidFxAccount account = new AndroidFxAccount(FxAccountStatusActivity.this, accounts[0]);
State state = account.getState();
account.setState(state.makeSeparatedState());
State state = fxAccount.getState();
fxAccount.setState(state.makeSeparatedState());
refresh();
}
});
@ -240,13 +362,8 @@ public class FxAccountStatusActivity extends FxAccountAbstractActivity {
@Override
public void onClick(View v) {
Logger.info(LOG_TAG, "Moving to Doghouse state: Requiring upgrade.");
Account accounts[] = FxAccountAuthenticator.getFirefoxAccounts(FxAccountStatusActivity.this);
if (accounts.length < 1) {
return;
}
AndroidFxAccount account = new AndroidFxAccount(FxAccountStatusActivity.this, accounts[0]);
State state = account.getState();
account.setState(state.makeDoghouseState());
State state = fxAccount.getState();
fxAccount.setState(state.makeDoghouseState());
refresh();
}
});

View File

@ -20,13 +20,10 @@ import org.mozilla.gecko.background.fxa.QuickPasswordStretcher;
import org.mozilla.gecko.fxa.FxAccountConstants;
import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.FxAccountSignInTask;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
import org.mozilla.gecko.fxa.authenticator.FxAccountAuthenticator;
import org.mozilla.gecko.fxa.login.Engaged;
import org.mozilla.gecko.fxa.login.Separated;
import org.mozilla.gecko.fxa.login.State;
import org.mozilla.gecko.fxa.login.State.StateLabel;
import android.accounts.Account;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
@ -42,7 +39,6 @@ public class FxAccountUpdateCredentialsActivity extends FxAccountAbstractSetupAc
protected static final String LOG_TAG = FxAccountUpdateCredentialsActivity.class.getSimpleName();
protected AndroidFxAccount fxAccount;
protected Separated accountState;
public FxAccountUpdateCredentialsActivity() {
// We want to share code with the other setup activities, but this activity
@ -84,29 +80,21 @@ public class FxAccountUpdateCredentialsActivity extends FxAccountAbstractSetupAc
@Override
public void onResume() {
super.onResume();
Account accounts[] = FxAccountAuthenticator.getFirefoxAccounts(this);
if (accounts.length < 1 || accounts[0] == null) {
Logger.warn(LOG_TAG, "No Android accounts.");
setResult(RESULT_CANCELED);
finish();
return;
}
this.fxAccount = new AndroidFxAccount(this, accounts[0]);
this.fxAccount = getAndroidFxAccount();
if (fxAccount == null) {
Logger.warn(LOG_TAG, "Could not get Firefox Account from Android account.");
Logger.warn(LOG_TAG, "Could not get Firefox Account.");
setResult(RESULT_CANCELED);
finish();
return;
}
State state = fxAccount.getState();
if (state.getStateLabel() != StateLabel.Separated) {
Logger.warn(LOG_TAG, "Could not get state from Firefox Account.");
Logger.warn(LOG_TAG, "Cannot update credentials from Firefox Account in state: " + state.getStateLabel());
setResult(RESULT_CANCELED);
finish();
return;
}
this.accountState = (Separated) state;
emailEdit.setText(fxAccount.getAndroidAccount().name);
emailEdit.setText(fxAccount.getEmail());
}
protected class UpdateCredentialsDelegate implements RequestDelegate<LoginResponse> {
@ -165,7 +153,7 @@ public class FxAccountUpdateCredentialsActivity extends FxAccountAbstractSetupAc
}
public void updateCredentials(String email, String password) {
String serverURI = FxAccountConstants.DEFAULT_AUTH_SERVER_ENDPOINT;
String serverURI = fxAccount.getAccountServerURI();
Executor executor = Executors.newSingleThreadExecutor();
FxAccountClient client = new FxAccountClient20(serverURI, executor);
PasswordStretcher passwordStretcher = new QuickPasswordStretcher(password);

View File

@ -6,40 +6,24 @@ package org.mozilla.gecko.fxa.activities;
import org.mozilla.gecko.R;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
import org.mozilla.gecko.fxa.login.State;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
/**
* Activity which displays "Account verified" success screen.
*/
public class FxAccountVerifiedAccountActivity extends Activity {
protected static final String LOG_TAG = FxAccountVerifiedAccountActivity.class.getSimpleName();
public class FxAccountVerifiedAccountActivity extends FxAccountAbstractActivity {
private static final String LOG_TAG = FxAccountVerifiedAccountActivity.class.getSimpleName();
protected AndroidFxAccount fxAccount;
protected TextView emailText;
/**
* Helper to find view or error if it is missing.
*
* @param id of view to find.
* @param description to print in error.
* @return non-null <code>View</code> instance.
*/
public View ensureFindViewById(View v, int id, String description) {
View view;
if (v != null) {
view = v.findViewById(id);
} else {
view = findViewById(id);
}
if (view == null) {
String message = "Could not find view " + description + ".";
Logger.error(LOG_TAG, message);
throw new RuntimeException(message);
}
return view;
public FxAccountVerifiedAccountActivity() {
super(CANNOT_RESUME_WHEN_NO_ACCOUNTS_EXIST);
}
/**
@ -53,8 +37,25 @@ public class FxAccountVerifiedAccountActivity extends Activity {
setContentView(R.layout.fxaccount_account_verified);
emailText = (TextView) ensureFindViewById(null, R.id.email, "email text");
if (getIntent() != null && getIntent().getExtras() != null) {
emailText.setText(getIntent().getStringExtra("email"));
}
@Override
public void onResume() {
super.onResume();
this.fxAccount = getAndroidFxAccount();
if (fxAccount == null) {
Logger.warn(LOG_TAG, "Could not get Firefox Account.");
setResult(RESULT_CANCELED);
finish();
return;
}
State state = fxAccount.getState();
if (!state.verified) {
Logger.warn(LOG_TAG, "Firefox Account is not verified; not displaying verified account activity.");
setResult(RESULT_CANCELED);
finish();
return;
}
emailText.setText(fxAccount.getEmail());
}
}

View File

@ -371,4 +371,16 @@ public class AndroidFxAccount {
FxAccountConstants.pii(LOG_TAG, key + ": " + o.get(key));
}
}
/**
* Return the Firefox Account's local email address.
* <p>
* It is important to note that this is the local email address, and not
* necessarily the normalized remote email address that the server expects.
*
* @return local email address.
*/
public String getEmail() {
return account.name;
}
}

View File

@ -11,9 +11,11 @@ import org.mozilla.gecko.background.fxa.FxAccountUtils;
import org.mozilla.gecko.browserid.BrowserIDKeyPair;
import org.mozilla.gecko.fxa.FxAccountConstants;
import org.mozilla.gecko.fxa.login.FxAccountLoginStateMachine.ExecuteDelegate;
import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.AccountVerified;
import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.LocalError;
import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.LogMessage;
import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.RemoteError;
import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.Transition;
import org.mozilla.gecko.sync.ExtendedJSONObject;
import org.mozilla.gecko.sync.Utils;
@ -68,7 +70,10 @@ public class Engaged extends State {
delegate.handleTransition(new RemoteError(e), new Separated(email, uid, verified));
return;
}
delegate.handleTransition(new LogMessage("keys succeeded"), new Cohabiting(email, uid, sessionToken, result.kA, kB, keyPair));
Transition transition = verified
? new LogMessage("keys succeeded")
: new AccountVerified();
delegate.handleTransition(transition, new Cohabiting(email, uid, sessionToken, result.kA, kB, keyPair));
}
});
}
@ -80,4 +85,8 @@ public class Engaged extends State {
}
return Action.None;
}
public byte[] getSessionToken() {
return sessionToken;
}
}

View File

@ -28,6 +28,12 @@ public class FxAccountLoginTransition {
}
}
public static class AccountVerified extends LogMessage {
public AccountVerified() {
super(null);
}
}
public static class PasswordRequired extends LogMessage {
public PasswordRequired() {
super(null);

View File

@ -43,10 +43,6 @@ public abstract class State {
return this.stateLabel;
}
public boolean isVerified() {
return this.verified;
}
public ExtendedJSONObject toJSONObject() {
ExtendedJSONObject o = new ExtendedJSONObject();
o.put("version", State.CURRENT_VERSION);

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="@color/fxaccount_input_textColor_inactive" />
<item android:state_pressed="true" android:color="@color/fxaccount_input_textColor_pressed" />
<item android:color="@color/fxaccount_input_textColor" />
</selector>

View File

@ -87,31 +87,23 @@
<CheckBox
android:id="@+id/bookmarks_checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
style="@style/FxAccountCheckBox"
android:text="@string/fxaccount_status_bookmarks" />
<CheckBox
android:id="@+id/history_checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
style="@style/FxAccountCheckBox"
android:text="@string/fxaccount_status_history" />
<CheckBox
android:id="@+id/passwords_checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:text="@string/fxaccount_status_passwords" />
android:id="@+id/tabs_checkbox"
style="@style/FxAccountCheckBox"
android:text="@string/fxaccount_status_tabs" />
<CheckBox
android:id="@+id/tabs_checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:text="@string/fxaccount_status_tabs" />
android:id="@+id/passwords_checkbox"
style="@style/FxAccountCheckBox"
android:text="@string/fxaccount_status_passwords" />
<TextView
style="@style/FxAccountHeaderItem"
@ -135,4 +127,4 @@
</TextView>
</LinearLayout>
</ScrollView>
</ScrollView>

View File

@ -20,6 +20,8 @@
<color name="fxaccount_button_background_loading">#424f59</color>
<color name="fxaccount_button_background_inactive">#c0c9d0</color>
<color name="fxaccount_input_textColor">#424f59</color>
<color name="fxaccount_input_textColor_pressed">#424f59</color>
<color name="fxaccount_input_textColor_inactive">#c0c9d0</color>
<color name="fxaccount_input_textColorHint">#c0c9d0</color>
<color name="fxaccount_link_textColor">#0096dd</color>
<color name="fxaccount_link_textColor_pressed">#00767d</color>

View File

@ -120,4 +120,11 @@
<item name="android:layout_height">wrap_content</item>
</style>
<style name="FxAccountCheckBox">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginBottom">10dp</item>
<item name="android:textColor">@drawable/fxaccount_checkbox_textcolor</item>
</style>
</resources>

View File

@ -65,6 +65,7 @@ public class SelectEnginesActivity extends Activity implements
protected Account account;
protected SharedPreferences accountPrefs;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getApplicationContext();
@ -123,7 +124,7 @@ public class SelectEnginesActivity extends Activity implements
dialog.show();
}
private Set<String> getEnginesFromPrefs(SharedPreferences syncPrefs) {
private static Set<String> getEnginesFromPrefs(SharedPreferences syncPrefs) {
Set<String> engines = SyncConfiguration.getEnabledEngineNames(syncPrefs);
if (engines == null) {
engines = SyncConfiguration.validEngineNames();
@ -142,7 +143,7 @@ public class SelectEnginesActivity extends Activity implements
* @return Set<String> of engine names to display as selected. Should never be
* null.
*/
private Set<String> getEnginesToSelect(SharedPreferences syncPrefs) {
public static Set<String> getEnginesToSelect(SharedPreferences syncPrefs) {
Set<String> engines = getEnginesFromPrefs(syncPrefs);
Map<String, Boolean> engineSelections = SyncConfiguration.getUserSelectedEngines(syncPrefs);
if (engineSelections != null) {