Bug 1324049 - Implement pref for opening the privacy policy in a background tab on first run instead of showing the data choices infobar. r=gijs a=lizzard
authorDão Gottwald <dao@mozilla.com>
Sun, 25 Dec 2016 07:36:25 +0100
changeset 353375 01a5cd136989665e51c9a21542f94af20605e48d
parent 353374 dbbbc4ab2f1bd1e37ebbc45cdedf291074717da0
child 353376 6329a43064daac4f8bef53202ae3ff57e173c9d7
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgijs, lizzard
bugs1324049
milestone52.0a2
Bug 1324049 - Implement pref for opening the privacy policy in a background tab on first run instead of showing the data choices infobar. r=gijs a=lizzard
toolkit/components/telemetry/TelemetryReportingPolicy.jsm
toolkit/components/telemetry/datareporting-prefs.js
toolkit/components/telemetry/docs/internals/preferences.rst
--- a/toolkit/components/telemetry/TelemetryReportingPolicy.jsm
+++ b/toolkit/components/telemetry/TelemetryReportingPolicy.jsm
@@ -42,16 +42,19 @@ const PREF_DATA_SUBMISSION_ENABLED = PRE
 const PREF_CURRENT_POLICY_VERSION = PREF_BRANCH + "currentPolicyVersion";
 // This indicates the minimum required policy version. If the accepted policy version
 // is lower than this, the notification bar must be showed again.
 const PREF_MINIMUM_POLICY_VERSION = PREF_BRANCH + "minimumPolicyVersion";
 // The version of the accepted policy.
 const PREF_ACCEPTED_POLICY_VERSION = PREF_BRANCH + "dataSubmissionPolicyAcceptedVersion";
 // The date user accepted the policy.
 const PREF_ACCEPTED_POLICY_DATE = PREF_BRANCH + "dataSubmissionPolicyNotifiedTime";
+// URL of privacy policy to be opened in a background tab on first run instead of showing the
+// data choices infobar.
+const PREF_FIRST_RUN_URL = PREF_BRANCH + "firstRunURL";
 // The following preferences are deprecated and will be purged during the preferences
 // migration process.
 const DEPRECATED_FHR_PREFS = [
   PREF_BRANCH + "dataSubmissionPolicyAccepted",
   PREF_BRANCH + "dataSubmissionPolicyBypassAcceptance",
   PREF_BRANCH + "dataSubmissionPolicyResponseType",
   PREF_BRANCH + "dataSubmissionPolicyResponseTime"
 ];
