Bug 1273689 - Move core ping upload to BrowserAppDelegate. r=sebastian
This lets us put the two paths of upload code all in the same place.
MozReview-Commit-ID: BUsdyEAcdDO
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -4,18 +4,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko;
import android.Manifest;
import android.app.DownloadManager;
import android.os.Environment;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
import org.json.JSONArray;
import org.mozilla.gecko.adjust.AdjustHelperInterface;
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;
@@ -73,19 +71,18 @@ import org.mozilla.gecko.search.SearchEn
import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
import org.mozilla.gecko.tabqueue.TabQueueHelper;
import org.mozilla.gecko.tabqueue.TabQueuePrompt;
import org.mozilla.gecko.tabs.TabHistoryController;
import org.mozilla.gecko.tabs.TabHistoryController.OnShowTabHistory;
import org.mozilla.gecko.tabs.TabHistoryFragment;
import org.mozilla.gecko.tabs.TabHistoryPage;
import org.mozilla.gecko.tabs.TabsPanel;
+import org.mozilla.gecko.telemetry.TelemetryCorePingUploadDelegate;
import org.mozilla.gecko.telemetry.measurements.SearchCountMeasurements;
-import org.mozilla.gecko.telemetry.TelemetryDispatcher;
-import org.mozilla.gecko.telemetry.UploadTelemetryCorePingCallback;
import org.mozilla.gecko.telemetry.measurements.SessionMeasurements;
import org.mozilla.gecko.toolbar.AutocompleteHandler;
import org.mozilla.gecko.toolbar.BrowserToolbar;
import org.mozilla.gecko.toolbar.BrowserToolbar.TabEditingState;
import org.mozilla.gecko.toolbar.ToolbarProgressView;
import org.mozilla.gecko.trackingprotection.TrackingProtectionPrompt;
import org.mozilla.gecko.updater.UpdateServiceHelper;
import org.mozilla.gecko.util.ActivityUtils;
@@ -304,23 +301,23 @@ public class BrowserApp extends GeckoApp
private final DynamicToolbar mDynamicToolbar = new DynamicToolbar();
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 ContentNotificationsDelegate(),
+ new TelemetryCorePingUploadDelegate()
));
@NonNull
private SearchEngineManager mSearchEngineManager; // Contains reference to Context - DO NOT LEAK!
- private TelemetryDispatcher mTelemetryDispatcher; // lazy.
private final SessionMeasurements mSessionMeasurements = new SessionMeasurements();
private boolean mHasResumed;
@Override
public View onCreateView(final String name, final Context context, final AttributeSet attrs) {
final View view;
if (BrowserToolbar.class.getName().equals(name)) {
@@ -1061,25 +1058,16 @@ public class BrowserApp extends GeckoApp
// It'd be better to launch this once, in onCreate, but there's ambiguity for when the
// profile is created so we run here instead. Don't worry, call start short-circuits pretty fast.
final SharedPreferences sharedPrefs = GeckoSharedPrefs.forProfileName(BrowserApp.this, profile.getName());
FileCleanupController.startIfReady(BrowserApp.this, sharedPrefs, profile.getDir().getAbsolutePath());
}
});
- // We don't upload in onCreate because that's only called when the Activity needs to be instantiated
- // and it's possible the system will never free the Activity from memory.
- //
- // We don't upload in onResume/onPause because that will be called each time the Activity is obscured,
- // including by our own Activities/dialogs, and there is no reason to upload each time we're unobscured.
- //
- // So we're left with onStart/onStop.
- mSearchEngineManager.getEngine(new UploadTelemetryCorePingCallback(BrowserApp.this));
-
for (final BrowserAppDelegate delegate : delegates) {
delegate.onStart(this);
}
}
@Override
public void onStop() {
super.onStop();
@@ -3902,22 +3890,18 @@ public class BrowserApp extends GeckoApp
@Override
public void onEditSuggestion(String suggestion) {
mBrowserToolbar.onEditSuggestion(suggestion);
}
@Override
public int getLayout() { return R.layout.gecko_app; }
- @WorkerThread // via constructor
- public TelemetryDispatcher getTelemetryDispatcher() {
- if (mTelemetryDispatcher == null) {
- mTelemetryDispatcher = new TelemetryDispatcher(getProfile().getDir().getAbsolutePath());
- }
- return mTelemetryDispatcher;
+ public SearchEngineManager getSearchEngineManager() {
+ return mSearchEngineManager;
}
public SessionMeasurements getSessionMeasurementDelegate() {
return mSessionMeasurements;
}
// For use from tests only.
@RobocopTarget
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/telemetry/TelemetryCorePingUploadDelegate.java
@@ -0,0 +1,132 @@
+/*
+ * 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.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.delegates.BrowserAppDelegate;
+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;
+import java.lang.ref.WeakReference;
+
+/**
+ * An activity-lifecycle delegate for uploading the core ping.
+ */
+public class TelemetryCorePingUploadDelegate extends BrowserAppDelegate {
+ private static final String LOGTAG = StringUtils.safeSubstring(
+ "Gecko" + TelemetryCorePingUploadDelegate.class.getSimpleName(), 0, 23);
+
+ private TelemetryDispatcher telemetryDispatcher; // lazy
+
+ @Override
+ public void onStart(final BrowserApp browserApp) {
+ // We don't upload in onCreate because that's only called when the Activity needs to be instantiated
+ // and it's possible the system will never free the Activity from memory.
+ //
+ // We don't upload in onResume/onPause because that will be called each time the Activity is obscured,
+ // including by our own Activities/dialogs, and there is no reason to upload each time we're unobscured.
+ //
+ // So we're left with onStart/onStop.
+ final SearchEngineManager searchEngineManager = browserApp.getSearchEngineManager();
+ searchEngineManager.getEngine(new UploadTelemetryCorePingCallback(browserApp));
+ }
+
+ @WorkerThread // via constructor
+ private TelemetryDispatcher getTelemetryDispatcher(final BrowserApp browserApp) {
+ if (telemetryDispatcher == null) {
+ final String profilePath = browserApp.getProfile().getDir().getAbsolutePath();
+ telemetryDispatcher = new TelemetryDispatcher(profilePath);
+ }
+ return telemetryDispatcher;
+ }
+
+ private class UploadTelemetryCorePingCallback implements SearchEngineManager.SearchEngineCallback {
+ private final WeakReference<BrowserApp> activityWeakReference;
+
+ private UploadTelemetryCorePingCallback(final BrowserApp activity) {
+ this.activityWeakReference = new WeakReference<>(activity);
+ }
+
+ // May be called from any thread.
+ @Override
+ public void execute(@Nullable final org.mozilla.gecko.search.SearchEngine engine) {
+ // Don't waste resources queueing to the background thread if we don't have a reference.
+ if (this.activityWeakReference.get() == null) {
+ return;
+ }
+
+ // The containing method can be called from onStart: queue this work so that
+ // the first launch of the activity doesn't trigger profile init too early.
+ //
+ // Additionally, getAndIncrementSequenceNumber must be called from a worker thread.
+ ThreadUtils.postToBackgroundThread(new Runnable() {
+ @WorkerThread
+ @Override
+ public void run() {
+ final BrowserApp activity = activityWeakReference.get();
+ if (activity == null) {
+ return;
+ }
+
+ final GeckoProfile profile = activity.getProfile();
+ if (!TelemetryUploadService.isUploadEnabledByProfileConfig(activity, profile)) {
+ Log.d(LOGTAG, "Core ping upload disabled by profile config. Returning.");
+ return;
+ }
+
+ final String clientID;
+ try {
+ clientID = profile.getClientId();
+ } catch (final IOException e) {
+ Log.w(LOGTAG, "Unable to get client ID to generate core ping: " + e);
+ return;
+ }
+
+ // Each profile can have different telemetry data so we intentionally grab the shared prefs for the profile.
+ final SharedPreferences sharedPrefs = GeckoSharedPrefs.forProfileName(activity, profile.getName());
+ final SessionMeasurements.SessionMeasurementsContainer sessionMeasurementsContainer =
+ activity.getSessionMeasurementDelegate().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);
+
+ getTelemetryDispatcher(activity).queuePingForUpload(activity, pingBuilder);
+ }
+ });
+ }
+
+ private void maybeSetOptionalMeasurements(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);
+ }
+ }
+ }
+}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/telemetry/UploadTelemetryCorePingCallback.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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.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.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.SessionMeasurementsContainer;
-import org.mozilla.gecko.telemetry.pingbuilders.TelemetryCorePingBuilder;
-import org.mozilla.gecko.util.StringUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-
-import java.io.IOException;
-import java.lang.ref.WeakReference;
-
-/**
- * A search engine callback that will attempt to upload the core ping.
- */
-public class UploadTelemetryCorePingCallback implements SearchEngineManager.SearchEngineCallback {
- private static final String LOGTAG = StringUtils.safeSubstring(
- "Gecko" + UploadTelemetryCorePingCallback.class.getSimpleName(), 0, 23);
-
- private final WeakReference<BrowserApp> activityWeakReference;
-
- public UploadTelemetryCorePingCallback(final BrowserApp activity) {
- this.activityWeakReference = new WeakReference<>(activity);
- }
-
- // May be called from any thread.
- @Override
- public void execute(@Nullable final org.mozilla.gecko.search.SearchEngine engine) {
- // Don't waste resources queueing to the background thread if we don't have a reference.
- if (this.activityWeakReference.get() == null) {
- return;
- }
-
- // The containing method can be called from onStart: queue this work so that
- // the first launch of the activity doesn't trigger profile init too early.
- //
- // Additionally, getAndIncrementSequenceNumber must be called from a worker thread.
- ThreadUtils.postToBackgroundThread(new Runnable() {
- @WorkerThread
- @Override
- public void run() {
- final BrowserApp activity = activityWeakReference.get();
- if (activity == null) {
- return;
- }
-
- final GeckoProfile profile = activity.getProfile();
- if (!TelemetryUploadService.isUploadEnabledByProfileConfig(activity, profile)) {
- Log.d(LOGTAG, "Core ping upload disabled by profile config. Returning.");
- return;
- }
-
- final String clientID;
- try {
- clientID = profile.getClientId();
- } catch (final IOException e) {
- Log.w(LOGTAG, "Unable to get client ID to generate core ping: " + e);
- return;
- }
-
- // Each profile can have different telemetry data so we intentionally grab the shared prefs for the profile.
- final SharedPreferences sharedPrefs = GeckoSharedPrefs.forProfileName(activity, profile.getName());
- final SessionMeasurementsContainer sessionMeasurementsContainer =
- activity.getSessionMeasurementDelegate().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);
-
- activity.getTelemetryDispatcher().queuePingForUpload(activity, pingBuilder);
- }
- });
- }
-
- private static void maybeSetOptionalMeasurements(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);
- }
- }
-}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -583,20 +583,20 @@ gbjar.sources += ['java/org/mozilla/geck
'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',
'telemetry/TelemetryConstants.java',
+ 'telemetry/TelemetryCorePingUploadDelegate.java',
'telemetry/TelemetryDispatcher.java',
'telemetry/TelemetryPing.java',
'telemetry/TelemetryUploadService.java',
- 'telemetry/UploadTelemetryCorePingCallback.java',
'TelemetryContract.java',
'text/FloatingActionModeCallback.java',
'text/FloatingToolbarTextSelection.java',
'text/TextAction.java',
'text/TextSelection.java',
'TextSelectionHandle.java',
'ThumbnailHelper.java',
'toolbar/AutocompleteHandler.java',