Bug 1269734 - Changes based on previous review for campaign ID retrieval r?mcomella draft
authorJonathan Almeida (:jonalmeida) <jonalmeida942@gmail.com>
Tue, 19 Jul 2016 13:58:28 -0700
changeset 392100 f7351689fedd9abb40f7b2692a5540b1fe0276c0
parent 392077 39c00f02f3e17b65a1345a58ae3e20534d1cd7ce
child 526251 5817c0743dc90aa8da23ccfa0a5109458071e3ff
push id23938
push userjonalmeida942@gmail.com
push dateSat, 23 Jul 2016 01:18:19 +0000
reviewersmcomella
bugs1269734
milestone50.0a1
Bug 1269734 - Changes based on previous review for campaign ID retrieval r?mcomella MozReview-Commit-ID: I90Dh3WJzst
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
mobile/android/base/java/org/mozilla/gecko/adjust/AttributionHelperListener.java
mobile/android/base/java/org/mozilla/gecko/adjust/CampaignIdMeasurements.java
mobile/android/base/java/org/mozilla/gecko/adjust/StubAdjustHelper.java
mobile/android/base/java/org/mozilla/gecko/telemetry/TelemetryConstants.java
mobile/android/base/java/org/mozilla/gecko/telemetry/TelemetryCorePingDelegate.java
mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCorePingBuilder.java
mobile/android/base/moz.build
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -8,16 +8,18 @@ package org.mozilla.gecko;
 import android.Manifest;
 import android.app.DownloadManager;
 import android.os.Environment;
 import android.support.annotation.CheckResult;
 import android.support.annotation.NonNull;
 
 import org.json.JSONArray;
 import org.mozilla.gecko.adjust.AdjustHelperInterface;
+import org.mozilla.gecko.adjust.AttributionHelperListener;
+import org.mozilla.gecko.adjust.CampaignIdMeasurements;
 import org.mozilla.gecko.annotation.RobocopTarget;
 import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.DynamicToolbar.VisibilityTransition;
 import org.mozilla.gecko.Tabs.TabEvents;
 import org.mozilla.gecko.animation.PropertyAnimator;
 import org.mozilla.gecko.animation.ViewHelper;
 import org.mozilla.gecko.cleanup.FileCleanupController;
 import org.mozilla.gecko.db.BrowserContract;
@@ -305,28 +307,25 @@ public class BrowserApp extends GeckoApp
     // The animator used to toggle HomePager visibility has a race where if the HomePager is shown
     // (starting the animation), the HomePager is hidden, and the HomePager animation completes,
     // both the web content and the HomePager will be hidden. This flag is used to prevent the
     // race by determining if the web content should be hidden at the animation's end.
     private boolean mHideWebContentOnAnimationEnd;
 
     private final DynamicToolbar mDynamicToolbar = new DynamicToolbar();
 
-    // Holding a reference here so that we can pass it to the AdjustHelper.
-    private final TelemetryCorePingDelegate mTelemetryCorePingDelegate = new TelemetryCorePingDelegate();
-
     private final List<BrowserAppDelegate> delegates = Collections.unmodifiableList(Arrays.asList(
             (BrowserAppDelegate) new AddToHomeScreenPromotion(),
             (BrowserAppDelegate) new ScreenshotDelegate(),
             (BrowserAppDelegate) new BookmarkStateChangeDelegate(),
             (BrowserAppDelegate) new ReaderViewBookmarkPromotion(),
             (BrowserAppDelegate) new ContentNotificationsDelegate(),
             (BrowserAppDelegate) new PostUpdateHandler(),
-            new OfflineTabStatusDelegate()
-            mTelemetryCorePingDelegate
+            new OfflineTabStatusDelegate(),
+            new TelemetryCorePingDelegate()
     ));
 
     @NonNull
     private SearchEngineManager mSearchEngineManager; // Contains reference to Context - DO NOT LEAK!
 
     private boolean mHasResumed;
 
     @Override
@@ -710,17 +709,17 @@ public class BrowserApp extends GeckoApp
         final BrowserDB db = profile.getDB();
         db.setSuggestedSites(suggestedSites);
 
         JavaAddonManager.getInstance().init(appContext);
         mSharedPreferencesHelper = new SharedPreferencesHelper(appContext);
         mReadingListHelper = new ReadingListHelper(appContext, profile);
         mAccountsHelper = new AccountsHelper(appContext, profile);
 
