Bug 1204937 - Part 1: Redirect native account UI launches through action intent filters. r=sebastian
authorNick Alexander <nalexander@mozilla.com>
Tue, 15 Sep 2015 14:18:46 -0400
changeset 295169 8cf398383bba7f3de165943692cb8820c5a78588
parent 295168 7fef7994f691875be099b47057bf8fb89e5e858c
child 295170 ec2b4ace61d3f2d85c555d62fe545fa6562244e8
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssebastian
bugs1204937
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1204937 - Part 1: Redirect native account UI launches through action intent filters. r=sebastian This patch stops referring to package/class objects to identify Android components directly and instead launches through action intent filters. The intent filters are scoped to the package, but not marked as private or as requiring a permission. A malicious package could inject itself into an account flow, but I don't think there's much advantage: the only time a secret is passed between activities is when the native sign up (CreateAccount) and sign in (SignIn) activities link between themselves, and in this instance I didn't route through the action intent filters. (This is entirely native -- there's no web analog -- so I didn't use the indirection.)
mobile/android/base/BrowserApp.java
mobile/android/base/firstrun/WelcomePanel.java
mobile/android/base/fxa/FxAccountConstants.java
mobile/android/base/fxa/activities/FxAccountAbstractActivity.java
mobile/android/base/fxa/activities/FxAccountAbstractUpdateCredentialsActivity.java
mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java
mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java
mobile/android/base/fxa/activities/FxAccountStatusActivity.java
mobile/android/base/fxa/activities/FxAccountStatusFragment.java
mobile/android/base/fxa/authenticator/FxAccountAuthenticator.java
mobile/android/base/fxa/sync/FxAccountNotificationManager.java
mobile/android/base/home/RemoteTabsStaticFragment.java
mobile/android/base/overlays/service/sharemethods/SendTab.java
mobile/android/base/preferences/SyncPreference.java
mobile/android/services/manifests/FxAccountAndroidManifest_activities.xml.in
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -1721,17 +1721,17 @@ public class BrowserApp extends GeckoApp
                 }
             }
             if (callback != null) {
                 callback.sendSuccess(fxAccount != null);
             }
 
         } else if ("Accounts:Create".equals(event)) {
             // Do exactly the same thing as if you tapped 'Sync' in Settings.
-            final Intent intent = new Intent(getContext(), FxAccountGetStartedActivity.class);
+            final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             final NativeJSObject extras = message.optObject("extras", null);
             if (extras != null) {
                 intent.putExtra("extras", extras.toString());
             }
             getContext().startActivity(intent);
 
         } else if ("CharEncoding:Data".equals(event)) {
--- a/mobile/android/base/firstrun/WelcomePanel.java
+++ b/mobile/android/base/firstrun/WelcomePanel.java
@@ -8,31 +8,32 @@ package org.mozilla.gecko.firstrun;
 import android.content.Intent;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
-import org.mozilla.gecko.fxa.activities.FxAccountGetStartedActivity;
+import org.mozilla.gecko.fxa.FxAccountConstants;
 
 public class WelcomePanel extends FirstrunPanel {
     public static final int TITLE_RES = R.string.firstrun_panel_title_welcome;
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) {
         final ViewGroup root = (ViewGroup) inflater.inflate(R.layout.firstrun_welcome_fragment, container, false);
         root.findViewById(R.id.welcome_account).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.BUTTON, "firstrun-sync");
 
-                final Intent accountIntent = new Intent(getActivity(), FxAccountGetStartedActivity.class);
-                startActivity(accountIntent);
+                final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+                startActivity(intent);
 
                 close();
             }
         });
 
         root.findViewById(R.id.welcome_browse).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
--- a/mobile/android/base/fxa/FxAccountConstants.java
+++ b/mobile/android/base/fxa/FxAccountConstants.java
@@ -89,9 +89,15 @@ public class FxAccountConstants {
    * This action is broadcast when an Android Firefox Account's internal state
    * is changed.
    * <p>
    * It is protected by signing-level permission PER_ACCOUNT_TYPE_PERMISSION and
    * can be received only by Firefox versions sharing the same Android Firefox
    * Account type.
    */
   public static final String ACCOUNT_STATE_CHANGED_ACTION = AppConstants.MOZ_ANDROID_SHARED_FXACCOUNT_TYPE + ".accounts.ACCOUNT_STATE_CHANGED_ACTION";
+
+  public static final String ACTION_FXA_CONFIRM_ACCOUNT            = AppConstants.ANDROID_PACKAGE_NAME + ".ACTION_FXA_CONFIRM_ACCOUNT";
+  public static final String ACTION_FXA_FINISH_MIGRATING           = AppConstants.ANDROID_PACKAGE_NAME + ".ACTION_FXA_FINISH_MIGRATING";
+  public static final String ACTION_FXA_GET_STARTED                = AppConstants.ANDROID_PACKAGE_NAME + ".ACTION_FXA_GET_STARTED";
+  public static final String ACTION_FXA_STATUS                     = AppConstants.ANDROID_PACKAGE_NAME + ".ACTION_FXA_STATUS";
+  public static final String ACTION_FXA_UPDATE_CREDENTIALS         = AppConstants.ANDROID_PACKAGE_NAME + ".ACTION_FXA_UPDATE_CREDENTIALS";
 }
