Bug 1374889 - Gather user attributes before MMA inits. r=maliu
authorNevin Chen <cnevinchen@gmail.com>
Mon, 10 Jul 2017 10:16:19 +0800
changeset 607433 3791e8357839e9721bec9969a77fbf848ddee0ee
parent 607432 b3e29154eac3cbfb47e4559ad007fbfeff91a849
child 607434 9c96f0963b33dd229219674da101f09eb80e7ca3
push id67985
push userbmo:emilio+bugs@crisal.io
push dateWed, 12 Jul 2017 08:36:44 +0000
reviewersmaliu
bugs1374889
milestone56.0a1
Bug 1374889 - Gather user attributes before MMA inits. r=maliu MozReview-Commit-ID: 5v28pWzYYWj
mobile/android/base/java/org/mozilla/gecko/mma/MmaDelegate.java
mobile/android/base/java/org/mozilla/gecko/mma/MmaInterface.java
mobile/android/base/java/org/mozilla/gecko/mma/MmaLeanplumImp.java
mobile/android/base/java/org/mozilla/gecko/mma/MmaStubImp.java
--- a/mobile/android/base/java/org/mozilla/gecko/mma/MmaDelegate.java
+++ b/mobile/android/base/java/org/mozilla/gecko/mma/MmaDelegate.java
@@ -7,44 +7,55 @@
 package org.mozilla.gecko.mma;
 
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
+import android.support.annotation.NonNull;
 import android.text.TextUtils;
 import android.util.Log;
 
 import org.mozilla.gecko.Experiments;
 import org.mozilla.gecko.MmaConstants;
 import org.mozilla.gecko.PrefsHelper;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
+import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.preferences.GeckoPreferences;
 import org.mozilla.gecko.switchboard.SwitchBoard;