@@ -90,18 +93,18 @@ var Policy = {
 function NotifyPolicyRequest(aLog) {
   this._log = aLog;
 }
 
 NotifyPolicyRequest.prototype = Object.freeze({
   /**
    * Called when the user is notified of the policy.
    */
-  onUserNotifyComplete: function () {
-    return TelemetryReportingPolicyImpl._infobarShownCallback();
+  onUserNotifyComplete: function() {
+    return TelemetryReportingPolicyImpl._userNotified();
    },
 
   /**
    * Called when there was an error notifying the user about the policy.
    *
    * @param error
    *        (Error) Explains what went wrong.
    */
@@ -155,17 +158,17 @@ this.TelemetryReportingPolicy = {
   testIsUserNotified: function() {
     return TelemetryReportingPolicyImpl.isUserNotifiedOfCurrentPolicy;
   },
 
   /**
    * Test only method, used to simulate the infobar being shown in xpcshell tests.
    */
   testInfobarShown: function() {
-    return TelemetryReportingPolicyImpl._infobarShownCallback();
+    return TelemetryReportingPolicyImpl._userNotified();
   },
 };
 
 var TelemetryReportingPolicyImpl = {
   _logger: null,
   // Keep track of the notification status if user wasn't notified already.
   _notificationInProgress: false,
   // The timer used to show the datachoices notification at startup.
@@ -382,44 +385,110 @@ var TelemetryReportingPolicyImpl = {
 
     this._log.trace("_showInfobar - User not notified, notifying now.");
     this._notificationInProgress = true;
     let request = new NotifyPolicyRequest(this._log);
     Observers.notify("datareporting:notify-data-policy:request", request);
   },
 
   /**
-   * Called when the user is notified with the infobar.
+   * Called when the user is notified with the infobar or otherwise.
    */
-  _infobarShownCallback: function() {
-    this._log.trace("_infobarShownCallback");
+  _userNotified() {
+    this._log.trace("_userNotified");
     this._recordNotificationData();
     TelemetrySend.notifyCanUpload();
   },
 
   /**
    * Record date and the version of the accepted policy.
    */
   _recordNotificationData: function() {
     this._log.trace("_recordNotificationData");
     this.dataSubmissionPolicyNotifiedDate = Policy.now();
     this.dataSubmissionPolicyAcceptedVersion = this.currentPolicyVersion;
     // The user was notified and the notification data saved: the notification
     // is no longer in progress.
     this._notificationInProgress = false;
   },
 
+  /**
+   * Try to open the privacy policy in a background tab instead of showing the infobar.
+   */
+  _openFirstRunPage() {
+    let firstRunPolicyURL = Preferences.get(PREF_FIRST_RUN_URL, "");
+    if (!firstRunPolicyURL) {
+      return false;
+    }
+    firstRunPolicyURL = Services.urlFormatter.formatURL(firstRunPolicyURL);
+
+    let win;
+    try {
+      const { RecentWindow } = Cu.import("resource:///modules/RecentWindow.jsm", {});
+      win = RecentWindow.getMostRecentBrowserWindow();
+    } catch (e) {}
+
+    if (!win) {
+      this._log.info("Couldn't find browser window to open first-run page. Falling back to infobar.");
+      return false;
+    }
+
+    // We'll consider the user notified once the privacy policy has been loaded
+    // in a background tab even if that tab hasn't been selected.
+    let progressListener = {};
+    progressListener.onStateChange =
+      (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) => {
+        if (aWebProgress.isTopLevel &&
+            aBrowser == tab.linkedBrowser &&
+            aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
+            aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) {
+          let uri = aBrowser.documentURI;
+          if (uri && !/^about:(blank|neterror|certerror|blocked)/.test(uri.spec)) {
+            this._userNotified();
+          } else {
+            this._log.info("Failed to load first-run page. Falling back to infobar.");
+            this._showInfobar();
+          }
+          removeListeners();
+        }
+      };
+
+    let removeListeners = () => {
+      win.removeEventListener("unload", removeListeners);
+      win.gBrowser.removeTabsProgressListener(progressListener);
+    };
+
+    win.addEventListener("unload", removeListeners);
+    win.gBrowser.addTabsProgressListener(progressListener);
+
+    let tab = win.gBrowser.loadOneTab(firstRunPolicyURL, { inBackground: true });
+
+    return true;
+  },
+
   observe: function(aSubject, aTopic, aData) {
     if (aTopic != "sessionstore-windows-restored") {
       return;
     }
 
     const isFirstRun = Preferences.get(PREF_FIRST_RUN, true);
+    if (isFirstRun) {
+      // We're performing the first run, flip firstRun preference for subsequent runs.
+      Preferences.set(PREF_FIRST_RUN, false);
+
+      try {
+        if (this._openFirstRunPage()) {
+          return;
+        }
+      } catch (e) {
+        this._log.error("Failed to open privacy policy tab: " + e);
+      }
+    }
+
+    // Show the info bar.
     const delay =
       isFirstRun ? NOTIFICATION_DELAY_FIRST_RUN_MSEC: NOTIFICATION_DELAY_NEXT_RUNS_MSEC;
 
     this._startupNotificationTimerId = Policy.setShowInfobarTimeout(
         // Calling |canUpload| eventually shows the infobar, if needed.
         () => this._showInfobar(), delay);
-    // We performed at least a run, flip the firstRun preference.
-    Preferences.set(PREF_FIRST_RUN, false);
   },
 };
--- a/toolkit/components/telemetry/datareporting-prefs.js
+++ b/toolkit/components/telemetry/datareporting-prefs.js
@@ -4,8 +4,9 @@
 
 pref("datareporting.policy.dataSubmissionEnabled", true);
 pref("datareporting.policy.dataSubmissionPolicyNotifiedTime", "0");
 pref("datareporting.policy.dataSubmissionPolicyAcceptedVersion", 0);
 pref("datareporting.policy.dataSubmissionPolicyBypassNotification", false);
 pref("datareporting.policy.currentPolicyVersion", 2);
 pref("datareporting.policy.minimumPolicyVersion", 1);
 pref("datareporting.policy.minimumPolicyVersion.channel-beta", 2);
+pref("datareporting.policy.firstRunURL", "");
--- a/toolkit/components/telemetry/docs/internals/preferences.rst
+++ b/toolkit/components/telemetry/docs/internals/preferences.rst
@@ -52,16 +52,20 @@ Preferences
 
 Data-choices notification
 -------------------------
 
 ``toolkit.telemetry.reportingpolicy.firstRun``
 
   This preference is not present until the first run. After, its value is set to false. This is used to show the infobar with a more aggressive timeout if it wasn't shown yet.
 
+``datareporting.policy.firstRunURL``
+
+  If set, a browser tab will be opened on first run instead of the infobar.
+
 ``datareporting.policy.dataSubmissionEnabled``
 
   This is the data submission master kill switch. If disabled, no policy is shown or upload takes place, ever.
 
 ``datareporting.policy.dataSubmissionPolicyNotifiedTime``
 
   Records the date user was shown the policy. This preference is also used on Android.