--- a/mobile/android/base/fxa/activities/FxAccountAbstractActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountAbstractActivity.java
@@ -1,28 +1,28 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa.activities;
 
-import org.mozilla.gecko.Locales.LocaleAwareActivity;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.fxa.FxAccountAgeLockoutHelper;
-import org.mozilla.gecko.fxa.FirefoxAccounts;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
-
 import android.accounts.Account;
 import android.app.Activity;
 import android.content.Intent;
 import android.os.SystemClock;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.TextView;
+import org.mozilla.gecko.Locales.LocaleAwareActivity;
+import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.background.fxa.FxAccountAgeLockoutHelper;
+import org.mozilla.gecko.fxa.FirefoxAccounts;
+import org.mozilla.gecko.fxa.FxAccountConstants;
+import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
+import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
 
 public abstract class FxAccountAbstractActivity extends LocaleAwareActivity {
   private static final String LOG_TAG = FxAccountAbstractActivity.class.getSimpleName();
 
   protected final boolean cannotResumeWhenAccountsExist;
   protected final boolean cannotResumeWhenNoAccountsExist;
   protected final boolean cannotResumeWhenLockedOut;
 
@@ -38,36 +38,40 @@ public abstract class FxAccountAbstractA
     this.cannotResumeWhenLockedOut = 0 != (resume & CANNOT_RESUME_WHEN_LOCKED_OUT);
   }
 
   /**
    * Many Firefox Accounts activities shouldn't display if an account already
    * exists or if account creation is locked out due to an age verification
    * check failing (getting started, create account, sign in). This function
    * redirects as appropriate.
+   *
+   * @return true if redirected.
    */