+import org.mozilla.gecko.util.ContextUtils;
 
 import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map;
 
 
 public class MmaDelegate {
 
     public static final String READER_AVAILABLE = "E_Reader_Available";
     public static final String DOWNLOAD_MEDIA_SAVED_IMAGE = "E_Download_Media_Saved_Image";
     public static final String CLEARED_PRIVATE_DATA = "E_Cleared_Private_Data";
     public static final String SAVED_BOOKMARK = "E_Saved_Bookmark";
     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 LAUNCH_BUT_NOT_DEFAULT_BROWSER = "E_Launch_But_Not_Default_Browser";
     public static final String NEW_TAB = "E_Opened_New_Tab";
 
 
+    public static final String USER_ATT_FOCUS_INSTALLED = "Focus Installed";
+    public static final String USER_ATT_KLAR_INSTALLED = "Klar Installed";
+    public static final String USER_ATT_DEFAULT_BROWSER = "Default Browser";
+    public static final String USER_ATT_SIGNED_IN = "Signed In Sync";
+
+
     private static final String TAG = "MmaDelegate";
     private static final String KEY_PREF_BOOLEAN_MMA_ENABLED = "mma.enabled";
     private static final String[] PREFS = { KEY_PREF_BOOLEAN_MMA_ENABLED };
 
 
     private static boolean isGeckoPrefOn = false;
     private static MmaInterface mmaHelper = MmaConstants.getMma();
     private static WeakReference<Context> applicationContext;
@@ -60,30 +71,51 @@ public class MmaDelegate {
 
     private static void setupPrefHandler(final Activity activity) {
         PrefsHelper.PrefHandler handler = new PrefsHelper.PrefHandlerBase() {
             @Override
             public void prefValue(String pref, boolean value) {
                 if (pref.equals(KEY_PREF_BOOLEAN_MMA_ENABLED)) {
                     Log.d(TAG, "prefValue() called with: pref = [" + pref + "], value = [" + value + "]");
                     if (value) {
-                        mmaHelper.init(activity);
+
+                        // Since user attributes are gathered in Fennec, not in MMA implementation,
+                        // we gather the information here then pass to mmaHelper.init()
+                        // Note that generateUserAttribute always return a non null HashMap.
+                        Map<String, Object> attributes = gatherUserAttributes(activity);
+
+                        mmaHelper.init(activity, attributes);
+
                         if (!isDefaultBrowser(activity)) {
                             mmaHelper.event(MmaDelegate.LAUNCH_BUT_NOT_DEFAULT_BROWSER);
                         }
                         isGeckoPrefOn = true;
                     } else {
                         isGeckoPrefOn = false;
                     }
                 }
             }
         };
         PrefsHelper.addObserver(PREFS, handler);
     }
 
+    /* This method must be called at background thread to avoid performance issues in some API level */
+    @NonNull
+    private static Map<String, Object> gatherUserAttributes(final Context context) {
+
+        final Map<String, Object> attributes = new HashMap<>();
+
+        attributes.put(USER_ATT_FOCUS_INSTALLED, ContextUtils.isPackageInstalled(context, "org.mozilla.focus"));
+        attributes.put(USER_ATT_KLAR_INSTALLED, ContextUtils.isPackageInstalled(context, "org.mozilla.klar"));
+        attributes.put(USER_ATT_DEFAULT_BROWSER, isDefaultBrowser(context));
+        attributes.put(USER_ATT_SIGNED_IN, FirefoxAccounts.firefoxAccountsExist(context));
+
+        return attributes;
+    }
+
 
     public static void track(String event) {
         if (isMmaEnabled()) {
             mmaHelper.event(event);
         }
     }
 
     public static void track(String event, long value) {
@@ -118,10 +150,9 @@ public class MmaDelegate {
             // No default is set
             return false;
         }
 
         final String packageName = info.activityInfo.packageName;
         return (TextUtils.equals(packageName, context.getPackageName()));
     }
 
-
 }
--- a/mobile/android/base/java/org/mozilla/gecko/mma/MmaInterface.java
+++ b/mobile/android/base/java/org/mozilla/gecko/mma/MmaInterface.java
@@ -4,19 +4,21 @@
  * 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.mma;
 
 import android.app.Activity;
 import android.content.Context;
 
+import java.util.Map;
+
 
 public interface MmaInterface {
-    void init(Activity Activity);
+    void init(Activity Activity, Map<String, ?> attributes);
 
     void start(Context context);
 
     void event(String mmaEvent);
 
     void event(String mmaEvent, double value);
 
     void stop();
--- a/mobile/android/base/java/org/mozilla/gecko/mma/MmaLeanplumImp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/mma/MmaLeanplumImp.java
@@ -4,87 +4,60 @@
  * 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.mma;
 
 import android.app.Activity;
 import android.content.Context;
 import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
 
 import com.leanplum.Leanplum;
 import com.leanplum.LeanplumActivityHelper;
 
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.MmaConstants;
-import org.mozilla.gecko.fxa.FirefoxAccounts;
 
-import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
 
 
 public class MmaLeanplumImp implements MmaInterface {
 
     private static final String KEY_ANDROID_PREF_STRING_LEANPLUM_DEVICE_ID = "android.not_a_preference.leanplum.device_id";
 
     @Override
-    public void init(final Activity activity) {
+    public void init(final Activity activity, Map<String, ?> attributes) {
         if (activity == null) {
             return;
         }
         Leanplum.setApplicationContext(activity.getApplicationContext());
 
         LeanplumActivityHelper.enableLifecycleCallbacks(activity.getApplication());
 
         if (AppConstants.MOZILLA_OFFICIAL) {
             Leanplum.setAppIdForProductionMode(MmaConstants.MOZ_LEANPLUM_SDK_CLIENTID, MmaConstants.MOZ_LEANPLUM_SDK_KEY);
         } else {
             Leanplum.setAppIdForDevelopmentMode(MmaConstants.MOZ_LEANPLUM_SDK_CLIENTID, MmaConstants.MOZ_LEANPLUM_SDK_KEY);
         }
 
-        Map<String, Object> attributes = new HashMap<>();
-        boolean installedFocus = isPackageInstalled(activity, "org.mozilla.focus");
-        boolean installedKlar = isPackageInstalled(activity, "org.mozilla.klar");
-        if (installedFocus) {
-            attributes.put("Focus Installed", true);
-        } else {
-            attributes.put("Focus Installed", false);
-        }
-        if (installedKlar) {
-            attributes.put("Klar Installed", true);
-        } else {
-            attributes.put("Klar Installed", false);
-        }
-
-
         final SharedPreferences sharedPreferences = activity.getPreferences(0);
         String deviceId = sharedPreferences.getString(KEY_ANDROID_PREF_STRING_LEANPLUM_DEVICE_ID, null);
         if (deviceId == null) {
             deviceId = UUID.randomUUID().toString();
             sharedPreferences.edit().putString(KEY_ANDROID_PREF_STRING_LEANPLUM_DEVICE_ID, deviceId).apply();
         }
         Leanplum.setDeviceId(deviceId);
-        if (MmaDelegate.isDefaultBrowser(activity)) {
-            attributes.put("Default Browser", true);
+
+        if (attributes != null) {
+            Leanplum.start(activity, attributes);
         } else {
-            attributes.put("Default Browser", false);
+            Leanplum.start(activity);
         }
 
-        // In order to trigger the campaign lazily, you check the account existence as an attribute,
-        // not when account login success callback is invoked. Because the attribute update lazily when process start.
-        if (FirefoxAccounts.firefoxAccountsExist(activity)) {
-            attributes.put("Signed In Sync", true);
-        } else {
-            attributes.put("Signed In Sync", false);
-        }
-
-        Leanplum.start(activity, attributes);
-
         // this is special to Leanplum. Since we defer LeanplumActivityHelper's onResume call till
         // switchboard completes loading. We miss the call to LeanplumActivityHelper.onResume.
         // So I manually call it here.
         //
         // There's a risk that if this is called after activity's onPause(Although I've
         // tested it's seems okay). We  should require their SDK to separate activity call back with
         // SDK initialization and Activity lifecycle in the future.
         //
@@ -114,18 +87,9 @@ public class MmaLeanplumImp implements M
 
     }
 
     @Override
     public void stop() {
         Leanplum.stop();
     }
 
-    private static boolean isPackageInstalled(final Context context, String packageName) {
-        try {
-            PackageManager pm = context.getPackageManager();
-            pm.getPackageInfo(packageName, 0);
-            return true;
-        } catch (PackageManager.NameNotFoundException e) {
-            return false;
-        }
-    }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/mma/MmaStubImp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/mma/MmaStubImp.java
@@ -2,23 +2,24 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.mma;
 
 import android.app.Activity;
-import android.app.Application;
 import android.content.Context;
 
+import java.util.Map;
+
 
 public class MmaStubImp implements MmaInterface {
     @Override
-    public void init(Activity activity) {
+    public void init(Activity activity, Map<String, ?> attributes) {
 
     }
 
     @Override
     public void start(Context context) {
 
     }
 
@@ -31,9 +32,10 @@ public class MmaStubImp implements MmaIn
     public void event(String leanplumEvent, double value) {
 
     }
 
     @Override
     public void stop() {
 
     }
+
 }