1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 const kEnabledPref = "browser.laterrun.enabled";
6 const kPagePrefRoot = "browser.laterrun.pages.";
7 // Number of sessions we've been active in
8 const kSessionCountPref = "browser.laterrun.bookkeeping.sessionCount";
9 // Time the profile was created at in seconds:
10 const kProfileCreationTime = "browser.laterrun.bookkeeping.profileCreationTime";
11 // Time the update was applied at in seconds:
12 const kUpdateAppliedTime = "browser.laterrun.bookkeeping.updateAppliedTime";
14 // After 50 sessions or 1 month since install, assume we will no longer be
15 // interested in showing anything to "new" users
16 const kSelfDestructSessionLimit = 50;
17 const kSelfDestructHoursLimit = 31 * 24;
22 minimumHoursSinceInstall,
28 this.minimumHoursSinceInstall = minimumHoursSinceInstall || 0;
29 this.minimumSessionCount = minimumSessionCount || 1;
30 this.requireBoth = requireBoth || false;
35 return Services.prefs.getBoolPref(this.pref + "hasRun", false);
38 applies(sessionInfo) {
42 if (this.requireBoth) {
44 sessionInfo.sessionCount >= this.minimumSessionCount &&
45 sessionInfo.hoursSinceInstall >= this.minimumHoursSinceInstall
49 sessionInfo.sessionCount >= this.minimumSessionCount ||
50 sessionInfo.hoursSinceInstall >= this.minimumHoursSinceInstall
55 export let LaterRun = {
56 get ENABLE_REASON_NEW_PROFILE() {
59 get ENABLE_REASON_UPDATE_APPLIED() {
68 if (reason == this.ENABLE_REASON_NEW_PROFILE) {
69 // If this is the first run, set the time we were installed
71 Services.prefs.getPrefType(kProfileCreationTime) ==
72 Ci.nsIPrefBranch.PREF_INVALID
74 // We need to store seconds in order to fit within int prefs.
75 Services.prefs.setIntPref(
77 Math.floor(Date.now() / 1000)
81 } else if (reason == this.ENABLE_REASON_UPDATE_APPLIED) {
82 Services.prefs.setIntPref(
84 Math.floor(Services.startup.getStartupInfo().start.getTime() / 1000)
89 this.hoursSinceInstall > kSelfDestructHoursLimit ||
90 this.sessionCount > kSelfDestructSessionLimit
96 // The enabled, hoursSinceInstall and sessionCount properties mirror the
97 // preferences system, and are here for convenience.
99 return Services.prefs.getBoolPref(kEnabledPref, false);
104 Services.prefs.setBoolPref(kEnabledPref, true);
109 get hoursSinceInstall() {
110 let installStampSec = Services.prefs.getIntPref(
111 kProfileCreationTime,
114 return Math.floor((Date.now() / 1000 - installStampSec) / 3600);
117 get hoursSinceUpdate() {
118 let updateStampSec = Services.prefs.getIntPref(kUpdateAppliedTime, 0);
119 return Math.floor((Date.now() / 1000 - updateStampSec) / 3600);
123 if (this._sessionCount) {
124 return this._sessionCount;
126 return (this._sessionCount = Services.prefs.getIntPref(
132 set sessionCount(val) {
133 this._sessionCount = val;
134 Services.prefs.setIntPref(kSessionCountPref, val);
137 // Because we don't want to keep incrementing this indefinitely for no reason,
138 // we will turn ourselves off after a set amount of time/sessions (see top of
141 Services.prefs.setBoolPref(kEnabledPref, false);
144 // Create an array of Page objects based on the currently set prefs
146 // Enumerate all the pages.
147 let allPrefsForPages = Services.prefs.getChildList(kPagePrefRoot);
148 let pageDataStore = new Map();
149 for (let pref of allPrefsForPages) {
150 let [slug, prop] = pref.substring(kPagePrefRoot.length).split(".");
151 if (!pageDataStore.has(slug)) {
152 pageDataStore.set(slug, {
153 pref: pref.substring(0, pref.length - prop.length),
156 if (prop == "requireBoth" || prop == "hasRun") {
157 pageDataStore.get(slug)[prop] = Services.prefs.getBoolPref(pref, false);
158 } else if (prop == "url") {
159 pageDataStore.get(slug)[prop] = Services.prefs.getStringPref(pref, "");
161 pageDataStore.get(slug)[prop] = Services.prefs.getIntPref(pref, 0);
165 for (let [, pageData] of pageDataStore) {
169 let urlString = Services.urlFormatter.formatURL(pageData.url.trim());
170 uri = Services.io.newURI(urlString);
173 "Invalid LaterRun page URL ",
179 if (!uri.schemeIs("https")) {
180 console.error("Insecure LaterRun page URL ", uri.spec, " ignored.");
182 pageData.url = uri.spec;
183 rv.push(new Page(pageData));
190 // Return a URL for display as a 'later run' page if its criteria are matched,
191 // or null otherwise.
192 // NB: will only return one page at a time; if multiple pages match, it's up
193 // to the preference service which one gets shown first, and the next one
194 // will be shown next startup instead.
199 let pages = this.readPages();
200 let page = pages.find(p => p.applies(this));
202 Services.prefs.setBoolPref(page.pref + "hasRun", true);