--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -72,18 +72,19 @@ 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.TelemetryConstants;
+import org.mozilla.gecko.telemetry.TelemetryDispatcher;
import org.mozilla.gecko.telemetry.TelemetryUploadService;
+import org.mozilla.gecko.telemetry.core.TelemetryCorePingBuilder;
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;
import org.mozilla.gecko.util.Clipboard;
@@ -308,16 +309,18 @@ public class BrowserApp extends GeckoApp
private final List<BrowserAppDelegate> delegates = Collections.unmodifiableList(Arrays.asList(
(BrowserAppDelegate) new AddToHomeScreenPromotion(),
(BrowserAppDelegate) new ScreenshotDelegate()
));
@NonNull
private SearchEngineManager searchEngineManager; // Contains reference to Context - DO NOT LEAK!
+ private TelemetryDispatcher mTelemetryDispatcher;
+
@Override
public View onCreateView(final String name, final Context context, final AttributeSet attrs) {
final View view;
if (BrowserToolbar.class.getName().equals(name)) {
view = BrowserToolbar.create(context, attrs);
} else if (TabsPanel.TabsLayout.class.getName().equals(name)) {
view = TabsPanel.createTabsLayout(context, attrs);
} else {
@@ -748,33 +751,36 @@ public class BrowserApp extends GeckoApp
"Menu:Add",
"Menu:Remove",
"Sanitize:ClearHistory",
"Sanitize:ClearSyncedTabs",
"Settings:Show",
"Telemetry:Gather",
"Updater:Launch");
+ final GeckoProfile profile = getProfile();
+
// We want to upload the telemetry core ping as soon after startup as possible. It relies on the
// Distribution being initialized. If you move this initialization, ensure it plays well with telemetry.
final Distribution distribution = Distribution.init(this);
- distribution.addOnDistributionReadyCallback(new DistributionStoreCallback(this, getProfile().getName()));
+ distribution.addOnDistributionReadyCallback(new DistributionStoreCallback(this, profile.getName()));
searchEngineManager = new SearchEngineManager(this, distribution);
+ mTelemetryDispatcher = new TelemetryDispatcher(profile.getDir().getAbsolutePath());
// Init suggested sites engine in BrowserDB.
final SuggestedSites suggestedSites = new SuggestedSites(appContext, distribution);
- final BrowserDB db = getProfile().getDB();
+ final BrowserDB db = profile.getDB();
db.setSuggestedSites(suggestedSites);
JavaAddonManager.getInstance().init(appContext);
mSharedPreferencesHelper = new SharedPreferencesHelper(appContext);
mOrderedBroadcastHelper = new OrderedBroadcastHelper(appContext);
- mReadingListHelper = new ReadingListHelper(appContext, getProfile());
- mAccountsHelper = new AccountsHelper(appContext, getProfile());
+ mReadingListHelper = new ReadingListHelper(appContext, profile);
+ mAccountsHelper = new AccountsHelper(appContext, profile);
final AdjustHelperInterface adjustHelper = AdjustConstants.getAdjustHelper();
adjustHelper.onCreate(this, AdjustConstants.MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN);
// 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(this);
@@ -1143,17 +1149,17 @@ public class BrowserApp extends GeckoApp
// 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.
- searchEngineManager.getEngine(new UploadTelemetryCallback(BrowserApp.this));
+ searchEngineManager.getEngine(new UploadTelemetryCorePingCallback(BrowserApp.this));
for (final BrowserAppDelegate delegate : delegates) {
delegate.onStart(this);
}
}
@Override
public void onStop() {
@@ -4067,67 +4073,71 @@ public class BrowserApp extends GeckoApp
mActionBarFlipper.showPrevious();
// Only slide the urlbar out if it was hidden when the action mode started
// Don't animate hiding it so that there's no flash as we switch back to url mode
mDynamicToolbar.setTemporarilyVisible(false, VisibilityTransition.IMMEDIATE);
}
- @WorkerThread // synchronous SharedPrefs write.
- private static void uploadTelemetry(final Context context, final GeckoProfile profile,
- final org.mozilla.gecko.search.SearchEngine defaultEngine) {
- if (!TelemetryUploadService.isUploadEnabledByProfileConfig(context, profile)) {
- return;
- }
-
- final SharedPreferences sharedPrefs = GeckoSharedPrefs.forProfileName(context, profile.getName());
- final int seq = sharedPrefs.getInt(TelemetryConstants.PREF_SEQ_COUNT, 1);
-
- // We store synchronously before sending the Intent to ensure this sequence number will not be re-used.
- sharedPrefs.edit().putInt(TelemetryConstants.PREF_SEQ_COUNT, seq + 1).commit();
-
- final Intent i = new Intent(TelemetryUploadService.ACTION_UPLOAD_CORE);
- i.setClass(context, TelemetryUploadService.class);
- i.putExtra(TelemetryUploadService.EXTRA_DEFAULT_SEARCH_ENGINE, (defaultEngine == null) ? null : defaultEngine.getIdentifier());
- i.putExtra(TelemetryUploadService.EXTRA_DOC_ID, UUID.randomUUID().toString());
- i.putExtra(TelemetryUploadService.EXTRA_PROFILE_NAME, profile.getName());
- i.putExtra(TelemetryUploadService.EXTRA_PROFILE_PATH, profile.getDir().getAbsolutePath());
- i.putExtra(TelemetryUploadService.EXTRA_SEQ, seq);
- context.startService(i);
- }
-
- private static class UploadTelemetryCallback implements SearchEngineManager.SearchEngineCallback {
+ private static class UploadTelemetryCorePingCallback implements SearchEngineManager.SearchEngineCallback {
private final WeakReference<BrowserApp> activityWeakReference;
- public UploadTelemetryCallback(final BrowserApp activity) {
+ public UploadTelemetryCorePingCallback(final BrowserApp activity) {
this.activityWeakReference = new WeakReference<>(activity);
}
// May be called from any thread.
@Override
public void execute(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, uploadTelemetry must be called from a worker thread.
+ // Additionally, getAndIncrementSequenceNumberSync 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;
}
- uploadTelemetry(activity, activity.getProfile(), engine);
+
+ 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 TelemetryCorePingBuilder pingBuilder = new TelemetryCorePingBuilder(activity, TelemetryCorePingBuilder.getServer(sharedPrefs))
+ .setClientID(clientID)
+ .setDefaultSearchEngine(TelemetryCorePingBuilder.getEngineIdentifier(engine))
+ .setProfileCreationDate(TelemetryCorePingBuilder.getProfileCreationDate(activity, profile))
+ .setSequenceNumber(TelemetryCorePingBuilder.getAndIncrementSequenceNumberSync(sharedPrefs));
+ final String distributionId = sharedPrefs.getString(DistributionStoreCallback.PREF_DISTRIBUTION_ID, null);
+ if (distributionId != null) {
+ pingBuilder.setOptDistributionID(distributionId);
+ }
+
+ activity.mTelemetryDispatcher.queuePingForUpload(activity, pingBuilder);
}
});
}
}
public static interface TabStripInterface {
public void refresh();
void setOnTabChangedListener(OnTabAddedOrRemovedListener listener);