Bug 959784 - Show spinner and native error UI as appropriate. r=rnewman

This commit is contained in:
Nick Alexander 2014-01-23 18:32:34 -08:00
parent aaf6744434
commit 8e30993ed8
16 changed files with 227 additions and 107 deletions

View File

@ -4,6 +4,7 @@
package org.mozilla.gecko.background.fxa;
import org.mozilla.gecko.R;
import org.mozilla.gecko.sync.HTTPFailureException;
import org.mozilla.gecko.sync.net.SyncStorageResponse;
@ -46,7 +47,7 @@ public class FxAccountClientException extends Exception {
@Override
public String toString() {
return "" + this.httpStatusCode + " [" + this.apiErrorNumber + "]: " + this.message;
return "<FxAccountClientRemoteException " + this.httpStatusCode + " [" + this.apiErrorNumber + "]: " + this.message + ">";
}
public boolean isInvalidAuthentication() {
@ -72,6 +73,28 @@ public class FxAccountClientException extends Exception {
apiErrorNumber == FxAccountRemoteError.INCORRECT_KEY_RETRIEVAL_METHOD_FOR_THIS_ACCOUNT ||
apiErrorNumber == FxAccountRemoteError.INCORRECT_API_VERSION_FOR_THIS_ACCOUNT;
}
public int getErrorMessageStringResource() {
if (isUpgradeRequired()) {
return R.string.fxaccount_remote_error_UPGRADE_REQUIRED;
}
switch ((int) apiErrorNumber) {
case FxAccountRemoteError.ATTEMPT_TO_CREATE_AN_ACCOUNT_THAT_ALREADY_EXISTS:
return R.string.fxaccount_remote_error_ATTEMPT_TO_CREATE_AN_ACCOUNT_THAT_ALREADY_EXISTS;
case FxAccountRemoteError.ATTEMPT_TO_ACCESS_AN_ACCOUNT_THAT_DOES_NOT_EXIST:
return R.string.fxaccount_remote_error_ATTEMPT_TO_ACCESS_AN_ACCOUNT_THAT_DOES_NOT_EXIST;
case FxAccountRemoteError.INCORRECT_PASSWORD:
return R.string.fxaccount_remote_error_INCORRECT_PASSWORD;
case FxAccountRemoteError.ATTEMPT_TO_OPERATE_ON_AN_UNVERIFIED_ACCOUNT:
return R.string.fxaccount_remote_error_ATTEMPT_TO_OPERATE_ON_AN_UNVERIFIED_ACCOUNT;
case FxAccountRemoteError.CLIENT_HAS_SENT_TOO_MANY_REQUESTS:
return R.string.fxaccount_remote_error_CLIENT_HAS_SENT_TOO_MANY_REQUESTS;
case FxAccountRemoteError.SERVICE_TEMPORARILY_UNAVAILABLE_DUE_TO_HIGH_LOAD:
return R.string.fxaccount_remote_error_SERVICE_TEMPORARILY_UNAVAILABLE_TO_DUE_HIGH_LOAD;
default:
return R.string.fxaccount_remote_error_UNKNOWN_ERROR;
}
}
}

View File

@ -25,6 +25,6 @@ public interface FxAccountRemoteError {
public static final int INCORRECT_LOGIN_METHOD_FOR_THIS_ACCOUNT = 117;
public static final int INCORRECT_KEY_RETRIEVAL_METHOD_FOR_THIS_ACCOUNT = 118;
public static final int INCORRECT_API_VERSION_FOR_THIS_ACCOUNT = 119;
public static final int SERVICE_TEMPORARILY_UNAVAILABLE_TO_DUE_HIGH_LOAD = 201;
public static final int SERVICE_TEMPORARILY_UNAVAILABLE_DUE_TO_HIGH_LOAD = 201;
public static final int UNKNOWN_ERROR = 999;
}

View File

@ -4,10 +4,13 @@
package org.mozilla.gecko.fxa.activities;
import java.io.IOException;
import org.mozilla.gecko.R;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException;
import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.ProgressDisplay;
import android.app.AlertDialog;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
@ -18,10 +21,11 @@ import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
abstract public class FxAccountAbstractSetupActivity extends FxAccountAbstractActivity {
abstract public class FxAccountAbstractSetupActivity extends FxAccountAbstractActivity implements ProgressDisplay {
public FxAccountAbstractSetupActivity() {
super(CANNOT_RESUME_WHEN_ACCOUNTS_EXIST | CANNOT_RESUME_WHEN_LOCKED_OUT);
}
@ -34,11 +38,12 @@ abstract public class FxAccountAbstractSetupActivity extends FxAccountAbstractAc
protected int minimumPasswordLength = 8;
protected TextView localErrorTextView;
protected EditText emailEdit;
protected EditText passwordEdit;
protected Button showPasswordButton;
protected TextView remoteErrorTextView;
protected Button button;
protected ProgressBar progressBar;
protected void createShowPasswordButton() {
showPasswordButton.setOnClickListener(new OnClickListener() {
@ -59,8 +64,20 @@ abstract public class FxAccountAbstractSetupActivity extends FxAccountAbstractAc
});
}
protected void showRemoteError(Exception e) {
new AlertDialog.Builder(this).setTitle("Remote error!").setMessage(e.toString()).show();
protected void hideRemoteError() {
remoteErrorTextView.setVisibility(View.INVISIBLE);
}
protected void showRemoteError(Exception e, int defaultResourceId) {
if (e instanceof IOException) {
remoteErrorTextView.setText(R.string.fxaccount_remote_error_COULD_NOT_CONNECT);
} else if (e instanceof FxAccountClientRemoteException) {
remoteErrorTextView.setText(((FxAccountClientRemoteException) e).getErrorMessageStringResource());
} else {
remoteErrorTextView.setText(defaultResourceId);
}
Logger.warn(LOG_TAG, "Got exception; showing error message: " + remoteErrorTextView.getText().toString(), e);
remoteErrorTextView.setVisibility(View.VISIBLE);
}
protected void addListeners() {
@ -124,11 +141,27 @@ abstract public class FxAccountAbstractSetupActivity extends FxAccountAbstractAc
protected boolean updateButtonState() {
boolean enabled = shouldButtonBeEnabled();
if (!enabled) {
// The user needs to do something before you can interact with the button;
// presumably that interaction will fix whatever error is shown.
hideRemoteError();
}
if (enabled != button.isEnabled()) {
Logger.debug(LOG_TAG, (enabled ? "En" : "Dis") + "abling button.");
button.setEnabled(enabled);
}
return enabled;
}
@Override
public void showProgress() {
progressBar.setVisibility(View.VISIBLE);
button.setVisibility(View.INVISIBLE);
}
@Override
public void dismissProgress() {
progressBar.setVisibility(View.INVISIBLE);
button.setVisibility(View.VISIBLE);
}
}

View File

@ -86,7 +86,7 @@ public class FxAccountConfirmAccountActivity extends Activity implements OnClick
protected final byte[] sessionToken;
public FxAccountResendCodeTask(Context context, byte[] sessionToken, FxAccountClient20 client, RequestDelegate<Void> delegate) {
super(context, false, client, delegate);
super(context, null, client, delegate);
this.sessionToken = sessionToken;
}

View File

@ -33,6 +33,7 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
@ -58,12 +59,13 @@ public class FxAccountCreateAccountActivity extends FxAccountAbstractSetupActivi
linkifyTextViews(null, new int[] { R.id.policy });
localErrorTextView = (TextView) ensureFindViewById(null, R.id.local_error, "local error text view");
emailEdit = (EditText) ensureFindViewById(null, R.id.email, "email edit");
passwordEdit = (EditText) ensureFindViewById(null, R.id.password, "password edit");
showPasswordButton = (Button) ensureFindViewById(null, R.id.show_password, "show password button");
yearEdit = (EditText) ensureFindViewById(null, R.id.year_edit, "year edit");
button = (Button) ensureFindViewById(null, R.id.create_account_button, "create account button");
remoteErrorTextView = (TextView) ensureFindViewById(null, R.id.remote_error, "remote error text view");
button = (Button) ensureFindViewById(null, R.id.button, "create account button");
progressBar = (ProgressBar) ensureFindViewById(null, R.id.progress, "progress bar");
createCreateAccountButton();
createYearEdit();
@ -145,12 +147,12 @@ public class FxAccountCreateAccountActivity extends FxAccountAbstractSetupActivi
@Override
public void handleError(Exception e) {
showRemoteError(e);
showRemoteError(e, R.string.fxaccount_create_account_unknown_error);
}
@Override
public void handleFailure(final FxAccountClientRemoteException e) {
handleError(e);
showRemoteError(e, R.string.fxaccount_create_account_unknown_error);
}
@Override
@ -209,9 +211,10 @@ public class FxAccountCreateAccountActivity extends FxAccountAbstractSetupActivi
Executor executor = Executors.newSingleThreadExecutor();
FxAccountClient20 client = new FxAccountClient20(serverURI, executor);
try {
new FxAccountCreateAccountTask(this, email, password, client, delegate).execute();
hideRemoteError();
new FxAccountCreateAccountTask(this, this, email, password, client, delegate).execute();
} catch (Exception e) {
showRemoteError(e);
showRemoteError(e, R.string.fxaccount_create_account_unknown_error);
}
}

View File

@ -16,7 +16,6 @@ import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClient
import org.mozilla.gecko.background.fxa.FxAccountUtils;
import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.InnerRequestDelegate;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
@ -30,12 +29,16 @@ import android.os.AsyncTask;
* process.
*/
abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerRequestDelegate<T>> {
protected static final String LOG_TAG = FxAccountSetupTask.class.getSimpleName();
private static final String LOG_TAG = FxAccountSetupTask.class.getSimpleName();
public interface ProgressDisplay {
public void showProgress();
public void dismissProgress();
}
protected final Context context;
protected final FxAccountClient20 client;
protected ProgressDialog progressDialog = null;
protected final ProgressDisplay progressDisplay;
// Initialized lazily.
protected byte[] quickStretchedPW;
@ -46,34 +49,30 @@ abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerRequestD
protected final RequestDelegate<T> delegate;
public FxAccountSetupTask(Context context, boolean shouldShowProgressDialog, FxAccountClient20 client, RequestDelegate<T> delegate) {
public FxAccountSetupTask(Context context, ProgressDisplay progressDisplay, FxAccountClient20 client, RequestDelegate<T> delegate) {
this.context = context;
this.client = client;
this.delegate = delegate;
if (shouldShowProgressDialog) {
progressDialog = new ProgressDialog(context);
}
this.progressDisplay = progressDisplay;
}
@Override
protected void onPreExecute() {
if (progressDialog != null) {
progressDialog.setTitle("Firefox Account..."); // XXX.
progressDialog.setMessage("Please wait.");
progressDialog.setCancelable(false);
progressDialog.setIndeterminate(true);
progressDialog.show();
if (progressDisplay != null) {
progressDisplay.showProgress();
}
}
@Override
protected void onPostExecute(InnerRequestDelegate<T> result) {
if (progressDialog != null) {
progressDialog.dismiss();
if (progressDisplay != null) {
progressDisplay.dismissProgress();
}
// We are on the UI thread, and need to invoke these callbacks here to allow UI updating.
if (innerDelegate.exception != null) {
if (innerDelegate.failure != null) {
delegate.handleFailure(innerDelegate.failure);
} else if (innerDelegate.exception != null) {
delegate.handleError(innerDelegate.exception);
} else {
delegate.handleSuccess(result.response);
@ -82,8 +81,8 @@ abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerRequestD
@Override
protected void onCancelled(InnerRequestDelegate<T> result) {
if (progressDialog != null) {
progressDialog.dismiss();
if (progressDisplay != null) {
progressDisplay.dismissProgress();
}
delegate.handleError(new IllegalStateException("Task was cancelled."));
}
@ -92,6 +91,7 @@ abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerRequestD
protected final CountDownLatch latch;
public T response = null;
public Exception exception = null;
public FxAccountClientRemoteException failure = null;
protected InnerRequestDelegate(CountDownLatch latch) {
this.latch = latch;
@ -107,7 +107,7 @@ abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerRequestD
@Override
public void handleFailure(FxAccountClientRemoteException e) {
Logger.warn(LOG_TAG, "Got failure.");
this.exception = e;
this.failure = e;
latch.countDown();
}
@ -120,13 +120,13 @@ abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerRequestD
}
public static class FxAccountCreateAccountTask extends FxAccountSetupTask<String> {
protected static final String LOG_TAG = FxAccountCreateAccountTask.class.getSimpleName();
private static final String LOG_TAG = FxAccountCreateAccountTask.class.getSimpleName();
protected final byte[] emailUTF8;
protected final byte[] passwordUTF8;
public FxAccountCreateAccountTask(Context context, String email, String password, FxAccountClient20 client, RequestDelegate<String> delegate) throws UnsupportedEncodingException {
super(context, true, client, delegate);
public FxAccountCreateAccountTask(Context context, ProgressDisplay progressDisplay, String email, String password, FxAccountClient20 client, RequestDelegate<String> delegate) throws UnsupportedEncodingException {
super(context, progressDisplay, client, delegate);
this.emailUTF8 = email.getBytes("UTF-8");
this.passwordUTF8 = password.getBytes("UTF-8");
}
@ -160,13 +160,13 @@ abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerRequestD
}
public static class FxAccountSignInTask extends FxAccountSetupTask<LoginResponse> {
protected static final String LOG_TAG = FxAccountCreateAccountTask.class.getSimpleName();
protected static final String LOG_TAG = FxAccountSignInTask.class.getSimpleName();
protected final byte[] emailUTF8;
protected final byte[] passwordUTF8;
public FxAccountSignInTask(Context context, String email, String password, FxAccountClient20 client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException {
super(context, true, client, delegate);
public FxAccountSignInTask(Context context, ProgressDisplay progressDisplay, String email, String password, FxAccountClient20 client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException {
super(context, progressDisplay, client, delegate);
this.emailUTF8 = email.getBytes("UTF-8");
this.passwordUTF8 = password.getBytes("UTF-8");
}

View File

@ -29,6 +29,7 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
@ -49,11 +50,12 @@ public class FxAccountSignInActivity extends FxAccountAbstractSetupActivity {
super.onCreate(icicle);
setContentView(R.layout.fxaccount_sign_in);
localErrorTextView = (TextView) ensureFindViewById(null, R.id.local_error, "local error text view");
emailEdit = (EditText) ensureFindViewById(null, R.id.email, "email edit");
passwordEdit = (EditText) ensureFindViewById(null, R.id.password, "password edit");
showPasswordButton = (Button) ensureFindViewById(null, R.id.show_password, "show password button");
button = (Button) ensureFindViewById(null, R.id.sign_in_button, "sign in button");
remoteErrorTextView = (TextView) ensureFindViewById(null, R.id.remote_error, "remote error text view");
button = (Button) ensureFindViewById(null, R.id.button, "sign in button");
progressBar = (ProgressBar) ensureFindViewById(null, R.id.progress, "progress bar");
minimumPasswordLength = 1; // Minimal restriction on passwords entered to sign in.
createSignInButton();
@ -114,12 +116,12 @@ public class FxAccountSignInActivity extends FxAccountAbstractSetupActivity {
@Override
public void handleError(Exception e) {
showRemoteError(e);
showRemoteError(e, R.string.fxaccount_sign_in_unknown_error);
}
@Override
public void handleFailure(FxAccountClientRemoteException e) {
showRemoteError(e);
showRemoteError(e, R.string.fxaccount_sign_in_unknown_error);
}
@Override
@ -184,9 +186,10 @@ public class FxAccountSignInActivity extends FxAccountAbstractSetupActivity {
Executor executor = Executors.newSingleThreadExecutor();
FxAccountClient20 client = new FxAccountClient20(serverURI, executor);
try {
new FxAccountSignInTask(this, email, password, client, delegate).execute();
hideRemoteError();
new FxAccountSignInTask(this, this, email, password, client, delegate).execute();
} catch (Exception e) {
showRemoteError(e);
showRemoteError(e, R.string.fxaccount_sign_in_unknown_error);
}
}

View File

@ -19,6 +19,7 @@ import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import android.widget.ViewFlipper;
/**
* Activity which displays account status.
@ -26,6 +27,7 @@ import android.widget.TextView;
public class FxAccountStatusActivity extends FxAccountAbstractActivity {
protected static final String LOG_TAG = FxAccountStatusActivity.class.getSimpleName();
protected ViewFlipper connectionStatusViewFlipper;
protected View connectionStatusUnverifiedView;
protected View connectionStatusSignInView;
protected View connectionStatusSyncingView;
@ -46,7 +48,8 @@ public class FxAccountStatusActivity extends FxAccountAbstractActivity {
super.onCreate(icicle);
setContentView(R.layout.fxaccount_status);
connectionStatusUnverifiedView = ensureFindViewById(null, R.id.unverified_view, "unverified view");
connectionStatusViewFlipper = (ViewFlipper) ensureFindViewById(null, R.id.connection_status_view, "connection status frame layout");
connectionStatusUnverifiedView = ensureFindViewById(null, R.id.unverified_view, "unverified vie w");
connectionStatusSignInView = ensureFindViewById(null, R.id.sign_in_view, "sign in view");
connectionStatusSyncingView = ensureFindViewById(null, R.id.syncing_view, "syncing view");
@ -161,29 +164,19 @@ public class FxAccountStatusActivity extends FxAccountAbstractActivity {
}
protected void showNeedsUpgrade() {
connectionStatusUnverifiedView.setVisibility(View.GONE);
connectionStatusSignInView.setVisibility(View.GONE);
connectionStatusSyncingView.setVisibility(View.GONE);
}
protected void showNeedsVerification() {
connectionStatusUnverifiedView.setVisibility(View.VISIBLE);
connectionStatusSignInView.setVisibility(View.GONE);
connectionStatusSyncingView.setVisibility(View.GONE);
connectionStatusViewFlipper.setDisplayedChild(0);
}
protected void showNeedsPassword() {
connectionStatusUnverifiedView.setVisibility(View.GONE);
connectionStatusSignInView.setVisibility(View.VISIBLE);
connectionStatusSyncingView.setVisibility(View.GONE);
return;
connectionStatusViewFlipper.setDisplayedChild(1);
}
protected void showNeedsVerification() {
connectionStatusViewFlipper.setDisplayedChild(2);
}
protected void showConnected() {
connectionStatusUnverifiedView.setVisibility(View.GONE);
connectionStatusSignInView.setVisibility(View.GONE);
connectionStatusSyncingView.setVisibility(View.VISIBLE);
return;
connectionStatusViewFlipper.setDisplayedChild(3);
}
protected void refresh(Account account) {

View File

@ -31,6 +31,7 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
@ -60,11 +61,12 @@ public class FxAccountUpdateCredentialsActivity extends FxAccountAbstractSetupAc
super.onCreate(icicle);
setContentView(R.layout.fxaccount_update_credentials);
localErrorTextView = (TextView) ensureFindViewById(null, R.id.local_error, "local error text view");
emailEdit = (EditText) ensureFindViewById(null, R.id.email, "email edit");
passwordEdit = (EditText) ensureFindViewById(null, R.id.password, "password edit");
showPasswordButton = (Button) ensureFindViewById(null, R.id.show_password, "show password button");
remoteErrorTextView = (TextView) ensureFindViewById(null, R.id.remote_error, "remote error text view");
button = (Button) ensureFindViewById(null, R.id.button, "update credentials");
progressBar = (ProgressBar) ensureFindViewById(null, R.id.progress, "progress bar");
minimumPasswordLength = 1; // Minimal restriction on passwords entered to sign in.
createButton();
@ -122,13 +124,13 @@ public class FxAccountUpdateCredentialsActivity extends FxAccountAbstractSetupAc
@Override
public void handleError(Exception e) {
showRemoteError(e);
showRemoteError(e, R.string.fxaccount_update_credentials_unknown_error);
}
@Override
public void handleFailure(FxAccountClientRemoteException e) {
// TODO On isUpgradeRequired, transition to Doghouse state.
showRemoteError(e);
showRemoteError(e, R.string.fxaccount_update_credentials_unknown_error);
}
@Override
@ -163,10 +165,12 @@ public class FxAccountUpdateCredentialsActivity extends FxAccountAbstractSetupAc
Executor executor = Executors.newSingleThreadExecutor();
FxAccountClient20 client = new FxAccountClient20(serverURI, executor);
try {
hideRemoteError();
RequestDelegate<LoginResponse> delegate = new UpdateCredentialsDelegate(email, password, serverURI);
new FxAccountSignInTask(this, email, password, client, delegate).execute();
new FxAccountSignInTask(this, this, email, password, client, delegate).execute();
} catch (Exception e) {
showRemoteError(e);
Logger.warn(LOG_TAG, "Got exception updating credentials for account.", e);
showRemoteError(e, R.string.fxaccount_update_credentials_unknown_error);
}
}

View File

@ -49,15 +49,20 @@
android:inputType="none" />
<TextView
android:id="@+id/local_error"
android:id="@+id/remote_error"
style="@style/FxAccountErrorItem" />
<Button
android:id="@+id/create_account_button"
style="@style/FxAccountButton"
android:layout_marginBottom="20dp"
android:layout_marginTop="45dp"
android:text="@string/fxaccount_create_account_button_label" />
<FrameLayout style="@style/FxAccountButtonLayout" >
<ProgressBar
android:id="@+id/progress"
style="@style/FxAccountProgress" />
<Button
android:id="@+id/button"
style="@style/FxAccountButton"
android:text="@string/fxaccount_create_account_button_label" />
</FrameLayout>
<TextView
android:id="@+id/sign_in_instead_link"
@ -78,4 +83,4 @@
android:contentDescription="@string/fxaccount_icon_contentDescription" />
</LinearLayout>
</ScrollView>
</ScrollView>

View File

@ -12,10 +12,6 @@
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/local_error"
style="@style/FxAccountErrorItem" />
<EditText
android:id="@+id/email"
style="@style/FxAccountEditItem"

View File

@ -26,12 +26,21 @@
<include layout="@layout/fxaccount_email_password_view" />
<Button
android:id="@+id/sign_in_button"
style="@style/FxAccountButton"
android:layout_marginBottom="20dp"
android:layout_marginTop="45dp"
android:text="@string/fxaccount_sign_in_button_label" />
<TextView
android:id="@+id/remote_error"
style="@style/FxAccountErrorItem" />
<FrameLayout style="@style/FxAccountButtonLayout" >
<ProgressBar
android:id="@+id/progress"
style="@style/FxAccountProgress" />
<Button
android:id="@+id/button"
style="@style/FxAccountButton"
android:text="@string/fxaccount_sign_in_button_label" />
</FrameLayout>
<LinearLayout
android:layout_width="fill_parent"
@ -64,4 +73,4 @@
android:contentDescription="@string/fxaccount_icon_contentDescription" />
</LinearLayout>
</ScrollView>
</ScrollView>

View File

@ -33,7 +33,7 @@
android:text="@string/fxaccount_change_password" >
</TextView>
<FrameLayout
<ViewFlipper
android:id="@+id/connection_status_view"
style="@style/FxAccountTextItem"
android:layout_width="match_parent"
@ -52,8 +52,7 @@
android:drawableStart="@drawable/fxaccount_sync_error"
android:gravity="center_vertical"
android:padding="10dp"
android:text="@string/fxaccount_status_needs_verification"
android:visibility="gone" >
android:text="@string/fxaccount_status_needs_upgrade" >
</TextView>
<TextView
@ -68,8 +67,22 @@
android:drawableStart="@drawable/fxaccount_sync_error"
android:gravity="center_vertical"
android:padding="10dp"
android:text="@string/fxaccount_status_needs_credentials"
android:visibility="gone" >
android:text="@string/fxaccount_status_needs_credentials" >
</TextView>
<TextView
android:id="@+id/unverified_view"
style="@style/FxAccountTextItem"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="10dp"
android:background="#fad4d2"
android:drawablePadding="10dp"
android:drawableStart="@drawable/fxaccount_sync_error"
android:gravity="center_vertical"
android:padding="10dp"
android:text="@string/fxaccount_status_needs_verification" >
</TextView>
<TextView
@ -84,10 +97,9 @@
android:drawableStart="@drawable/fxaccount_sync_icon"
android:gravity="center_vertical"
android:padding="10dp"
android:text="@string/fxaccount_status_syncing"
android:visibility="visible" >
android:text="@string/fxaccount_status_syncing" >
</TextView>
</FrameLayout>
</ViewFlipper>
<TextView
style="@style/FxAccountHeaderItem"

View File

@ -26,12 +26,21 @@
<include layout="@layout/fxaccount_email_password_view" />
<Button
android:id="@+id/button"
style="@style/FxAccountButton"
android:layout_marginBottom="20dp"
android:layout_marginTop="45dp"
android:text="@string/fxaccount_update_credentials_button_label" />
<TextView
android:id="@+id/remote_error"
style="@style/FxAccountErrorItem" />
<FrameLayout style="@style/FxAccountButtonLayout" >
<ProgressBar
android:id="@+id/progress"
style="@style/FxAccountProgress" />
<Button
android:id="@+id/button"
style="@style/FxAccountButton"
android:text="@string/fxaccount_update_credentials_button_label" />
</FrameLayout>
<TextView
android:id="@+id/forgot_password_link"
@ -45,4 +54,4 @@
android:contentDescription="@string/fxaccount_icon_contentDescription" />
</LinearLayout>
</ScrollView>
</ScrollView>

View File

@ -91,10 +91,13 @@
</style>
<style name="FxAccountErrorItem">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_marginBottom">10dp</item>
<item name="android:layout_marginLeft">@dimen/fxaccount_corner_radius</item>
<item name="android:layout_marginRight">@dimen/fxaccount_corner_radius</item>
<item name="android:layout_marginTop">30dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_gravity">left</item>
<item name="android:layout_margin">5dp</item>
<item name="android:background">@drawable/fxaccount_textview_error_background</item>
<item name="android:padding">5dp</item>
<item name="android:text">Error</item>
@ -103,4 +106,18 @@
<item name="android:visibility">invisible</item>
</style>
</resources>
<style name="FxAccountProgress">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:background">@drawable/fxaccount_button_background</item>
<item name="android:visibility">invisible</item>
</style>
<style name="FxAccountButtonLayout">
<item name="android:orientation">vertical</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginBottom">20dp</item>
</style>
</resources>

View File

@ -142,6 +142,7 @@
<string name="fxaccount_confirmation_email_sent">&fxaccount.confirmation.email.sent;</string>
<string name="fxaccount_password_length_restriction">&fxaccount.password.length.restriction;</string>
<string name="fxaccount_change_password">&fxaccount.change.password;</string>
<string name="fxaccount_status_needs_upgrade">You need to upgrade Firefox to log in to this account.</string>
<string name="fxaccount_status_needs_verification">&fxaccount.status.needs.verification;</string>
<string name="fxaccount_status_needs_credentials">&fxaccount.status.needs.credentials;</string>
<string name="fxaccount_status_syncing">&fxaccount.status.syncing;</string>
@ -187,3 +188,15 @@
<string name="fxaccount_status_debug_forget_certificate_button_label">Forget certificate (if applicable)</string>
<string name="fxaccount_status_debug_require_password_button_label">Require password re-entry</string>
<string name="fxaccount_status_debug_require_upgrade_button_label">Require upgrade</string>
<string name="fxaccount_create_account_unknown_error">Could not create account</string>
<string name="fxaccount_sign_in_unknown_error">Could not sign in</string>
<string name="fxaccount_update_credentials_unknown_error">Could not update password</string>
<string name="fxaccount_remote_error_UPGRADE_REQUIRED">You need to upgrade Firefox</string>
<string name="fxaccount_remote_error_ATTEMPT_TO_CREATE_AN_ACCOUNT_THAT_ALREADY_EXISTS">Account already exists</string>
<string name="fxaccount_remote_error_ATTEMPT_TO_ACCESS_AN_ACCOUNT_THAT_DOES_NOT_EXIST">Account does not exist</string>
<string name="fxaccount_remote_error_INCORRECT_PASSWORD">Bad password</string>
<string name="fxaccount_remote_error_ATTEMPT_TO_OPERATE_ON_AN_UNVERIFIED_ACCOUNT">Account is not verified</string>
<string name="fxaccount_remote_error_CLIENT_HAS_SENT_TOO_MANY_REQUESTS">Try again later</string>
<string name="fxaccount_remote_error_SERVICE_TEMPORARILY_UNAVAILABLE_TO_DUE_HIGH_LOAD">Try again later</string>
<string name="fxaccount_remote_error_UNKNOWN_ERROR">There was a problem</string>
<string name="fxaccount_remote_error_COULD_NOT_CONNECT">Couldn\&apos;t connect to the internet</string>