Merge f-t to m-c, a=merge

This commit is contained in:
Phil Ringnalda 2015-01-17 13:09:20 -08:00
commit b7929d83b1
24 changed files with 316 additions and 82 deletions

View File

@ -924,13 +924,16 @@
var controller = this.view.QueryInterface(Components.interfaces.nsIAutoCompleteController);
// Check for unmodified left-click, and use default behavior
var searchBar = BrowserSearch.searchBar;
searchBar.telemetrySearchDetails = {
index: controller.selection.currentIndex,
kind: "mouse"
};
var popupForSearchBar = searchBar && searchBar.textbox == this.mInput;
if (popupForSearchBar) {
searchBar.telemetrySearchDetails = {
index: controller.selection.currentIndex,
kind: "mouse"
};
}
// Check for unmodified left-click, and use default behavior
if (aEvent.button == 0 && !aEvent.shiftKey && !aEvent.ctrlKey &&
!aEvent.altKey && !aEvent.metaKey) {
controller.handleEnter(true);
@ -938,7 +941,7 @@
}
// Check for middle-click or modified clicks on the search bar
if (searchBar && searchBar.textbox == this.mInput) {
if (popupForSearchBar) {
// Handle search bar popup clicks
var search = controller.getValueAt(this.selectedIndex);

View File

@ -187,7 +187,7 @@ public class BrowserApp extends GeckoApp
private ViewGroup mHomePagerContainer;
protected Telemetry.Timer mAboutHomeStartupTimer;
private ActionModeCompat mActionMode;
private boolean mShowActionModeEndAnimation;
private boolean mHideDynamicToolbarOnActionModeEnd;
private TabHistoryController tabHistoryController;
private static final int GECKO_TOOLS_MENU = -1;
@ -294,6 +294,8 @@ public class BrowserApp extends GeckoApp
if (Tabs.getInstance().isSelectedTab(tab)) {
updateHomePagerForTab(tab);
}
mHideDynamicToolbarOnActionModeEnd = false;
break;
case START:
if (Tabs.getInstance().isSelectedTab(tab)) {
@ -3322,10 +3324,11 @@ public class BrowserApp extends GeckoApp
if (mDynamicToolbar.isEnabled() && !margins.areMarginsShown()) {
margins.setMaxMargins(0, mBrowserChrome.getHeight(), 0, 0);
mDynamicToolbar.setVisible(true, VisibilityTransition.ANIMATE);
mShowActionModeEndAnimation = true;
mHideDynamicToolbarOnActionModeEnd = true;
} else {
// Otherwise, we animate the actionbar itself
mActionBar.animateIn();
mHideDynamicToolbarOnActionModeEnd = false;
}
mDynamicToolbar.setPinned(true, PinReason.ACTION_MODE);
@ -3355,9 +3358,8 @@ public class BrowserApp extends GeckoApp
// Only slide the urlbar out if it was hidden when the action mode started
// Don't animate hiding it so that there's no flash as we switch back to url mode
if (mShowActionModeEndAnimation) {
if (mHideDynamicToolbarOnActionModeEnd) {
mDynamicToolbar.setVisible(false, VisibilityTransition.IMMEDIATE);
mShowActionModeEndAnimation = false;
}
}

View File

@ -780,6 +780,7 @@ sync_java_files = [
'background/common/log/writers/StringLogWriter.java',
'background/common/log/writers/TagLogWriter.java',
'background/common/log/writers/ThreadLocalTagLogWriter.java',
'background/common/telemetry/TelemetryWrapper.java',
'background/datareporting/TelemetryRecorder.java',
'background/db/CursorDumper.java',
'background/db/Tab.java',
@ -1132,6 +1133,7 @@ sync_java_files = [
'sync/synchronizer/UnbundleError.java',
'sync/synchronizer/UnexpectedSessionException.java',
'sync/SynchronizerConfiguration.java',
'sync/telemetry/TelemetryContract.java',
'sync/ThreadPool.java',
'sync/UnexpectedJSONException.java',
'sync/UnknownSynchronizerConfigurationVersionException.java',

View File

@ -0,0 +1,56 @@
/* 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.background.common.telemetry;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.mozilla.gecko.background.common.log.Logger;
/**
* Android Background Services are normally built into Fennec, but can also be
* built as a stand-alone APK for rapid local development. The current Telemetry
* implementation is coupled to Gecko, and Background Services should not
* interact with Gecko directly. To maintain this independence, Background
* Services lazily introspects the relevant Telemetry class from the enclosing
* package, warning but otherwise ignoring failures during introspection or
* invocation.
* <p>
* It is possible that Background Services will introspect and invoke the
* Telemetry implementation while Gecko is not running. In this case, the Fennec
* process itself buffers Telemetry events until such time as they can be
* flushed to disk and uploaded. <b>There is no guarantee that all Telemetry
* events will be uploaded!</b> Depending on the volume of data and the
* application lifecycle, Telemetry events may be dropped.
*/
public class TelemetryWrapper {
private static final String LOG_TAG = TelemetryWrapper.class.getSimpleName();
// Marking this volatile maintains thread safety cheaply.
private static volatile Method mAddToHistogram;
public static void addToHistogram(String key, int value) {
if (mAddToHistogram == null) {
try {
final Class<?> telemetry = Class.forName("org.mozilla.gecko.Telemetry");
mAddToHistogram = telemetry.getMethod("addToHistogram", String.class, int.class);
} catch (ClassNotFoundException e) {
Logger.warn(LOG_TAG, "org.mozilla.gecko.Telemetry class found!");
return;
} catch (NoSuchMethodException e) {
Logger.warn(LOG_TAG, "org.mozilla.gecko.Telemetry.addToHistogram(String, int) method not found!");
return;
}
}
if (mAddToHistogram != null) {
try {
mAddToHistogram.invoke(null, key, value);
} catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
Logger.warn(LOG_TAG, "Got exception invoking telemetry!");
}
}
}
}

View File

@ -4,6 +4,8 @@
package org.mozilla.gecko.background.fxa;
import java.util.Map;
import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate;
import org.mozilla.gecko.background.fxa.FxAccountClient10.StatusResponse;
import org.mozilla.gecko.background.fxa.FxAccountClient10.TwoKeys;
@ -11,8 +13,8 @@ import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse;
import org.mozilla.gecko.sync.ExtendedJSONObject;
public interface FxAccountClient {
public void createAccountAndGetKeys(final byte[] emailUTF8, final PasswordStretcher passwordStretcher, final RequestDelegate<LoginResponse> delegate);
public void loginAndGetKeys(final byte[] emailUTF8, final PasswordStretcher passwordStretcher, final RequestDelegate<LoginResponse> requestDelegate);
public void createAccountAndGetKeys(final byte[] emailUTF8, final PasswordStretcher passwordStretcher, final Map<String, String> queryParameters, final RequestDelegate<LoginResponse> delegate);
public void loginAndGetKeys(final byte[] emailUTF8, final PasswordStretcher passwordStretcher, final Map<String, String> queryParameters, final RequestDelegate<LoginResponse> requestDelegate);
public void status(byte[] sessionToken, RequestDelegate<StatusResponse> requestDelegate);
public void keys(byte[] keyFetchToken, RequestDelegate<TwoKeys> requestDelegate);
public void sign(byte[] sessionToken, ExtendedJSONObject publicKey, long certificateDurationInMilliseconds, RequestDelegate<String> requestDelegate);

View File

@ -8,11 +8,14 @@ import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Executor;
import javax.crypto.Mac;
@ -71,7 +74,6 @@ public class FxAccountClient10 {
public static final String JSON_KEY_CODE = "code";
public static final String JSON_KEY_ERRNO = "errno";
protected static final String[] requiredErrorStringFields = { JSON_KEY_ERROR, JSON_KEY_MESSAGE, JSON_KEY_INFO };
protected static final String[] requiredErrorLongFields = { JSON_KEY_CODE, JSON_KEY_ERRNO };
@ -99,6 +101,48 @@ public class FxAccountClient10 {
this.executor = executor;
}
protected BaseResource getBaseResource(String path, Map<String, String> queryParameters) throws UnsupportedEncodingException, URISyntaxException {
if (queryParameters == null || queryParameters.isEmpty()) {
return getBaseResource(path);
}
final String[] array = new String[2 * queryParameters.size()];
int i = 0;
for (Entry<String, String> entry : queryParameters.entrySet()) {
array[i++] = entry.getKey();
array[i++] = entry.getValue();
}
return getBaseResource(path, array);
}
/**
* Create <code>BaseResource</code>, encoding query parameters carefully.
* <p>
* This is equivalent to <code>android.net.Uri.Builder</code>, which is not
* present in our JUnit 4 tests.
*
* @param path fragment.
* @param queryParameters list of key/value query parameter pairs. Must be even length!
* @return <code>BaseResource<instance>
* @throws URISyntaxException
* @throws UnsupportedEncodingException
*/
protected BaseResource getBaseResource(String path, String... queryParameters) throws URISyntaxException, UnsupportedEncodingException {
final StringBuilder sb = new StringBuilder(serverURI);
sb.append(path);
if (queryParameters != null) {
int i = 0;
while (i < queryParameters.length) {
sb.append(i > 0 ? "&" : "?");
final String key = queryParameters[i++];
final String val = queryParameters[i++];
sb.append(URLEncoder.encode(key, "UTF-8"));
sb.append("=");
sb.append(URLEncoder.encode(val, "UTF-8"));
}
}
return new BaseResource(new URI(sb.toString()));
}
/**
* Process a typed value extracted from a successful response (in an
* endpoint-dependent way).
@ -353,8 +397,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "account/create"));
} catch (URISyntaxException e) {
resource = getBaseResource("account/create");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -384,8 +428,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "auth/start"));
} catch (URISyntaxException e) {
resource = getBaseResource("auth/start");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -416,8 +460,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "auth/finish"));
} catch (URISyntaxException e) {
resource = getBaseResource("auth/finish");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -480,8 +524,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "session/create"));
} catch (URISyntaxException e) {
resource = getBaseResource("session/create");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -516,8 +560,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "session/destroy"));
} catch (URISyntaxException e) {
resource = getBaseResource("session/destroy");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -605,8 +649,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "account/keys"));
} catch (URISyntaxException e) {
resource = getBaseResource("account/keys");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -667,8 +711,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "recovery_email/status"));
} catch (URISyntaxException e) {
resource = getBaseResource("recovery_email/status");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -709,8 +753,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "certificate/sign"));
} catch (URISyntaxException e) {
resource = getBaseResource("certificate/sign");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -750,8 +794,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "recovery_email/resend_code"));
} catch (URISyntaxException e) {
resource = getBaseResource("recovery_email/resend_code");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -788,7 +832,7 @@ public class FxAccountClient10 {
final BaseResource resource;
final JSONObject body = new JSONObject();
try {
resource = new BaseResource(new URI(serverURI + "account/unlock/resend_code"));
resource = getBaseResource("account/unlock/resend_code");
body.put("email", new String(emailUTF8, "UTF-8"));
} catch (URISyntaxException e) {
invokeHandleError(delegate, e);

View File

@ -4,10 +4,8 @@
package org.mozilla.gecko.background.fxa;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import org.json.simple.JSONObject;
@ -53,12 +51,20 @@ public class FxAccountClient20 extends FxAccountClient10 implements FxAccountCli
// Public for testing only; prefer login and loginAndGetKeys (without boolean parameter).
public void login(final byte[] emailUTF8, final byte[] quickStretchedPW, final boolean getKeys,
final Map<String, String> queryParameters,
final RequestDelegate<LoginResponse> delegate) {
BaseResource resource;
JSONObject body;
final String path = getKeys ? "account/login?keys=true" : "account/login";
final BaseResource resource;
final JSONObject body;
try {
resource = new BaseResource(new URI(serverURI + path));
final String path = "account/login";
final Map<String, String> modifiedParameters = new HashMap<>();
if (queryParameters != null) {
modifiedParameters.putAll(queryParameters);
}
if (getKeys) {
modifiedParameters.put("keys", "true");
}
resource = getBaseResource(path, modifiedParameters);
body = new FxAccount20LoginDelegate(emailUTF8, quickStretchedPW).getCreateBody();
} catch (Exception e) {
invokeHandleError(delegate, e);
@ -96,35 +102,23 @@ public class FxAccountClient20 extends FxAccountClient10 implements FxAccountCli
post(resource, body, delegate);
}
/**
* Create account/create URI, encoding query parameters carefully.
* <p>
* This is equivalent to <code>android.net.Uri.Builder</code>, which is not
* present in our JUnit 4 tests.
*/
protected URI getCreateAccountURI(final boolean getKeys, final String service) throws UnsupportedEncodingException, URISyntaxException {
if (service == null) {
throw new IllegalArgumentException("service must not be null");
}
final StringBuilder sb = new StringBuilder(serverURI); // serverURI always has a trailing slash.
sb.append("account/create?service=");
// Be very careful that query parameters are encoded correctly!
sb.append(URLEncoder.encode(service, "UTF-8"));
if (getKeys) {
sb.append("&keys=true");
}
return new URI(sb.toString());
}
public void createAccount(final byte[] emailUTF8, final byte[] quickStretchedPW,
final boolean getKeys,
final boolean preVerified,
final String service,
final Map<String, String> queryParameters,
final RequestDelegate<LoginResponse> delegate) {
final BaseResource resource;
final JSONObject body;
try {
resource = new BaseResource(getCreateAccountURI(getKeys, service));
final String path = "account/create";
final Map<String, String> modifiedParameters = new HashMap<>();
if (queryParameters != null) {
modifiedParameters.putAll(queryParameters);
}
if (getKeys) {
modifiedParameters.put("keys", "true");
}
resource = getBaseResource(path, modifiedParameters);
body = new FxAccount20CreateDelegate(emailUTF8, quickStretchedPW, preVerified).getCreateBody();
} catch (Exception e) {
invokeHandleError(delegate, e);
@ -163,18 +157,18 @@ public class FxAccountClient20 extends FxAccountClient10 implements FxAccountCli
}
@Override
public void createAccountAndGetKeys(byte[] emailUTF8, PasswordStretcher passwordStretcher, RequestDelegate<LoginResponse> delegate) {
public void createAccountAndGetKeys(byte[] emailUTF8, PasswordStretcher passwordStretcher, final Map<String, String> queryParameters, RequestDelegate<LoginResponse> delegate) {
try {
byte[] quickStretchedPW = passwordStretcher.getQuickStretchedPW(emailUTF8);
createAccount(emailUTF8, quickStretchedPW, true, false, "sync", delegate);
createAccount(emailUTF8, quickStretchedPW, true, false, queryParameters, delegate);
} catch (Exception e) {
invokeHandleError(delegate, e);
}
}
@Override
public void loginAndGetKeys(byte[] emailUTF8, PasswordStretcher passwordStretcher, RequestDelegate<LoginResponse> delegate) {
login(emailUTF8, passwordStretcher, true, delegate);
public void loginAndGetKeys(byte[] emailUTF8, PasswordStretcher passwordStretcher, final Map<String, String> queryParameters, RequestDelegate<LoginResponse> delegate) {
login(emailUTF8, passwordStretcher, true, queryParameters, delegate);
}
/**
@ -198,10 +192,12 @@ public class FxAccountClient20 extends FxAccountClient10 implements FxAccountCli
* @param getKeys
* true if a <code>keyFetchToken</code> should be returned (in
* addition to the standard <code>sessionToken</code>).
* @param queryParameters
* @param delegate
* to invoke callbacks.
*/
public void login(final byte[] emailUTF8, final PasswordStretcher stretcher, final boolean getKeys,
final Map<String, String> queryParameters,
final RequestDelegate<LoginResponse> delegate) {
byte[] quickStretchedPW;
try {
@ -212,7 +208,7 @@ public class FxAccountClient20 extends FxAccountClient10 implements FxAccountCli
return;
}
this.login(emailUTF8, quickStretchedPW, getKeys, new RequestDelegate<LoginResponse>() {
this.login(emailUTF8, quickStretchedPW, getKeys, queryParameters, new RequestDelegate<LoginResponse>() {
@Override
public void handleSuccess(LoginResponse result) {
delegate.handleSuccess(result);
@ -239,7 +235,7 @@ public class FxAccountClient20 extends FxAccountClient10 implements FxAccountCli
// signature here, which invokes a non-retrying version.
byte[] alternateEmailUTF8 = alternateEmail.getBytes("UTF-8");
byte[] alternateQuickStretchedPW = stretcher.getQuickStretchedPW(alternateEmailUTF8);
login(alternateEmailUTF8, alternateQuickStretchedPW, getKeys, delegate);
login(alternateEmailUTF8, alternateQuickStretchedPW, getKeys, queryParameters, delegate);
} catch (Exception innerException) {
delegate.handleError(innerException);
return;

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko.fxa.activities;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@ -565,4 +566,10 @@ abstract public class FxAccountAbstractSetupActivity extends FxAccountAbstractAc
ensureFindViewById(null, R.id.account_server_layout, "account server layout").setVisibility(visibility);
ensureFindViewById(null, R.id.sync_server_layout, "sync server layout").setVisibility(visibility);
}
protected Map<String, String> getQueryParameters() {
final Map<String, String> queryParameters = new HashMap<>();
queryParameters.put("service", "sync");
return queryParameters;
}
}

View File

@ -9,6 +9,7 @@ import java.util.concurrent.Executors;
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;
@ -22,6 +23,7 @@ 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;
@ -150,6 +152,8 @@ public abstract class FxAccountAbstractUpdateCredentialsActivity extends FxAccou
startActivity(successIntent);
}
finish();
TelemetryWrapper.addToHistogram(TelemetryContract.SYNC11_MIGRATIONS_COMPLETED, 1);
}
}
@ -161,7 +165,7 @@ public abstract class FxAccountAbstractUpdateCredentialsActivity extends FxAccou
try {
hideRemoteError();
RequestDelegate<LoginResponse> delegate = new UpdateCredentialsDelegate(email, passwordStretcher, serverURI);
new FxAccountSignInTask(this, this, email, passwordStretcher, client, delegate).execute();
new FxAccountSignInTask(this, this, email, passwordStretcher, client, getQueryParameters(), delegate).execute();
} catch (Exception e) {
Logger.warn(LOG_TAG, "Got exception updating credentials for account.", e);
showRemoteError(e, R.string.fxaccount_update_credentials_unknown_error);

View File

@ -221,7 +221,7 @@ public class FxAccountCreateAccountActivity extends FxAccountAbstractSetupActivi
FxAccountClient client = new FxAccountClient20(serverURI, executor);
try {
hideRemoteError();
new FxAccountCreateAccountTask(this, this, email, passwordStretcher, client, delegate).execute();
new FxAccountCreateAccountTask(this, this, email, passwordStretcher, client, getQueryParameters(), delegate).execute();
} catch (Exception e) {
showRemoteError(e, R.string.fxaccount_create_account_unknown_error);
}

View File

@ -4,6 +4,8 @@
package org.mozilla.gecko.fxa.activities;
import java.util.Map;
import org.mozilla.gecko.R;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse;
@ -51,4 +53,11 @@ public class FxAccountFinishMigratingActivity extends FxAccountAbstractUpdateCre
successIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
return successIntent;
}
@Override
protected Map<String, String> getQueryParameters() {
final Map<String, String> queryParameters = super.getQueryParameters();
queryParameters.put("migration", "sync11");
return queryParameters;
}
}

View File

@ -111,7 +111,7 @@ public class FxAccountSignInActivity extends FxAccountAbstractSetupActivity {
FxAccountClient client = new FxAccountClient20(serverURI, executor);
try {
hideRemoteError();
new FxAccountSignInTask(this, this, email, passwordStretcher, client, delegate).execute();
new FxAccountSignInTask(this, this, email, passwordStretcher, client, getQueryParameters(), delegate).execute();
} catch (Exception e) {
showRemoteError(e, R.string.fxaccount_sign_in_unknown_error);
}

View File

@ -6,6 +6,8 @@ package org.mozilla.gecko.fxa.receivers;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.fxa.FxAccountConstants;
import org.mozilla.gecko.fxa.sync.FxAccountNotificationManager;
import org.mozilla.gecko.fxa.sync.FxAccountSyncAdapter;
import org.mozilla.gecko.sync.config.AccountPickler;
import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
@ -63,6 +65,9 @@ public class FxAccountDeletedService extends IntentService {
// Delete client database and non-local tabs.
Logger.info(LOG_TAG, "Deleting the entire clients database and non-local tabs");
FennecTabsRepository.deleteNonLocalClientsAndTabs(context);
// Remove any displayed notifications.
new FxAccountNotificationManager(FxAccountSyncAdapter.NOTIFICATION_ID).clear(context);
}
public static void deletePickle(final Context context) {

View File

@ -7,12 +7,14 @@ 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;
@ -43,6 +45,17 @@ public class FxAccountNotificationManager {
this.notificationId = notificationId;
}
/**
* Remove all Firefox Account related notifications from the notification manager.
*
* @param context
* Android context.
*/
public void clear(Context context) {
final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(notificationId);
}
/**
* Reflect new Firefox Account state to the notification manager: show or hide
* notifications reflecting the state of a Firefox Account.
@ -72,6 +85,8 @@ public class FxAccountNotificationManager {
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);

View File

@ -67,7 +67,7 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter {
public static final String SYNC_EXTRAS_RESPECT_LOCAL_RATE_LIMIT = "respect_local_rate_limit";
public static final String SYNC_EXTRAS_RESPECT_REMOTE_SERVER_BACKOFF = "respect_remote_server_backoff";
protected static final int NOTIFICATION_ID = LOG_TAG.hashCode();
public static final int NOTIFICATION_ID = LOG_TAG.hashCode();
// Tracks the last seen storage hostname for backoff purposes.
private static final String PREF_BACKOFF_STORAGE_HOST = "backoffStorageHost";

View File

@ -17,6 +17,7 @@ import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
import org.mozilla.gecko.fxa.login.Engaged;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;
/**
@ -32,7 +33,7 @@ public class FxAccountCodeResender {
protected final byte[] sessionToken;
public FxAccountResendCodeTask(Context context, byte[] sessionToken, FxAccountClient client, RequestDelegate<Void> delegate) {
super(context, null, client, delegate);
super(context, null, client, null, delegate);
this.sessionToken = sessionToken;
}

View File

@ -5,6 +5,7 @@
package org.mozilla.gecko.fxa.tasks;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.background.fxa.FxAccountClient;
@ -20,8 +21,8 @@ public class FxAccountCreateAccountTask extends FxAccountSetupTask<LoginResponse
protected final byte[] emailUTF8;
protected final PasswordStretcher passwordStretcher;
public FxAccountCreateAccountTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException {
super(context, progressDisplay, client, delegate);
public FxAccountCreateAccountTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, Map<String, String> queryParameters, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException {
super(context, progressDisplay, client, queryParameters, delegate);
this.emailUTF8 = email.getBytes("UTF-8");
this.passwordStretcher = passwordStretcher;
}
@ -29,7 +30,7 @@ public class FxAccountCreateAccountTask extends FxAccountSetupTask<LoginResponse
@Override
protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) {
try {
client.createAccountAndGetKeys(emailUTF8, passwordStretcher, innerDelegate);
client.createAccountAndGetKeys(emailUTF8, passwordStretcher, queryParameters, innerDelegate);
latch.await();
return innerDelegate;
} catch (Exception e) {

View File

@ -4,6 +4,7 @@
package org.mozilla.gecko.fxa.tasks;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import org.mozilla.gecko.background.common.log.Logger;
@ -43,13 +44,16 @@ public abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerR
protected final CountDownLatch latch = new CountDownLatch(1);
protected final InnerRequestDelegate<T> innerDelegate = new InnerRequestDelegate<T>(latch);
protected final Map<String, String> queryParameters;
protected final RequestDelegate<T> delegate;
public FxAccountSetupTask(Context context, ProgressDisplay progressDisplay, FxAccountClient client, RequestDelegate<T> delegate) {
public FxAccountSetupTask(Context context, ProgressDisplay progressDisplay, FxAccountClient client, Map<String, String> queryParameters, RequestDelegate<T> delegate) {
this.context = context;
this.client = client;
this.delegate = delegate;
this.progressDisplay = progressDisplay;
this.queryParameters = queryParameters;
}
@Override

View File

@ -5,6 +5,7 @@
package org.mozilla.gecko.fxa.tasks;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.background.fxa.FxAccountClient;
@ -20,8 +21,8 @@ public class FxAccountSignInTask extends FxAccountSetupTask<LoginResponse> {
protected final byte[] emailUTF8;
protected final PasswordStretcher passwordStretcher;
public FxAccountSignInTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException {
super(context, progressDisplay, client, delegate);
public FxAccountSignInTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, Map<String, String> queryParameters, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException {
super(context, progressDisplay, client, queryParameters, delegate);
this.emailUTF8 = email.getBytes("UTF-8");
this.passwordStretcher = passwordStretcher;
}
@ -29,7 +30,7 @@ public class FxAccountSignInTask extends FxAccountSetupTask<LoginResponse> {
@Override
protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) {
try {
client.loginAndGetKeys(emailUTF8, passwordStretcher, innerDelegate);
client.loginAndGetKeys(emailUTF8, passwordStretcher, queryParameters, innerDelegate);
latch.await();
return innerDelegate;
} catch (Exception e) {

View File

@ -31,7 +31,7 @@ public class FxAccountUnlockCodeResender {
protected final byte[] emailUTF8;
public FxAccountUnlockCodeTask(Context context, byte[] emailUTF8, FxAccountClient client, RequestDelegate<Void> delegate) {
super(context, null, client, delegate);
super(context, null, client, null, delegate);
this.emailUTF8 = emailUTF8;
}

View File

@ -191,7 +191,7 @@
<!ENTITY fxaccount_finish_migrating_header 'Sign in to finish upgrading'>
<!ENTITY fxaccount_finish_migrating_button_label 'Finish upgrading'>
<!ENTITY fxaccount_finish_migrating_description 'Upgrading can transfer a lot of data. It\&apos;s best to be on a WiFi network.'>
<!ENTITY fxaccount_finish_migrating_description 'Upgrading can transfer a lot of data. It\&apos;s best to be on a Wi-Fi network.'>
<!ENTITY fxaccount_status_header2 'Firefox Account'>
<!ENTITY fxaccount_status_signed_in_as 'Signed in as'>

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko.sync;
import java.net.URISyntaxException;
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;
@ -18,6 +19,7 @@ import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
import org.mozilla.gecko.sync.net.SyncStorageResponse;
import org.mozilla.gecko.sync.stage.AbstractNonRepositorySyncStage;
import org.mozilla.gecko.sync.stage.NoSuchStageException;
import org.mozilla.gecko.sync.telemetry.TelemetryContract;
/**
* The purpose of this class is to talk to a Sync 1.1 server and check
@ -152,6 +154,7 @@ public class MigrationSentinelSyncStage extends AbstractNonRepositorySyncStage {
private void onMigrated() {
Logger.info(LOG_TAG, "Account migrated!");
TelemetryWrapper.addToHistogram(TelemetryContract.SYNC11_MIGRATIONS_SUCCEEDED, 1);
session.config.persistLastMigrationSentinelCheckTimestamp(fetchTimestamp);
session.abort(null, "Account migrated.");
}
@ -163,6 +166,7 @@ public class MigrationSentinelSyncStage extends AbstractNonRepositorySyncStage {
private void onError(Exception ex, String reason) {
Logger.info(LOG_TAG, "Could not migrate: " + reason, ex);
TelemetryWrapper.addToHistogram(TelemetryContract.SYNC11_MIGRATIONS_FAILED, 1);
session.abort(ex, reason);
}
@ -181,6 +185,9 @@ public class MigrationSentinelSyncStage extends AbstractNonRepositorySyncStage {
public void handleRequestSuccess(SyncStorageResponse response) {
Logger.info(LOG_TAG, "Found " + META_FXA_CREDENTIALS + " record; attempting migration.");
setTimestamp(response.normalizedWeaveTimestamp());
TelemetryWrapper.addToHistogram(TelemetryContract.SYNC11_MIGRATION_SENTINELS_SEEN, 1);
try {
final ExtendedJSONObject body = response.jsonObjectBody();
final CryptoRecord cryptoRecord = CryptoRecord.fromJSONRecord(body);

View File

@ -0,0 +1,48 @@
/* 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.sync.telemetry;
public class TelemetryContract {
/**
* We are a Sync 1.1 (legacy) client, and we downloaded a migration sentinel.
*/
public static final String SYNC11_MIGRATION_SENTINELS_SEEN = "FENNEC_SYNC11_MIGRATION_SENTINELS_SEEN";
/**
* We are a Sync 1.1 (legacy) client and we have downloaded a migration
* sentinel, but there was an error creating a Firefox Account from that
* sentinel.
* <p>
* We have logged the error and are ignoring that sentinel.
*/
public static final String SYNC11_MIGRATIONS_FAILED = "FENNEC_SYNC11_MIGRATIONS_FAILED";
/**
* We are a Sync 1.1 (legacy) client and we have downloaded a migration
* sentinel, and there was no reported error creating a Firefox Account from
* that sentinel.
* <p>
* We have created a Firefox Account corresponding to the sentinel and have
* queued the existing Old Sync account for removal.
*/
public static final String SYNC11_MIGRATIONS_SUCCEEDED = "FENNEC_SYNC11_MIGRATIONS_SUCCEEDED";
/**
* We are (now) a Sync 1.5 (Firefox Accounts-based) client that migrated from
* Sync 1.1. We have presented the user the "complete upgrade" notification.
* <p>
* We will offer every time a sync is triggered, including when a notification
* is already pending.
*/
public static final String SYNC11_MIGRATION_NOTIFICATIONS_OFFERED = "FENNEC_SYNC11_MIGRATION_NOTIFICATIONS_OFFERED";
/**
* We are (now) a Sync 1.5 (Firefox Accounts-based) client that migrated from
* Sync 1.1. We have presented the user the "complete upgrade" notification
* and they have successfully completed the upgrade process by entering their
* Firefox Account credentials.
*/
public static final String SYNC11_MIGRATIONS_COMPLETED = "FENNEC_SYNC11_MIGRATIONS_COMPLETED";
}

View File

@ -7157,5 +7157,32 @@
"n_buckets" : 50,
"extended_statistics_ok": true,
"description": "The number of saved signons in storage"
},
"FENNEC_SYNC11_MIGRATION_SENTINELS_SEEN": {
"expires_in_version": "45",
"kind": "count",
"description": "The number of Sync 1.1 -> Sync 1.5 migration sentinels seen by Android Sync."
},
"FENNEC_SYNC11_MIGRATIONS_FAILED": {
"expires_in_version": "45",
"kind": "count",
"description": "The number of Sync 1.1 -> Sync 1.5 migrations that failed during Android Sync."
},
"FENNEC_SYNC11_MIGRATIONS_SUCCEEDED": {
"expires_in_version": "45",
"kind": "count",
"description": "The number of Sync 1.1 -> Sync 1.5 migrations that succeeded during Android Sync."
},
"FENNEC_SYNC11_MIGRATION_NOTIFICATIONS_OFFERED": {
"expires_in_version": "45",
"kind": "exponential",
"high": 500,
"n_buckets": 5,
"description": "The number of Sync 1.5 'complete upgrade/migration' notifications offered by Android Sync."
},
"FENNEC_SYNC11_MIGRATIONS_COMPLETED": {
"expires_in_version": "45",
"kind": "count",
"description": "The number of Sync 1.5 migrations completed by Android Sync."
}
}