-  protected void redirectIfAppropriate() {
+  protected boolean redirectIfAppropriate() {
     if (cannotResumeWhenAccountsExist || cannotResumeWhenNoAccountsExist) {
       final Account account = FirefoxAccounts.getFirefoxAccount(this);
       if (cannotResumeWhenAccountsExist && account != null) {
-        redirectToActivity(FxAccountStatusActivity.class);
-        return;
+        redirectToAction(FxAccountConstants.ACTION_FXA_STATUS);
+        return true;
       }
       if (cannotResumeWhenNoAccountsExist && account == null) {
-        redirectToActivity(FxAccountGetStartedActivity.class);
-        return;
+        redirectToAction(FxAccountConstants.ACTION_FXA_GET_STARTED);
+        return true;
       }
     }
     if (cannotResumeWhenLockedOut) {
       if (FxAccountAgeLockoutHelper.isLockedOut(SystemClock.elapsedRealtime())) {
         this.setResult(RESULT_CANCELED);
-        redirectToActivity(FxAccountCreateAccountNotAllowedActivity.class);
-        return;
+        launchActivity(FxAccountCreateAccountNotAllowedActivity.class);
+        finish();
+        return true;
       }
     }
+    return false;
   }
 
   @Override
   public void onResume() {
     super.onResume();
     redirectIfAppropriate();
   }
 
@@ -80,18 +84,22 @@ public abstract class FxAccountAbstractA
   protected void launchActivity(Class<? extends Activity> activityClass) {
     Intent intent = new Intent(this, activityClass);
     // 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?
     intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
     startActivity(intent);
   }
 
-  protected void redirectToActivity(Class<? extends Activity> activityClass) {
-    launchActivity(activityClass);
+  protected void redirectToAction(final String action) {
+    final Intent intent = new Intent(action);
+    // 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?
+    intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+    startActivity(intent);
     finish();
   }
 
   /**
    * Helper to find view or error if it is missing.
    *
    * @param id of view to find.
    * @param description to print in error.
--- a/mobile/android/base/fxa/activities/FxAccountAbstractUpdateCredentialsActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountAbstractUpdateCredentialsActivity.java
@@ -1,44 +1,44 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa.activities;
 
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AutoCompleteTextView;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ProgressBar;
+import android.widget.TextView;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.common.telemetry.TelemetryWrapper;
 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.FxAccountClient20.LoginResponse;
 import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException;
 import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.background.fxa.PasswordStretcher;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
+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.tasks.FxAccountSignInTask;
 import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
 import org.mozilla.gecko.sync.telemetry.TelemetryContract;
 
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AutoCompleteTextView;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ProgressBar;
-import android.widget.TextView;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 
 /**
  * Abstract activity which displays a screen for updating the local password.
  */
 public abstract class FxAccountAbstractUpdateCredentialsActivity extends FxAccountAbstractSetupActivity {
   protected static final String LOG_TAG = FxAccountAbstractUpdateCredentialsActivity.class.getSimpleName();
 
   protected AndroidFxAccount fxAccount;
@@ -104,17 +104,17 @@ public abstract class FxAccountAbstractU
 
     @Override
     public void handleFailure(FxAccountClientRemoteException e) {
       if (e.isUpgradeRequired()) {
         Logger.error(LOG_TAG, "Got upgrade required from remote server; transitioning Firefox Account to Doghouse state.");
         final State state = fxAccount.getState();
         fxAccount.setState(state.makeDoghouseState());
         // The status activity will say that the user needs to upgrade.
-        redirectToActivity(FxAccountStatusActivity.class);
+        redirectToAction(FxAccountConstants.ACTION_FXA_STATUS);
         return;
       }
       showRemoteError(e, R.string.fxaccount_update_credentials_unknown_error);
     }
 
     @Override
     public void handleSuccess(LoginResponse result) {
       Logger.info(LOG_TAG, "Got success signing in.");
--- a/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java
@@ -1,34 +1,34 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa.activities;
 
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.fxa.FirefoxAccounts;
-import org.mozilla.gecko.fxa.SyncStatusListener;
-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.Action;
-import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper;
-import org.mozilla.gecko.fxa.tasks.FxAccountCodeResender;
-import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
-
 import android.accounts.Account;
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.TextView;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.fxa.FirefoxAccounts;
+import org.mozilla.gecko.fxa.FxAccountConstants;
+import org.mozilla.gecko.fxa.SyncStatusListener;
+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.Action;
+import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper;
+import org.mozilla.gecko.fxa.tasks.FxAccountCodeResender;
+import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
 
 /**
  * Activity which displays account created successfully screen to the user, and
  * starts them on the email verification path.
  */
 public class FxAccountConfirmAccountActivity extends FxAccountAbstractActivity implements OnClickListener {
   private static final String LOG_TAG = FxAccountConfirmAccountActivity.class.getSimpleName();
 
@@ -141,17 +141,17 @@ public class FxAccountConfirmAccountActi
     case NeedsVerification:
       // This is what we're here to handle.
       break;
     default:
       // We're not in the right place!  Redirect to status.
       Logger.warn(LOG_TAG, "No need to verify Firefox Account that needs action " + neededAction.toString() +
           " (in state " + state.getStateLabel() + ").");
       setResult(RESULT_CANCELED);
-      this.redirectToActivity(FxAccountStatusActivity.class);
+      redirectToAction(FxAccountConstants.ACTION_FXA_STATUS);
       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;
--- a/mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java
@@ -424,17 +424,18 @@ public class FxAccountCreateAccountActiv
             : AndroidFxAccount.DEFAULT_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP;
         if (FxAccountAgeLockoutHelper.passesAgeCheck(dayOfBirth, zeroBasedMonthOfBirth, yearEdit.getText().toString(), yearItems)) {
           FxAccountUtils.pii(LOG_TAG, "Passed age check.");
           createAccount(email, password, engines, authoritiesMap);
         } else {
           FxAccountUtils.pii(LOG_TAG, "Failed age check!");
           FxAccountAgeLockoutHelper.lockOut(SystemClock.elapsedRealtime());
           setResult(RESULT_CANCELED);
-          redirectToActivity(FxAccountCreateAccountNotAllowedActivity.class);
+          launchActivity(FxAccountCreateAccountNotAllowedActivity.class);
+          finish();
         }
       }
     });
   }
 
   /**
    * The "Choose what to sync" checkbox pops up a multi-choice dialog when it is
    * unchecked. It toggles to unchecked from checked.
--- a/mobile/android/base/fxa/activities/FxAccountStatusActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountStatusActivity.java
@@ -1,23 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa.activities;
 
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.Locales.LocaleAwareFragmentActivity;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.fxa.FxAccountUtils;
-import org.mozilla.gecko.fxa.FirefoxAccounts;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.sync.Utils;
-
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AccountManagerCallback;
 import android.accounts.AccountManagerFuture;
 import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.app.ActionBar;
 import android.app.Activity;
@@ -27,16 +18,25 @@ import android.content.DialogInterface;
 import android.content.Intent;
 import android.os.Build;
 import android.os.Bundle;
 import android.util.TypedValue;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.widget.Toast;
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.Locales.LocaleAwareFragmentActivity;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.background.fxa.FxAccountUtils;
+import org.mozilla.gecko.fxa.FirefoxAccounts;
+import org.mozilla.gecko.fxa.FxAccountConstants;
+import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
+import org.mozilla.gecko.sync.Utils;
 
 /**
  * Activity which displays account status.
  */
 public class FxAccountStatusActivity extends LocaleAwareFragmentActivity {
   private static final String LOG_TAG = FxAccountStatusActivity.class.getSimpleName();
 
   protected FxAccountStatusFragment statusFragment;
@@ -80,17 +80,17 @@ public class FxAccountStatusActivity ext
   public void onResume() {
     super.onResume();
 
     final AndroidFxAccount fxAccount = getAndroidFxAccount();
     if (fxAccount == null) {
       Logger.warn(LOG_TAG, "Could not get Firefox Account.");
 
       // Gracefully redirect to get started.
-      Intent intent = new Intent(this, FxAccountGetStartedActivity.class);
+      final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
       // 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?
       intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
       startActivity(intent);
 
       setResult(RESULT_CANCELED);
       finish();
       return;
--- a/mobile/android/base/fxa/activities/FxAccountStatusFragment.java
+++ b/mobile/android/base/fxa/activities/FxAccountStatusFragment.java
@@ -1,40 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa.activities;
 
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.fxa.FxAccountUtils;
-import org.mozilla.gecko.background.preferences.PreferenceFragment;
-import org.mozilla.gecko.fxa.FirefoxAccounts;
-import org.mozilla.gecko.fxa.FxAccountConstants;
-import org.mozilla.gecko.fxa.SyncStatusListener;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.fxa.login.Married;
-import org.mozilla.gecko.fxa.login.State;
-import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper;
-import org.mozilla.gecko.fxa.tasks.FxAccountCodeResender;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.SharedPreferencesClientsDataDelegate;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.util.HardwareUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-
 import android.accounts.Account;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.os.Bundle;
@@ -44,19 +18,43 @@ import android.preference.EditTextPrefer
 import android.preference.Preference;
 import android.preference.Preference.OnPreferenceChangeListener;
 import android.preference.Preference.OnPreferenceClickListener;
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceScreen;
 import android.support.v4.content.LocalBroadcastManager;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
-
 import com.squareup.picasso.Picasso;
 import com.squareup.picasso.Target;
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.background.fxa.FxAccountUtils;
+import org.mozilla.gecko.background.preferences.PreferenceFragment;
+import org.mozilla.gecko.fxa.FirefoxAccounts;
+import org.mozilla.gecko.fxa.FxAccountConstants;
+import org.mozilla.gecko.fxa.SyncStatusListener;
+import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
+import org.mozilla.gecko.fxa.login.Married;
+import org.mozilla.gecko.fxa.login.State;
+import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper;
+import org.mozilla.gecko.fxa.tasks.FxAccountCodeResender;
+import org.mozilla.gecko.sync.ExtendedJSONObject;
+import org.mozilla.gecko.sync.SharedPreferencesClientsDataDelegate;
+import org.mozilla.gecko.sync.SyncConfiguration;
+import org.mozilla.gecko.util.HardwareUtils;
+import org.mozilla.gecko.util.ThreadUtils;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * A fragment that displays the status of an AndroidFxAccount.
  * <p>
  * The owning activity is responsible for providing an AndroidFxAccount at
  * appropriate times.
  */
 public class FxAccountStatusFragment
@@ -232,47 +230,49 @@ public class FxAccountStatusFragment
   @Override
   public void onResume() {
     super.onResume();
   }
 
   @Override
   public boolean onPreferenceClick(Preference preference) {
     if (preference == needsPasswordPreference) {
-      Intent intent = new Intent(getActivity(), FxAccountUpdateCredentialsActivity.class);
+      final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_UPDATE_CREDENTIALS);
       final Bundle extras = getExtrasForAccount();
       if (extras != null) {
         intent.putExtras(extras);
       }
       // 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?
       intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
       startActivity(intent);
 
       return true;
     }
 
     if (preference == needsFinishMigratingPreference) {
-      final Intent intent = new Intent(getActivity(), FxAccountFinishMigratingActivity.class);
+      final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_FINISH_MIGRATING);
       final Bundle extras = getExtrasForAccount();
       if (extras != null) {
         intent.putExtras(extras);
       }
       // 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?
       intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
       startActivity(intent);
 
       return true;
     }
 
     if (preference == needsVerificationPreference) {
-      FxAccountCodeResender.resendCode(getActivity().getApplicationContext(), fxAccount);
+      if (AppConstants.MOZ_ANDROID_NATIVE_ACCOUNT_UI) {
+        FxAccountCodeResender.resendCode(getActivity().getApplicationContext(), fxAccount);
+      }
 
-      Intent intent = new Intent(getActivity(), FxAccountConfirmAccountActivity.class);
+      final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_CONFIRM_ACCOUNT);
       // 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?
       intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
       startActivity(intent);
 
       return true;
     }
 
--- a/mobile/android/base/fxa/authenticator/FxAccountAuthenticator.java
+++ b/mobile/android/base/fxa/authenticator/FxAccountAuthenticator.java
@@ -1,48 +1,46 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa.authenticator;
 
-import java.security.NoSuchAlgorithmException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.fxa.FxAccountClient;
 import org.mozilla.gecko.background.fxa.FxAccountClient20;
 import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClient.RequestDelegate;
 import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClientException.FxAccountAbstractClientRemoteException;
 import org.mozilla.gecko.background.fxa.oauth.FxAccountOAuthClient10;
 import org.mozilla.gecko.background.fxa.oauth.FxAccountOAuthClient10.AuthorizationResponse;
 import org.mozilla.gecko.browserid.BrowserIDKeyPair;
 import org.mozilla.gecko.browserid.JSONWebTokenUtils;
 import org.mozilla.gecko.fxa.FxAccountConstants;
-import org.mozilla.gecko.fxa.activities.FxAccountGetStartedActivity;
 import org.mozilla.gecko.fxa.login.FxAccountLoginStateMachine;
 import org.mozilla.gecko.fxa.login.FxAccountLoginStateMachine.LoginStateMachineDelegate;
 import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.Transition;
 import org.mozilla.gecko.fxa.login.Married;
 import org.mozilla.gecko.fxa.login.State;
 import org.mozilla.gecko.fxa.login.State.StateLabel;
 import org.mozilla.gecko.fxa.login.StateFactory;
 import org.mozilla.gecko.fxa.sync.FxAccountNotificationManager;
 import org.mozilla.gecko.fxa.sync.FxAccountSyncAdapter;
 
-import android.accounts.AbstractAccountAuthenticator;
-import android.accounts.Account;
-import android.accounts.AccountAuthenticatorResponse;
-import android.accounts.AccountManager;
-import android.accounts.NetworkErrorException;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
+import java.security.NoSuchAlgorithmException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 
 public class FxAccountAuthenticator extends AbstractAccountAuthenticator {
   public static final String LOG_TAG = FxAccountAuthenticator.class.getSimpleName();
   public static final int UNKNOWN_ERROR_CODE = 999;
 
   protected final Context context;
   protected final AccountManager accountManager;
 
@@ -66,17 +64,17 @@ public class FxAccountAuthenticator exte
     final Bundle res = new Bundle();
 
     if (!FxAccountConstants.ACCOUNT_TYPE.equals(accountType)) {
       res.putInt(AccountManager.KEY_ERROR_CODE, -1);
       res.putString(AccountManager.KEY_ERROR_MESSAGE, "Not adding unknown account type.");
       return res;
     }
 
-    Intent intent = new Intent(context, FxAccountGetStartedActivity.class);
+    final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
     res.putParcelable(AccountManager.KEY_INTENT, intent);
     return res;
   }
 
   @Override
   public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options)
       throws NetworkErrorException {
     Logger.debug(LOG_TAG, "confirmCredentials");
--- a/mobile/android/base/fxa/sync/FxAccountNotificationManager.java
+++ b/mobile/android/base/fxa/sync/FxAccountNotificationManager.java
@@ -1,32 +1,30 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa.sync;
 
-import org.mozilla.gecko.BrowserLocaleManager;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.common.telemetry.TelemetryWrapper;
-import org.mozilla.gecko.background.fxa.FxAccountUtils;
-import org.mozilla.gecko.fxa.activities.FxAccountFinishMigratingActivity;
-import org.mozilla.gecko.fxa.activities.FxAccountStatusActivity;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.fxa.login.State;
-import org.mozilla.gecko.fxa.login.State.Action;
-import org.mozilla.gecko.sync.telemetry.TelemetryContract;
-
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.support.v4.app.NotificationCompat;
 import android.support.v4.app.NotificationCompat.Builder;
+import org.mozilla.gecko.BrowserLocaleManager;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.background.common.telemetry.TelemetryWrapper;
+import org.mozilla.gecko.background.fxa.FxAccountUtils;
+import org.mozilla.gecko.fxa.FxAccountConstants;
+import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
+import org.mozilla.gecko.fxa.login.State;
+import org.mozilla.gecko.fxa.login.State.Action;
+import org.mozilla.gecko.sync.telemetry.TelemetryContract;
 
 /**
  * Abstraction that manages notifications shown or hidden for a Firefox Account.
  * <p>
  * In future, we anticipate this tracking things like:
  * <ul>
  * <li>new engines to offer to Sync;</li>
  * <li>service interruption updates;</li>
@@ -84,21 +82,21 @@ public class FxAccountNotificationManage
     final String title;
     final String text;
     final Intent notificationIntent;
     if (action == Action.NeedsFinishMigrating) {
       TelemetryWrapper.addToHistogram(TelemetryContract.SYNC11_MIGRATION_NOTIFICATIONS_OFFERED, 1);
 
       title = context.getResources().getString(R.string.fxaccount_sync_finish_migrating_notification_title);
       text = context.getResources().getString(R.string.fxaccount_sync_finish_migrating_notification_text, state.email);
-      notificationIntent = new Intent(context, FxAccountFinishMigratingActivity.class);
+      notificationIntent = new Intent(FxAccountConstants.ACTION_FXA_FINISH_MIGRATING);
     } else {
       title = context.getResources().getString(R.string.fxaccount_sync_sign_in_error_notification_title);
       text = context.getResources().getString(R.string.fxaccount_sync_sign_in_error_notification_text, state.email);
-      notificationIntent = new Intent(context, FxAccountStatusActivity.class);
+      notificationIntent = new Intent(FxAccountConstants.ACTION_FXA_STATUS);
     }
     Logger.info(LOG_TAG, "State " + state.getStateLabel() + " needs action; offering notification with title: " + title);
     FxAccountUtils.pii(LOG_TAG, "And text: " + text);
 
     final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
 
     final Builder builder = new NotificationCompat.Builder(context);
     builder
--- a/mobile/android/base/home/RemoteTabsStaticFragment.java
+++ b/mobile/android/base/home/RemoteTabsStaticFragment.java
@@ -1,30 +1,27 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.home;
 
-import java.util.EnumSet;
-import java.util.Locale;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.fxa.FirefoxAccounts;
-import org.mozilla.gecko.fxa.activities.FxAccountCreateAccountActivity;
-import org.mozilla.gecko.fxa.activities.FxAccountFinishMigratingActivity;
-import org.mozilla.gecko.fxa.activities.FxAccountUpdateCredentialsActivity;
-import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
-
 import android.content.Intent;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.fxa.FirefoxAccounts;
+import org.mozilla.gecko.fxa.FxAccountConstants;
+import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
+
+import java.util.EnumSet;
+import java.util.Locale;
 
 /**
  * A <code>HomeFragment</code> which displays one of a small set of static views
  * in response to different Firefox Account states. When the Firefox Account is
  * healthy and syncing normally, these views should not be shown.
  * <p>
  * This class exists to handle view-specific actions when buttons and links
  * shown by the different static views are clicked. For example, a static view
@@ -97,37 +94,36 @@ public class RemoteTabsStaticFragment ex
         }
     }
 
     @Override
     public void onClick(final View v) {
         final int id = v.getId();
         if (id == R.id.remote_tabs_setup_get_started) {
             // This Activity will redirect to the correct Activity as needed.
-            final Intent intent = new Intent(getActivity(), FxAccountCreateAccountActivity.class);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
             startActivity(intent);
         } else if (id == R.id.remote_tabs_setup_old_sync_link) {
             final String url = FirefoxAccounts.getOldSyncUpgradeURL(getResources(), Locale.getDefault());
             // Don't allow switch-to-tab.
             final EnumSet<OnUrlOpenListener.Flags> flags = EnumSet.noneOf(OnUrlOpenListener.Flags.class);
             mUrlOpenListener.onUrlOpen(url, flags);
         } else if (id == R.id.remote_tabs_needs_verification_resend_email) {
             // Send a fresh email; this displays a toast, so the user gets feedback.
             FirefoxAccounts.resendVerificationEmail(getActivity());
         } else if (id == R.id.remote_tabs_needs_verification_help) {
             // Don't allow switch-to-tab.
             final EnumSet<OnUrlOpenListener.Flags> flags = EnumSet.noneOf(OnUrlOpenListener.Flags.class);
             mUrlOpenListener.onUrlOpen(CONFIRM_ACCOUNT_SUPPORT_URL, flags);
         } else if (id == R.id.remote_tabs_needs_password_sign_in) {
-            final Intent intent = new Intent(getActivity(), FxAccountUpdateCredentialsActivity.class);
+            final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_UPDATE_CREDENTIALS);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             startActivity(intent);
         } else if (id == R.id.remote_tabs_needs_finish_migrating_sign_in) {
-            final Intent intent = new Intent(getActivity(), FxAccountFinishMigratingActivity.class);
+            final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_FINISH_MIGRATING);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             startActivity(intent);
         }
     }
 
     @Override
     protected void load() {
         // We're static, so nothing to do here!
--- a/mobile/android/base/overlays/service/sharemethods/SendTab.java
+++ b/mobile/android/base/overlays/service/sharemethods/SendTab.java
@@ -1,35 +1,31 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.overlays.service.sharemethods;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
-import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.support.v4.content.LocalBroadcastManager;
 import android.util.Log;
-
 import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.db.RemoteClient;
 import org.mozilla.gecko.db.TabsAccessor;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.FxAccountConstants;
-import org.mozilla.gecko.fxa.activities.FxAccountGetStartedActivity;
-import org.mozilla.gecko.fxa.activities.FxAccountStatusActivity;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 import org.mozilla.gecko.fxa.login.State;
 import org.mozilla.gecko.overlays.OverlayConstants;
 import org.mozilla.gecko.overlays.service.ShareData;
 import org.mozilla.gecko.sync.CommandProcessor;
 import org.mozilla.gecko.sync.CommandRunner;
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.SyncConfiguration;
@@ -154,17 +150,17 @@ public class SendTab extends ShareMethod
         if (fxAccounts.length > 0) {
             final AndroidFxAccount fxAccount = new AndroidFxAccount(context, fxAccounts[0]);
             if (fxAccount.getState().getNeededAction() != State.Action.None) {
                 // We have a Firefox Account, but it's definitely not able to send a tab
                 // right now. Redirect to the status activity.
                 Log.w(LOGTAG, "Firefox Account named like " + fxAccount.getObfuscatedEmail() +
                               " needs action before it can send a tab; redirecting to status activity.");
 
-                setOverrideIntent(FxAccountStatusActivity.class);
+                setOverrideIntentAction(FxAccountConstants.ACTION_FXA_STATUS);
                 return;
             }
 
             tabSender = new FxAccountTabSender(fxAccount);
 
             updateClientList(tabSender);
 
             Log.i(LOGTAG, "Allowing tab send for Firefox Account.");
@@ -179,17 +175,17 @@ public class SendTab extends ShareMethod
             updateClientList(tabSender);
 
             Log.i(LOGTAG, "Allowing tab send for Sync account.");
             registerDisplayURICommand();
             return;
         }
 
         // Have registered UIs offer to set up a Firefox Account.
-        setOverrideIntent(FxAccountGetStartedActivity.class);
+        setOverrideIntentAction(FxAccountConstants.ACTION_FXA_GET_STARTED);
     }
 
     /**
      * Load the list of Sync clients that are not this device using the given TabSender.
      */
     private void updateClientList(TabSender tabSender) {
         Collection<RemoteClient> otherClients = getOtherClients(tabSender);
 
@@ -201,37 +197,37 @@ public class SendTab extends ShareMethod
 
         for (RemoteClient client : otherClients) {
             validGUIDs.add(client.guid);
         }
 
         if (validGUIDs.isEmpty()) {
             // Guess we'd better override. We have no clients.
             // This does the broadcast for us.
-            setOverrideIntent(FxAccountGetStartedActivity.class);
+            setOverrideIntentAction(FxAccountConstants.ACTION_FXA_GET_STARTED);
             return;
         }
 
         Intent uiStateIntent = getUIStateIntent();
         uiStateIntent.putExtra(EXTRA_REMOTE_CLIENT_RECORDS, records);
         broadcastUIState(uiStateIntent);
     }
 
     /**
      * Record our intention to redirect the user to a different activity when they attempt to share
      * with us, usually because we found something wrong with their Sync account (a need to login,
      * register, etc.)
      * This will be recorded in the OVERRIDE_INTENT field of the UI broadcast. Consumers should
      * dispatch this intent instead of attempting to share with this ShareMethod whenever it is
      * non-null.
      *
-     * @param activityClass The class of the activity we wish to launch instead of invoking a share.
+     * @param action to launch instead of invoking a share.
      */
-    protected void setOverrideIntent(Class<? extends Activity> activityClass) {
-        Intent intent = new Intent(context, activityClass);
+    protected void setOverrideIntentAction(final String action) {
+        Intent intent = new Intent(action);
         // 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?
         intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
         Intent uiStateIntent = getUIStateIntent();
         uiStateIntent.putExtra(OVERRIDE_INTENT, intent);
 
--- a/mobile/android/base/preferences/SyncPreference.java
+++ b/mobile/android/base/preferences/SyncPreference.java
@@ -1,27 +1,25 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.preferences;
 
-import org.mozilla.gecko.Telemetry;
-import org.mozilla.gecko.TelemetryContract;
-import org.mozilla.gecko.TelemetryContract.Method;
-import org.mozilla.gecko.fxa.activities.FxAccountGetStartedActivity;
-import org.mozilla.gecko.sync.setup.SyncAccounts;
-import org.mozilla.gecko.sync.setup.activities.SetupSyncActivity;
-import org.mozilla.gecko.util.HardwareUtils;
-
 import android.content.Context;
 import android.content.Intent;
 import android.preference.Preference;
 import android.util.AttributeSet;
+import org.mozilla.gecko.Telemetry;
+import org.mozilla.gecko.TelemetryContract;
+import org.mozilla.gecko.TelemetryContract.Method;
+import org.mozilla.gecko.fxa.FxAccountConstants;
+import org.mozilla.gecko.sync.setup.SyncAccounts;
+import org.mozilla.gecko.sync.setup.activities.SetupSyncActivity;
 
 class SyncPreference extends Preference {
     private static final boolean DEFAULT_TO_FXA = true;
 
     private final Context mContext;
 
     public SyncPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -36,23 +34,19 @@ class SyncPreference extends Preference 
             SyncAccounts.openSyncSettings(mContext);
             return;
         }
         Intent intent = new Intent(mContext, SetupSyncActivity.class);
         mContext.startActivity(intent);
     }
 
     private void launchFxASetup() {
-        Intent intent = new Intent(mContext, FxAccountGetStartedActivity.class);
+        final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        if (HardwareUtils.IS_KINDLE_DEVICE) {
-            intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
-        }
-
+        intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
         mContext.startActivity(intent);
     }
 
     @Override
     protected void onClick() {
         // If we're not defaulting to FxA, just do what we've always done.
         if (!DEFAULT_TO_FXA) {
             openSync11Settings();
--- a/mobile/android/services/manifests/FxAccountAndroidManifest_activities.xml.in
+++ b/mobile/android/services/manifests/FxAccountAndroidManifest_activities.xml.in
@@ -7,47 +7,63 @@
             android:configChanges="locale|layoutDirection"
             android:windowSoftInputMode="adjustResize">
             <!-- Adding a launcher will make this activity appear on the
                  Apps screen, which we only want when testing. -->
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <!-- <category android:name="android.intent.category.LAUNCHER" /> -->
             </intent-filter>
+            <intent-filter>
+                <action android:name="@ANDROID_PACKAGE_NAME@.ACTION_FXA_STATUS"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
         </activity>
 
         <activity
             android:theme="@style/FxAccountTheme"
             android:label="@string/sync_app_name"
             android:clearTaskOnLaunch="true"
             android:taskAffinity="@ANDROID_PACKAGE_NAME@.FXA"
             android:name="org.mozilla.gecko.fxa.activities.FxAccountGetStartedActivity"
             android:configChanges="locale|layoutDirection"
             android:windowSoftInputMode="adjustResize">
             <!-- Adding a launcher will make this activity appear on the
                  Apps screen, which we only want when testing. -->
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <!-- <category android:name="android.intent.category.LAUNCHER" /> -->
             </intent-filter>
+#ifdef MOZ_ANDROID_NATIVE_ACCOUNT_UI
+            <intent-filter>
+                <action android:name="@ANDROID_PACKAGE_NAME@.ACTION_FXA_GET_STARTED"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+#endif
         </activity>
 
         <activity
             android:theme="@style/FxAccountTheme"
             android:name="org.mozilla.gecko.fxa.activities.FxAccountCreateAccountActivity"
             android:configChanges="locale|layoutDirection"
             android:windowSoftInputMode="adjustResize">
         </activity>
 
         <activity
             android:theme="@style/FxAccountTheme"
             android:name="org.mozilla.gecko.fxa.activities.FxAccountConfirmAccountActivity"
             android:configChanges="locale|layoutDirection"
             android:noHistory="true"
             android:windowSoftInputMode="adjustResize">
+#ifdef MOZ_ANDROID_NATIVE_ACCOUNT_UI
+            <intent-filter>
+                <action android:name="@ANDROID_PACKAGE_NAME@.ACTION_FXA_CONFIRM_ACCOUNT"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+#endif
         </activity>
 
         <activity
             android:theme="@style/FxAccountTheme"
             android:name="org.mozilla.gecko.fxa.activities.FxAccountSignInActivity"
             android:configChanges="locale|layoutDirection"
             android:windowSoftInputMode="adjustResize">
         </activity>
@@ -60,23 +76,35 @@
             android:windowSoftInputMode="adjustResize">
         </activity>
 
         <activity
             android:theme="@style/FxAccountTheme"
             android:name="org.mozilla.gecko.fxa.activities.FxAccountUpdateCredentialsActivity"
             android:configChanges="locale|layoutDirection"
             android:windowSoftInputMode="adjustResize">
+#ifdef MOZ_ANDROID_NATIVE_ACCOUNT_UI
+            <intent-filter>
+                <action android:name="@ANDROID_PACKAGE_NAME@.ACTION_FXA_UPDATE_CREDENTIALS"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+#endif
         </activity>
 
         <activity
             android:theme="@style/FxAccountTheme"
             android:name="org.mozilla.gecko.fxa.activities.FxAccountFinishMigratingActivity"
             android:configChanges="locale|layoutDirection"
             android:windowSoftInputMode="adjustResize">
+#ifdef MOZ_ANDROID_NATIVE_ACCOUNT_UI
+            <intent-filter>
+                <action android:name="@ANDROID_PACKAGE_NAME@.ACTION_FXA_FINISH_MIGRATING"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+#endif
         </activity>
 
         <activity
             android:theme="@style/FxAccountTheme"
             android:name="org.mozilla.gecko.fxa.activities.FxAccountMigrationFinishedActivity"
             android:configChanges="locale|layoutDirection"
             android:noHistory="true"
             android:windowSoftInputMode="adjustResize">