Bug 1380854 - Track Sign up, Sign in and sync events. r?sdaswani
Created a new event passed between FxAccountsWebChannel and AccountsHelper in order to differentiate between a sign in and an account update.
MozReview-Commit-ID: JMTJC693k7s
--- a/mobile/android/base/java/org/mozilla/gecko/AccountsHelper.java
+++ b/mobile/android/base/java/org/mozilla/gecko/AccountsHelper.java
@@ -17,16 +17,17 @@ import android.util.Log;
import org.json.JSONException;
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.fxa.login.Engaged;
import org.mozilla.gecko.fxa.login.State;
+import org.mozilla.gecko.mma.MmaDelegate;
import org.mozilla.gecko.restrictions.Restrictable;
import org.mozilla.gecko.restrictions.Restrictions;
import org.mozilla.gecko.sync.SyncConfiguration;
import org.mozilla.gecko.sync.Utils;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.ThreadUtils;
@@ -48,28 +49,30 @@ public class AccountsHelper implements B
protected final GeckoProfile mProfile;
public AccountsHelper(Context context, GeckoProfile profile) {
mContext = context;
mProfile = profile;
EventDispatcher.getInstance().registerGeckoThreadListener(this,
"Accounts:CreateFirefoxAccountFromJSON",
+ "Accounts:LoginFirefoxAccountFromJSON",
"Accounts:UpdateFirefoxAccountFromJSON",
"Accounts:DeleteFirefoxAccount",
"Accounts:Exist",
"Accounts:ProfileUpdated");
EventDispatcher.getInstance().registerUiThreadListener(this,
"Accounts:Create",
"Accounts:ShowSyncPreferences");
}
public synchronized void uninit() {
EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
"Accounts:CreateFirefoxAccountFromJSON",
+ "Accounts:LoginFirefoxAccountFromJSON",
"Accounts:UpdateFirefoxAccountFromJSON",
"Accounts:DeleteFirefoxAccount",
"Accounts:Exist",
"Accounts:ProfileUpdated");
EventDispatcher.getInstance().unregisterUiThreadListener(this,
"Accounts:Create",
"Accounts:ShowSyncPreferences");
}
@@ -140,69 +143,29 @@ public class AccountsHelper implements B
UnsupportedEncodingException e) {
Log.w(LOGTAG, "Got exception creating Firefox Account from JSON; ignoring.", e);
if (callback != null) {
callback.sendError("Could not create Firefox Account from JSON: " +
e.toString());
return;
}
}
+
+ MmaDelegate.track(MmaDelegate.USER_SIGNED_UP_TO_FXA);
+
if (callback != null) {
callback.sendSuccess(fxAccount != null);
}
} else if ("Accounts:UpdateFirefoxAccountFromJSON".equals(event)) {
- final Account account = FirefoxAccounts.getFirefoxAccount(mContext);
- if (account == null) {
- if (callback != null) {
- callback.sendError("Could not update Firefox Account since none exists");
- }
- return;
- }
-
- final GeckoBundle json = message.getBundle("json");
- final String email = json.getString("email");
- final String uid = json.getString("uid");
-
- // Protect against cross-connecting accounts.
- if (account.name == null || !account.name.equals(email)) {
- final String errorMessage = "Cannot update Firefox Account from JSON: " +
- "datum has different email address!";
- Log.e(LOGTAG, errorMessage);
- if (callback != null) {
- callback.sendError(errorMessage);
- }
- return;
+ updateFirefoxAccount(message, callback);
+ } else if ( "Acounts:LoginFirefoxAccountFromJSON".equals(event)) {
+ if (updateFirefoxAccount(message, callback)) {
+ MmaDelegate.track(MmaDelegate.USER_SIGNED_IN_TO_FXA);
}
-
- final boolean verified = json.getBoolean("verified", false);
- final byte[] unwrapkB = Utils.hex2Byte(json.getString("unwrapBKey", ""));
- final byte[] sessionToken = Utils.hex2Byte(json.getString("sessionToken", ""));
- final byte[] keyFetchToken = Utils.hex2Byte(json.getString("keyFetchToken", ""));
-
- if (unwrapkB.length == 0 || sessionToken.length == 0 || keyFetchToken.length == 0) {
- final String error = "Cannot update Firefox Account from JSON: invalid key/tokens";
- Log.e(LOGTAG, error);
- if (callback != null) {
- callback.sendError(error);
- }
- return;
- }
-
- final State state = new Engaged(email, uid, verified, unwrapkB,
- sessionToken, keyFetchToken);
-
- final AndroidFxAccount fxAccount = new AndroidFxAccount(mContext, account);
- fxAccount.setState(state);
- fxAccount.updateFirstRunScope(mContext);
-
- if (callback != null) {
- callback.sendSuccess(true);
- }
-
} else if ("Accounts:Create".equals(event)) {
// Do exactly the same thing as if you tapped 'Sync' in Settings.
final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final GeckoBundle extras = message.getBundle("extras");
if (extras != null) {
try {
intent.putExtra("extras", extras.toJSONObject().toString());
@@ -312,9 +275,62 @@ public class AccountsHelper implements B
}
// We don't necessarily have an Activity context here, so we always start in a new task.
final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_STATUS);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
}
+
+ private boolean updateFirefoxAccount(final GeckoBundle message,
+ final EventCallback callback) {
+ final Account account = FirefoxAccounts.getFirefoxAccount(mContext);
+ if (account == null) {
+ if (callback != null) {
+ callback.sendError("Could not update Firefox Account since none exists");
+ }
+ return false;
+ }
+
+ final GeckoBundle json = message.getBundle("json");
+ final String email = json.getString("email");
+ final String uid = json.getString("uid");
+
+ // Protect against cross-connecting accounts.
+ if (account.name == null || !account.name.equals(email)) {
+ final String errorMessage = "Cannot update Firefox Account from JSON: " +
+ "datum has different email address!";
+ Log.e(LOGTAG, errorMessage);
+ if (callback != null) {
+ callback.sendError(errorMessage);
+ }
+ return true;
+ }
+
+ final boolean verified = json.getBoolean("verified", false);
+ final byte[] unwrapkB = Utils.hex2Byte(json.getString("unwrapBKey", ""));
+ final byte[] sessionToken = Utils.hex2Byte(json.getString("sessionToken", ""));
+ final byte[] keyFetchToken = Utils.hex2Byte(json.getString("keyFetchToken", ""));
+
+ if (unwrapkB.length == 0 || sessionToken.length == 0 || keyFetchToken.length == 0) {
+ final String error = "Cannot update Firefox Account from JSON: invalid key/tokens";
+ Log.e(LOGTAG, error);
+ if (callback != null) {
+ callback.sendError(error);
+ }
+ return true;
+ }
+
+ final State state = new Engaged(email, uid, verified, unwrapkB,
+ sessionToken, keyFetchToken);
+
+ final AndroidFxAccount fxAccount = new AndroidFxAccount(mContext, account);
+ fxAccount.setState(state);
+ fxAccount.updateFirstRunScope(mContext);
+
+ if (callback != null) {
+ callback.sendSuccess(true);
+ }
+
+ return true;
+ }
}
--- a/mobile/android/base/java/org/mozilla/gecko/mma/MmaDelegate.java
+++ b/mobile/android/base/java/org/mozilla/gecko/mma/MmaDelegate.java
@@ -43,16 +43,20 @@ public class MmaDelegate {
public static final String OPENED_BOOKMARK = "E_Opened_Bookmark";
public static final String INTERACT_WITH_SEARCH_URL_AREA = "E_Interact_With_Search_URL_Area";
public static final String SCREENSHOT = "E_Screenshot";
public static final String SAVED_LOGIN_AND_PASSWORD = "E_Saved_Login_And_Password";
public static final String RESUMED_FROM_BACKGROUND = "E_Resumed_From_Background";
public static final String NEW_TAB = "E_Opened_New_Tab";
public static final String DISMISS_ONBOARDING = "E_Dismiss_Onboarding";
+ public static final String USER_SIGNED_UP_TO_FXA = "E_User_Signed_Up_To_FxA";
+ public static final String USER_SIGNED_IN_TO_FXA = "E_User_Signed_In_To_FxA";
+ public static final String USER_FINISHED_SYNC = "E_User_Finished_Sync";
+
private static final String LAUNCH_BUT_NOT_DEFAULT_BROWSER = "E_Launch_But_Not_Default_Browser";
private static final String LAUNCH_BROWSER = "E_Launch_Browser";
private static final String CHANGED_DEFAULT_TO_FENNEC = "E_Changed_Default_To_Fennec";
private static final String INSTALLED_FOCUS = "E_Just_Installed_Focus";
private static final String INSTALLED_KLAR = "E_Just_Installed_Klar";
private static final String USER_ATT_FOCUS_INSTALLED = "Focus Installed";
private static final String USER_ATT_KLAR_INSTALLED = "Klar Installed";
--- a/mobile/android/docs/mma.rst
+++ b/mobile/android/docs/mma.rst
@@ -151,16 +151,28 @@ List of current Events related data that
* General app start event
{
"event" : "E_Launch_Browser"
}
* The user just dismissed on-boarding
{
"event" : "E_Dismiss_Onboarding"
}
+* Sign Up for Firefox Account
+{
+ "event" : "E_User_Signed_Up_To_FxA"
+}
+* Sign in Firefox Account
+{
+ "event" : "E_User_Signed_In_To_FxA"
+}
+* Firefox Sync finished event
+{
+ "event" : "E_User_Finished_Sync"
+}
* The user just resumed the app from background
{
"event" : "E_Resumed_From_Background"
}
* User set Fennec as default browser and resumed the app
{
"event" : "E_Changed_Default_To_Fennec"
}
--- a/mobile/android/modules/Accounts.jsm
+++ b/mobile/android/modules/Accounts.jsm
@@ -103,16 +103,33 @@ var Accounts = Object.freeze({
updateFirefoxAccountFromJSON: function(json) {
return EventDispatcher.instance.sendRequestForResult({
type: "Accounts:UpdateFirefoxAccountFromJSON",
json: this._addDefaultEndpoints(json)
});
},
/**
+ * Sign in an existing Android Account to the "Engaged" state with the given
+ * fxa-content-server "login" JSON datum. The account will (re)start
+ * syncing immediately, unless the user has manually configured the account
+ * to not Sync.
+ *
+ * It is an error if no Android Account exists.
+ *
+ * Returns a Promise that resolves to a boolean indicating success.
+ */
+ loginFirefoxAccountFromJSON: function(json) {
+ return EventDispatcher.instance.sendRequestForResult({
+ type: "Accounts:LoginFirefoxAccountFromJSON",
+ json: this._addDefaultEndpoints(json)
+ });
+ },
+
+ /**
* Notify that profile for Android Account has updated.
* The account will re-fetch the profile image.
*
* It is an error if no Android Account exists.
*
* There is no return value from this method.
*/
notifyFirefoxAccountProfileChanged: function() {
--- a/mobile/android/modules/FxAccountsWebChannel.jsm
+++ b/mobile/android/modules/FxAccountsWebChannel.jsm
@@ -267,17 +267,17 @@ this.FxAccountsWebChannel.prototype = {
return Accounts.createFirefoxAccountFromJSON(data).then(success => {
if (!success) {
throw new Error("Could not create Firefox Account!");
}
UITelemetry.addEvent("action.1", "content", null, "fxaccount-create");
return success;
});
}
- return Accounts.updateFirefoxAccountFromJSON(data).then(success => {
+ return Accounts.loginFirefoxAccountFromJSON(data).then(success => {
if (!success) {
throw new Error("Could not update Firefox Account!");
}
UITelemetry.addEvent("action.1", "content", null, "fxaccount-login");
return success;
});
})
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncStatusHelper.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncStatusHelper.java
@@ -5,16 +5,17 @@
package org.mozilla.gecko.fxa.sync;
import java.util.Map;
import java.util.Map.Entry;
import java.util.WeakHashMap;
import org.mozilla.gecko.fxa.SyncStatusListener;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
+import org.mozilla.gecko.mma.MmaDelegate;
import org.mozilla.gecko.util.ThreadUtils;
import android.content.ContentResolver;
import android.content.SyncStatusObserver;
/**
* Abstract away some details of Android's SyncStatusObserver.
* <p>
@@ -62,16 +63,17 @@ public class FxAccountSyncStatusHelper i
}
if (!active && wasActiveLastTime) {
// We've finished a sync.
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
delegate.onSyncFinished();
+ MmaDelegate.track(MmaDelegate.USER_FINISHED_SYNC);
}
});
}
}
}
protected void addListener() {
final int mask = ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;