-        initAdjustSDK(this, isInAutomation, mTelemetryCorePingDelegate);
+        initAdjustSDK(this, isInAutomation, addAttributionHelperListener());
 
         if (AppConstants.MOZ_ANDROID_BEAM) {
             NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this);
             if (nfc != null) {
                 nfc.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() {
                     @Override
                     public NdefMessage createNdefMessage(NfcEvent event) {
                         Tab tab = Tabs.getInstance().getSelectedTab();
@@ -804,29 +803,38 @@ public class BrowserApp extends GeckoApp
         final String serverUrl = TextUtils.isEmpty(serverExtra) ? SWITCHBOARD_SERVER : serverExtra;
         new AsyncConfigLoader(context, serverUrl).execute();
     }
 
     private static void initTelemetryUploader(final boolean isInAutomation) {
         TelemetryUploadService.setDisabled(isInAutomation);
     }
 
-    private static void initAdjustSDK(final Context context, final boolean isInAutomation, TelemetryCorePingDelegate delegate) {
+    private static void initAdjustSDK(final Context context, final boolean isInAutomation, final AttributionHelperListener listener) {
         final AdjustHelperInterface adjustHelper = AdjustConstants.getAdjustHelper();
-        adjustHelper.onCreate(context, AdjustConstants.MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN, delegate);
+        adjustHelper.onCreate(context, AdjustConstants.MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN, listener);
 
         // Adjust stores enabled state so this is only necessary because users may have set
         // their data preferences before this feature was implemented and we need to respect
         // those before upload can occur in Adjust.onResume.
         final SharedPreferences prefs = GeckoSharedPrefs.forApp(context);
         final boolean enabled = !isInAutomation &&
                 prefs.getBoolean(GeckoPreferences.PREFS_HEALTHREPORT_UPLOAD_ENABLED, true);
         adjustHelper.setEnabled(enabled);
     }
 
+    private AttributionHelperListener addAttributionHelperListener() {
+        return new AttributionHelperListener() {
+            @Override
+            public void onCampaignIdChanged(String campaignId) {
+                CampaignIdMeasurements.updateCampaignIdPref(BrowserApp.this, campaignId);
+            }
+        };
+    }
+
     private void showUpdaterPermissionSnackbar() {
         SnackbarBuilder.SnackbarCallback allowCallback = new SnackbarBuilder.SnackbarCallback() {
             @Override
             public void onClick(View v) {
                 Permissions.from(BrowserApp.this)
                         .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                         .run();
             }
--- a/mobile/android/base/java/org/mozilla/gecko/adjust/AttributionHelperListener.java
+++ b/mobile/android/base/java/org/mozilla/gecko/adjust/AttributionHelperListener.java
@@ -1,14 +1,16 @@
 /* -*- 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.adjust;
 
 /**
- * A callback Used along with the AdjustHelper for notifying when an Adjust Attribution
- * is available.
+ * We use this listener to notify when to store the campaign ID when we receive
+ * the attribution from the OnAttributionListener in the Adjust SDK. We can't directly access
+ * the attribution since we don't always compile against the Adjust SDK and use a stub
+ * in those cases.
  */
 public interface AttributionHelperListener {
     void onCampaignIdChanged(String campaignId);
 }
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/adjust/CampaignIdMeasurements.java
@@ -0,0 +1,36 @@
+/*
+ * 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.adjust;
+
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+
+import org.mozilla.gecko.BrowserApp;
+import org.mozilla.gecko.GeckoSharedPrefs;
+
+/**
+ * A class to retrieve and store the campaign Id pref that is used when the Adjust SDK gives us
+ * new attribution from the {@link AttributionHelperListener}.
+ */
+public class CampaignIdMeasurements {
+    private static final String PREF_CAMPAIGN_ID = "campaignId";
+
+    public static String getCampaignIdFromPrefs(@NonNull final BrowserApp activity) {
+        return GeckoSharedPrefs.forProfile(activity)
+                .getString(PREF_CAMPAIGN_ID, null);
+    }
+
+    public static void updateCampaignIdPref(@NonNull final BrowserApp activity, @NonNull final String campaignId) {
+        if (TextUtils.isEmpty(campaignId)) {
+            return;
+        }
+        GeckoSharedPrefs.forProfile(activity)
+                .edit()
+                .putString(PREF_CAMPAIGN_ID, campaignId)
+                .apply();
+    }
+}
--- a/mobile/android/base/java/org/mozilla/gecko/adjust/StubAdjustHelper.java
+++ b/mobile/android/base/java/org/mozilla/gecko/adjust/StubAdjustHelper.java
@@ -3,20 +3,17 @@
  * 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.adjust;
 
 import android.content.Context;
 import android.content.Intent;
 
-import com.adjust.sdk.AdjustAttribution;
-import com.adjust.sdk.OnAttributionChangedListener;
-
-public class StubAdjustHelper implements AdjustHelperInterface, OnAttributionChangedListener {
+public class StubAdjustHelper implements AdjustHelperInterface {
     public void onCreate(final Context context, final String appToken, final AttributionHelperListener listener) {
         // Do nothing.
     }
 
     public void onPause() {
         // Do nothing.
     }
 
@@ -26,13 +23,9 @@ public class StubAdjustHelper implements
 
     public void setEnabled(final boolean isEnabled) {
         // Do nothing.
     }
 
     public void onReceive(final Context context, final Intent intent) {
         // Do nothing.
     }
-
-    public void onAttributionChanged(AdjustAttribution attribution) {
-        // Do nothing.
-    }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/telemetry/TelemetryConstants.java
+++ b/mobile/android/base/java/org/mozilla/gecko/telemetry/TelemetryConstants.java
@@ -7,12 +7,9 @@ package org.mozilla.gecko.telemetry;
 import org.mozilla.gecko.AppConstants;
 
 public class TelemetryConstants {
     // To test, set this to true & change "toolkit.telemetry.server" in about:config.
     public static final boolean UPLOAD_ENABLED = AppConstants.MOZILLA_OFFICIAL; // Disabled for developer builds.
 
     public static final String USER_AGENT =
             "Firefox-Android-Telemetry/" + AppConstants.MOZ_APP_VERSION + " (" + AppConstants.MOZ_APP_UA_NAME + ")";
-
-    public static final String PREF_SERVER_URL = "telemetry-serverUrl";
-    public static final String PREF_CAMPAIGN_ID = "campaignId";
 }
--- a/mobile/android/base/java/org/mozilla/gecko/telemetry/TelemetryCorePingDelegate.java
+++ b/mobile/android/base/java/org/mozilla/gecko/telemetry/TelemetryCorePingDelegate.java
@@ -9,16 +9,17 @@ package org.mozilla.gecko.telemetry;
 import android.content.SharedPreferences;
 import android.support.annotation.Nullable;
 import android.support.annotation.WorkerThread;
 import android.util.Log;
 import org.mozilla.gecko.BrowserApp;
 import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.GeckoSharedPrefs;
 import org.mozilla.gecko.adjust.AttributionHelperListener;
+import org.mozilla.gecko.adjust.CampaignIdMeasurements;
 import org.mozilla.gecko.delegates.BrowserAppDelegateWithReference;
 import org.mozilla.gecko.distribution.DistributionStoreCallback;
 import org.mozilla.gecko.search.SearchEngineManager;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.telemetry.measurements.SearchCountMeasurements;
 import org.mozilla.gecko.telemetry.measurements.SessionMeasurements;
 import org.mozilla.gecko.telemetry.pingbuilders.TelemetryCorePingBuilder;
 import org.mozilla.gecko.util.StringUtils;
@@ -148,37 +149,39 @@ public class TelemetryCorePingDelegate e
                 final SessionMeasurements.SessionMeasurementsContainer sessionMeasurementsContainer =
                         sessionMeasurements.getAndResetSessionMeasurements(activity);
                 final TelemetryCorePingBuilder pingBuilder = new TelemetryCorePingBuilder(activity)
                         .setClientID(clientID)
                         .setDefaultSearchEngine(TelemetryCorePingBuilder.getEngineIdentifier(engine))
                         .setProfileCreationDate(TelemetryCorePingBuilder.getProfileCreationDate(activity, profile))
                         .setSequenceNumber(TelemetryCorePingBuilder.getAndIncrementSequenceNumber(sharedPrefs))
                         .setSessionCount(sessionMeasurementsContainer.sessionCount)
-                        .setSessionDuration(sessionMeasurementsContainer.elapsedSeconds)
-                        .setOptCampaignId(activity);
-                maybeSetOptionalMeasurements(sharedPrefs, pingBuilder);
+                        .setSessionDuration(sessionMeasurementsContainer.elapsedSeconds);
+                maybeSetOptionalMeasurements(sharedPrefs, pingBuilder, activity);
 
                 getTelemetryDispatcher(activity).queuePingForUpload(activity, pingBuilder);
             }
         });
     }
 
-    private void maybeSetOptionalMeasurements(final SharedPreferences sharedPrefs, final TelemetryCorePingBuilder pingBuilder) {
+    private void maybeSetOptionalMeasurements(final SharedPreferences sharedPrefs, final TelemetryCorePingBuilder pingBuilder,
+                                              final BrowserApp activity) {
         final String distributionId = sharedPrefs.getString(DistributionStoreCallback.PREF_DISTRIBUTION_ID, null);
         if (distributionId != null) {
             pingBuilder.setOptDistributionID(distributionId);
         }
 
         final ExtendedJSONObject searchCounts = SearchCountMeasurements.getAndZeroSearch(sharedPrefs);
         if (searchCounts.size() > 0) {
             pingBuilder.setOptSearchCounts(searchCounts);
         }
+
+        final String campaignId = CampaignIdMeasurements.getCampaignIdFromPrefs(activity);
+        if (campaignId != null) {
+            pingBuilder.setOptCampaignId(campaignId);
+        }
     }
 
     @Override
     public void onCampaignIdChanged(String campaignId) {
-        GeckoSharedPrefs.forProfile(getBrowserApp())
-                .edit()
-                .putString(TelemetryConstants.PREF_CAMPAIGN_ID, campaignId)
-                .apply();
+        CampaignIdMeasurements.updateCampaignIdPref(getBrowserApp(), campaignId);
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCorePingBuilder.java
+++ b/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCorePingBuilder.java
@@ -39,23 +39,23 @@ import java.util.concurrent.TimeUnit;
  * See https://gecko.readthedocs.org/en/latest/toolkit/components/telemetry/telemetry/core-ping.html
  * for details on the core ping.
  */
 public class TelemetryCorePingBuilder extends TelemetryPingBuilder {
     private static final String LOGTAG = StringUtils.safeSubstring(TelemetryCorePingBuilder.class.getSimpleName(), 0, 23);
 
     // For legacy reasons, this preference key is not namespaced with "core".
     private static final String PREF_SEQ_COUNT = "telemetry-seqCount";
+    private static final String PREF_CAMPAIGN_ID = "campaignId";
 
     private static final String NAME = "core";
     private static final int VERSION_VALUE = 7; // For version history, see toolkit/components/telemetry/docs/core-ping.rst
     private static final String OS_VALUE = "Android";
 
     private static final String ARCHITECTURE = "arch";
-    private static final String CAMPAIGN_ID = "campaignId";
     private static final String CLIENT_ID = "clientId";
     private static final String DEFAULT_SEARCH_ENGINE = "defaultSearch";
     private static final String DEVICE = "device";
     private static final String DISTRIBUTION_ID = "distributionId";
     private static final String EXPERIMENTS = "experiments";
     private static final String LOCALE = "locale";
     private static final String OS_ATTR = "os";
     private static final String OS_VERSION = "osversion";
@@ -153,24 +153,21 @@ public class TelemetryCorePingBuilder ex
         } else if (searchCounts.size() == 0) {
             throw new IllegalStateException("Expected non-empty search counts");
         }
 
         payload.put(SEARCH_COUNTS, searchCounts);
         return this;
     }
 
-    public TelemetryCorePingBuilder setOptCampaignId(final Context context) {
-        final String campaignId = GeckoSharedPrefs.forProfile(context)
-                .getString(TelemetryConstants.PREF_CAMPAIGN_ID, null);
-        Log.d(LOGTAG, "Got adjust campaignId from prefs: " + campaignId);
+    public TelemetryCorePingBuilder setOptCampaignId(final String campaignId) {
         if (campaignId == null) {
-            throw new IllegalStateException("Received empty string.");
+            throw new IllegalStateException("Expected non-null campaign ID.");
         }
-        payload.put(TelemetryConstants.PREF_CAMPAIGN_ID, campaignId);
+        payload.put(PREF_CAMPAIGN_ID, campaignId);
         return this;
     }
 
     /**
      * @param date The profile creation date in days to the unix epoch (not millis!), or null if there is an error.
      */
     public TelemetryCorePingBuilder setProfileCreationDate(@Nullable final Long date) {
         if (date != null && date < 0) {
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -11,16 +11,17 @@ CONFIGURE_SUBST_FILES += ['adjust_sdk_ap
 include('android-services.mozbuild')
 
 thirdparty_source_dir = TOPSRCDIR + '/mobile/android/thirdparty/'
 
 constants_jar = add_java_jar('constants')
 constants_jar.sources = ['java/org/mozilla/gecko/' + x for x in [
     'adjust/AdjustHelperInterface.java',
     'adjust/AttributionHelperListener.java',
+    'adjust/CampaignIdMeasurements.java',
     'annotation/JNITarget.java',
     'annotation/ReflectionTarget.java',
     'annotation/RobocopTarget.java',
     'annotation/WebRTCJNITarget.java',
     'annotation/WrapForJNI.java',
     'db/BrowserContract.java',
     'LocaleManager.java',
     'Locales.java',