Bug 1269734 - Include adjust campaign ID with core ping r?mcomella
MozReview-Commit-ID: KZJKYzBfRfK
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -6,24 +6,23 @@
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 android.widget.AbsoluteLayout;
import android.widget.VideoView;
-import android.graphics.RectF;
import android.graphics.Rect;
import org.json.JSONArray;
import org.mozilla.gecko.activitystream.ActivityStream;
import org.mozilla.gecko.adjust.AdjustHelperInterface;
+import org.mozilla.gecko.adjust.AttributionHelperListener;
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;
@@ -47,17 +46,16 @@ import org.mozilla.gecko.gfx.DynamicTool
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.home.BrowserSearch;
import org.mozilla.gecko.home.HomeBanner;
import org.mozilla.gecko.home.HomeConfig;
import org.mozilla.gecko.home.HomeConfig.PanelType;
import org.mozilla.gecko.home.HomeConfigPrefsBackend;
import org.mozilla.gecko.home.HomeFragment;
-import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.home.HomePager.OnUrlOpenInBackgroundListener;
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
import org.mozilla.gecko.home.HomePanelsManager;
import org.mozilla.gecko.home.HomeScreen;
import org.mozilla.gecko.home.SearchEngine;
import org.mozilla.gecko.javaaddons.JavaAddonManager;
import org.mozilla.gecko.media.AudioFocusAgent;
import org.mozilla.gecko.menu.GeckoMenu;
@@ -126,17 +124,16 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcEvent;
import android.os.Build;
import android.os.Bundle;
@@ -313,24 +310,26 @@ 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();
+ 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 TelemetryCorePingDelegate(),
+ mTelemetryCorePingDelegate,
new OfflineTabStatusDelegate()
));
@NonNull
private SearchEngineManager mSearchEngineManager; // Contains reference to Context - DO NOT LEAK!
private boolean mHasResumed;
@@ -716,17 +715,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);
+ initAdjustSDK(this, isInAutomation, mTelemetryCorePingDelegate);
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();
@@ -814,19 +813,19 @@ 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) {
+ 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);
+ 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);
--- a/mobile/android/base/java/org/mozilla/gecko/adjust/AdjustHelper.java
+++ b/mobile/android/base/java/org/mozilla/gecko/adjust/AdjustHelper.java
@@ -4,39 +4,46 @@
* 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.Adjust;
+import com.adjust.sdk.AdjustAttribution;
import com.adjust.sdk.AdjustConfig;
import com.adjust.sdk.AdjustReferrerReceiver;
import com.adjust.sdk.LogLevel;
+import com.adjust.sdk.OnAttributionChangedListener;
import org.mozilla.gecko.AppConstants;
-public class AdjustHelper implements AdjustHelperInterface {
- public void onCreate(final Context context, final String maybeAppToken) {
+public class AdjustHelper implements AdjustHelperInterface, OnAttributionChangedListener {
+
+ private AttributionHelperListener attributionListener;
+
+ public void onCreate(final Context context, final String maybeAppToken, final AttributionHelperListener listener) {
final String environment;
final LogLevel logLevel;
if (AppConstants.MOZILLA_OFFICIAL) {
environment = AdjustConfig.ENVIRONMENT_PRODUCTION;
logLevel = LogLevel.WARN;
} else {
environment = AdjustConfig.ENVIRONMENT_SANDBOX;
logLevel = LogLevel.VERBOSE;
}
if (maybeAppToken == null) {
// We've got install tracking turned on -- we better have a token!
throw new IllegalArgumentException("maybeAppToken must not be null");
}
+ attributionListener = listener;
AdjustConfig config = new AdjustConfig(context, maybeAppToken, environment);
config.setLogLevel(logLevel);
+ config.setOnAttributionChangedListener(this);
Adjust.onCreate(config);
}
public void onPause() {
Adjust.onPause();
}
public void onResume() {
@@ -45,9 +52,17 @@ public class AdjustHelper implements Adj
public void setEnabled(final boolean isEnabled) {
Adjust.setEnabled(isEnabled);
}
public void onReceive(final Context context, final Intent intent) {
new AdjustReferrerReceiver().onReceive(context, intent);
}
+
+ @Override
+ public void onAttributionChanged(AdjustAttribution attribution) {
+ if (attributionListener == null || attribution == null) {
+ return;
+ }
+ attributionListener.onCampaignIdChanged(attribution.campaign);
+ }
}
--- a/mobile/android/base/java/org/mozilla/gecko/adjust/AdjustHelperInterface.java
+++ b/mobile/android/base/java/org/mozilla/gecko/adjust/AdjustHelperInterface.java
@@ -8,15 +8,15 @@ package org.mozilla.gecko.adjust;
import android.content.Context;
import android.content.Intent;
public interface AdjustHelperInterface {
/**
* Register the Application with the Adjust SDK.
* @param appToken the (secret!) Adjust SDK per-application token to register with; may be null.
*/
- void onCreate(final Context context, final String appToken);
+ void onCreate(final Context context, final String appToken, final AttributionHelperListener listener);
void onPause();
void onResume();
void setEnabled(final boolean isEnabled);
void onReceive(final Context context, final Intent intent);
}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/adjust/AttributionHelperListener.java
@@ -0,0 +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;
+
+/**
+ * Because of how our build module dependencies is structured, we aren't able to use
+ * the {@link com.adjust.sdk.OnAttributionChangedListener} directly outside of {@link AdjustHelper}.
+ * If the Adjust SDK is enabled, this listener will be notified when {@link com.adjust.sdk.OnAttributionChangedListener}
+ * is fired (i.e. this listener would be daisy-chained to the Adjust one)
+ */
+public interface AttributionHelperListener {
+ void onCampaignIdChanged(String campaignId);
+}
--- a/mobile/android/base/java/org/mozilla/gecko/adjust/StubAdjustHelper.java
+++ b/mobile/android/base/java/org/mozilla/gecko/adjust/StubAdjustHelper.java
@@ -4,17 +4,17 @@
* 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;
public class StubAdjustHelper implements AdjustHelperInterface {
- public void onCreate(final Context context, final String appToken) {
+ public void onCreate(final Context context, final String appToken, final AttributionHelperListener listener) {
// Do nothing.
}
public void onPause() {
// Do nothing.
}
public void onResume() {
--- a/mobile/android/base/java/org/mozilla/gecko/telemetry/TelemetryCorePingDelegate.java
+++ b/mobile/android/base/java/org/mozilla/gecko/telemetry/TelemetryCorePingDelegate.java
@@ -1,40 +1,43 @@
/*
* 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.telemetry;
+import android.content.Context;
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.telemetry.measurements.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;
import org.mozilla.gecko.util.ThreadUtils;
import java.io.IOException;
/**
* An activity-lifecycle delegate for uploading the core ping.
*/
public class TelemetryCorePingDelegate extends BrowserAppDelegateWithReference
- implements SearchEngineManager.SearchEngineCallback {
+ implements SearchEngineManager.SearchEngineCallback, AttributionHelperListener {
private static final String LOGTAG = StringUtils.safeSubstring(
"Gecko" + TelemetryCorePingDelegate.class.getSimpleName(), 0, 23);
private static final String PREF_IS_FIRST_RUN = "telemetry-isFirstRun";
private TelemetryDispatcher telemetryDispatcher; // lazy
private final SessionMeasurements sessionMeasurements = new SessionMeasurements();
@@ -148,27 +151,39 @@ public class TelemetryCorePingDelegate e
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);
- maybeSetOptionalMeasurements(sharedPrefs, pingBuilder);
+ maybeSetOptionalMeasurements(activity, sharedPrefs, pingBuilder);
getTelemetryDispatcher(activity).queuePingForUpload(activity, pingBuilder);
}
});
}
- private void maybeSetOptionalMeasurements(final SharedPreferences sharedPrefs, final TelemetryCorePingBuilder pingBuilder) {
+ private void maybeSetOptionalMeasurements(final Context context,
+ final SharedPreferences sharedPrefs,
+ final TelemetryCorePingBuilder pingBuilder) {
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(context);
+ if (campaignId != null) {
+ pingBuilder.setOptCampaignId(campaignId);
+ }
+ }
+
+ @Override
+ public void onCampaignIdChanged(String campaignId) {
+ CampaignIdMeasurements.updateCampaignIdPref(getBrowserApp(), campaignId);
}
}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/telemetry/measurements/CampaignIdMeasurements.java
@@ -0,0 +1,37 @@
+/*
+ * 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.telemetry.measurements;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+
+import org.mozilla.gecko.GeckoSharedPrefs;
+import org.mozilla.gecko.adjust.AttributionHelperListener;
+
+/**
+ * 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 = "measurements-campaignId";
+
+ public static String getCampaignIdFromPrefs(@NonNull final Context context) {
+ return GeckoSharedPrefs.forProfile(context)
+ .getString(PREF_CAMPAIGN_ID, null);
+ }
+
+ public static void updateCampaignIdPref(@NonNull final Context context, @NonNull final String campaignId) {
+ if (TextUtils.isEmpty(campaignId)) {
+ return;
+ }
+ GeckoSharedPrefs.forProfile(context)
+ .edit()
+ .putString(PREF_CAMPAIGN_ID, campaignId)
+ .apply();
+ }
+}
--- a/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCorePingBuilder.java
+++ b/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCorePingBuilder.java
@@ -43,16 +43,17 @@ public class TelemetryCorePingBuilder ex
// For legacy reasons, this preference key is not namespaced with "core".
private static final String PREF_SEQ_COUNT = "telemetry-seqCount";
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";
@@ -150,16 +151,24 @@ 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 String campaignId) {
+ if (campaignId == null) {
+ throw new IllegalStateException("Expected non-null campaign ID.");
+ }
+ payload.put(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) {
throw new IllegalArgumentException("Expect positive date value. Received: " + date);
}
payload.put(PROFILE_CREATION_DATE, date);
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -10,16 +10,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',
'annotation/JNITarget.java',
'annotation/ReflectionTarget.java',
'annotation/RobocopTarget.java',
'annotation/WebRTCJNITarget.java',
'annotation/WrapForJNI.java',
'db/BrowserContract.java',
'LocaleManager.java',
'Locales.java',
@@ -588,16 +589,17 @@ gbjar.sources += ['java/org/mozilla/geck
'tabs/TabPanelBackButton.java',
'tabs/TabsGridLayout.java',
'tabs/TabsLayoutAdapter.java',
'tabs/TabsLayoutItemView.java',
'tabs/TabsListLayout.java',
'tabs/TabsPanel.java',
'tabs/TabsPanelThumbnailView.java',
'Telemetry.java',
+ 'telemetry/measurements/CampaignIdMeasurements.java',
'telemetry/measurements/SearchCountMeasurements.java',
'telemetry/measurements/SessionMeasurements.java',
'telemetry/pingbuilders/TelemetryCorePingBuilder.java',
'telemetry/pingbuilders/TelemetryPingBuilder.java',
'telemetry/schedulers/TelemetryUploadAllPingsImmediatelyScheduler.java',
'telemetry/schedulers/TelemetryUploadScheduler.java',
'telemetry/stores/TelemetryJSONFilePingStore.java',
'telemetry/stores/TelemetryPingStore.java',