sbAddOnBundleUpdateService.js
Go to the documentation of this file.
1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 :miv */
3 /*
4 //
5 // BEGIN SONGBIRD GPL
6 //
7 // This file is part of the Songbird web player.
8 //
9 // Copyright(c) 2005-2008 POTI, Inc.
10 // http://songbirdnest.com
11 //
12 // This file may be licensed under the terms of of the
13 // GNU General Public License Version 2 (the "GPL").
14 //
15 // Software distributed under the License is distributed
16 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
17 // express or implied. See the GPL for the specific language
18 // governing rights and limitations.
19 //
20 // You should have received a copy of the GPL along with this
21 // program. If not, go to http://www.gnu.org/licenses/gpl.html
22 // or write to the Free Software Foundation, Inc.,
23 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 //
25 // END SONGBIRD GPL
26 //
27 */
28 
34 //------------------------------------------------------------------------------
35 //------------------------------------------------------------------------------
36 //
37 // Add-on bundle update service component.
38 //
39 // This component periodically checks for updates to the add-on bundle and
40 // presents new add-ons for installation to the user.
41 //
42 //------------------------------------------------------------------------------
43 //------------------------------------------------------------------------------
44 
45 //------------------------------------------------------------------------------
46 //
47 // Add-on bundle update service imported services.
48 //
49 //------------------------------------------------------------------------------
50 
51 // Songbird services.
52 Components.utils.import("resource://app/jsmodules/AddOnUtils.jsm");
53 Components.utils.import("resource://app/jsmodules/ObserverUtils.jsm");
54 Components.utils.import("resource://app/jsmodules/SBUtils.jsm");
55 Components.utils.import("resource://app/jsmodules/WindowUtils.jsm");
56 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
57 
58 
59 //------------------------------------------------------------------------------
60 //
61 // Add-on bundle update service defs.
62 //
63 //------------------------------------------------------------------------------
64 
65 if (typeof(Cc) == "undefined")
66  var Cc = Components.classes;
67 if (typeof(Ci) == "undefined")
68  var Ci = Components.interfaces;
69 if (typeof(Cr) == "undefined")
70  var Cr = Components.results;
71 if (typeof(Cu) == "undefined")
72  var Cu = Components.utils;
73 
74 
75 //------------------------------------------------------------------------------
76 //
77 // Add-on bundle update service configuration.
78 //
79 //------------------------------------------------------------------------------
80 
81 //
82 // className Name of component class.
83 // cid Component CID.
84 // contractID Component contract ID.
85 // ifList List of external component interfaces.
86 // categoryList List of component categories.
87 //
88 // updateEnabledPref Preference for enabling add-on bundle updates.
89 // updateIntervalPref Preference for setting interval between add-on
90 // bundle update checks.
91 // updatePrevAppVersionPref Preference containing the version of the
92 // Application when the add-on bundle update
93 // service previously checked for updates.
94 // defaultUpdateEnabled Default update enabled preference value.
95 // defaultUpdateInterval Default add-on bundle update interval in
96 // seconds.
97 //
98 
100  className: "Songbird Add-on Bundle Update Service",
101  cid: Components.ID("{927d9849-8565-4bc4-805a-f3a6ad1b25ec}"),
102  contractID: "@songbirdnest.com/AddOnBundleUpdateService;1",
103  ifList: [ Ci.sbIAddOnBundleUpdateService, Ci.nsIObserver ],
104 
105  updateEnabledPref: "songbird.recommended_addons.update.enabled",
106  updateIntervalPref: "songbird.recommended_addons.update.interval",
107  updatePrevAppVersionPref:
108  "songbird.recommended_addons.update.prev_app_version",
109  defaultUpdateEnabled: false,
110  defaultUpdateInterval: 86400
111 };
112 
113 sbAddOnBundleUpdateServiceCfg.categoryList = [
114  {
115  category: "app-startup",
116  entry: sbAddOnBundleUpdateServiceCfg.className,
117  value: "service," + sbAddOnBundleUpdateServiceCfg.contractID
118  }
119 ];
120 
121 
122 //------------------------------------------------------------------------------
123 //
124 // Add-on bundle update service.
125 //
126 //------------------------------------------------------------------------------
127 
133 }
134 
135 // Define the object.
137  // Set the constructor.
139 
140  //
141  // Add-on bundle update service fields.
142  //
143  // classDescription Description of component class.
144  // classID Component class ID.
145  // contractID Component contract ID.
146  // _xpcom_categories List of component categories.
147  //
148  // _cfg Configuration settings.
149  // _isInitialized True if the add-on bundle update service has
150  // been initialized.
151  // _observerSet Set of observers.
152  // _prefsAvailable True if preferences are available.
153  // _networkAvailable True if the network is available.
154  // _updateEnabled True if add-on bundle update is enabled.
155  // _checkedFirstRunHasCompleted
156  // True if a check has been made for first-run
157  // completion.
158  // _firstRunHasCompleted True if the first-run has been completed.
159  // _addOnBundleLoader Add-on bundle loader object.
160  //
161 
162  classDescription: sbAddOnBundleUpdateServiceCfg.className,
163  classID: sbAddOnBundleUpdateServiceCfg.cid,
164  contractID: sbAddOnBundleUpdateServiceCfg.contractID,
165  _xpcom_categories: sbAddOnBundleUpdateServiceCfg.categoryList,
166 
168  _isInitialized: false,
169  _observerSet: null,
170  _prefsAvailable: false,
171  _networkAvailable: false,
172  _updateEnabled: false,
173  _checkedFirstRunHasCompleted: false,
174  _firstRunHasCompleted: false,
175  _addOnBundleLoader: null,
176 
177 
178  //----------------------------------------------------------------------------
179  //
180  // Add-on bundle update service sbIAddOnBundleUpdateService services.
181  //
182  //----------------------------------------------------------------------------
183 
188  restartRequired: false,
189 
190 
195  checkForUpdates: function sbAddOnBundleUpdateService_checkForUpdates() {
196  // Ensure the services are initialized.
197  this._initialize();
198 
199  // Present any new add-ons if update is enabled.
200  if (this._updateEnabled) {
201  // Update the add-on bundle cache synchronously if the application was
202  // updated.
203  if (this._getApplicationWasUpdated())
204  this._updateAddOnBundleCache(true);
205 
206  // Present any new add-ons.
207  this._presentNewAddOns();
208  }
209  },
210 
211 
212  //----------------------------------------------------------------------------
213  //
214  // Add-on bundle update service nsIObserver services.
215  //
216  //----------------------------------------------------------------------------
217 
226  observe: function sbAddOnBundleUpdateService_observe(aSubject,
227  aTopic,
228  aData) {
229  // Dispatch processing of the event.
230  switch (aTopic) {
231  case "app-startup" :
232  this._handleAppStartup();
233  break;
234 
235  case "profile-after-change" :
236  this._handleProfileAfterChange();
237  break;
238 
239  case "final-ui-startup" :
240  this._handleFinalUIStartup();
241  break;
242 
243  case "quit-application" :
244  this._handleAppQuit();
245  break;
246 
247  default :
248  break;
249  }
250  },
251 
252 
253  //----------------------------------------------------------------------------
254  //
255  // Add-on bundle update service nsISupports services.
256  //
257  //----------------------------------------------------------------------------
258 
259  QueryInterface: XPCOMUtils.generateQI(sbAddOnBundleUpdateServiceCfg.ifList),
260 
261 
262  //----------------------------------------------------------------------------
263  //
264  // Add-on bundle update service event handler services.
265  //
266  //----------------------------------------------------------------------------
267 
272  _handleAppStartup: function sbAddOnBundleUpdateService__handleAppStartup() {
273  // Initialize the services.
274  this._initialize();
275  },
276 
277 
282  _handleProfileAfterChange:
283  function sbAddOnBundleUpdateService__handleProfileAfterChange() {
284  // Preferences are now available.
285  this._prefsAvailable = true;
286 
287  // Initialize the services.
288  this._initialize();
289  },
290 
291 
296  _handleFinalUIStartup:
297  function sbAddOnBundleUpdateService__handleFinalUIStartup() {
298  // The network is now available.
299  //XXXeps trying to load the add-on bundle too early will result in a hang
300  //XXXeps during EM restart. Not sure how to fix this better.
301  this._networkAvailable = true;
302 
303  // Initialize the services.
304  this._initialize();
305  },
306 
307 
312  _handleAppQuit: function sbAddOnBundleUpdateService__handleAppQuit() {
313  // Finalize the services.
314  this._finalize();
315  },
316 
317 
322  _handleAddOnUpdateTimer:
323  function sbAddOnBundleUpdateService__handleAddOnUpdateTimer(aTimer) {
324  // Update the add-on bundle cache.
325  this._updateAddOnBundleCache(false);
326  },
327 
328 
329  //----------------------------------------------------------------------------
330  //
331  // Internal add-on bundle update services.
332  //
333  //----------------------------------------------------------------------------
334 
339  _initialize: function sbAddOnBundleUpdateService__initialize() {
340  // Do nothing if already initialized.
341  if (this._isInitialized)
342  return;
343 
344  // Set up observers.
345  if (!this._observerSet) {
346  this._observerSet = new ObserverSet();
347  this._observerSet.add(this, "quit-application", false, false);
348  this._observerSet.add(this, "profile-after-change", false, true);
349  this._observerSet.add(this, "final-ui-startup", false, true);
350  }
351 
352  // Wait until preferences are available.
353  if (!this._prefsAvailable)
354  return;
355 
356  // Initialize the previous application version if first-run has not
357  // completed. This needs to be done as soon as possible so it occurs before
358  // the first-run.
359  if (!this._checkedFirstRunHasCompleted) {
360  this._firstRunHasCompleted = SBUtils.hasFirstRunCompleted();
361  if (!this._firstRunHasCompleted)
362  this._updatePrevAppVersion();
363  this._checkedFirstRunHasCompleted = true;
364  }
365 
366  // Wait until the network is available.
367  if (!this._networkAvailable)
368  return;
369 
370  // Initialization is now complete.
371  this._isInitialized = true;
372 
373  // Don't check for add-on bundle updates if the first-run has not completed.
374  if (!this._firstRunHasCompleted)
375  return;
376 
377  // Get the application services.
378  var Application = Cc["@mozilla.org/fuel/application;1"]
379  .getService(Ci.fuelIApplication);
380 
381  // Check if add-on bundle update is enabled. Do nothing more if not.
382  this._updateEnabled =
383  Application.prefs.getValue(this._cfg.updateEnabledPref,
384  this._cfg.defaultUpdateEnabled);
385  if (!this._updateEnabled)
386  return;
387 
388  // Get the add-on bundle update period.
389  var updateInterval =
390  Application.prefs.getValue(this._cfg.updateIntervalPref,
391  this._cfg.defaultUpdateInterval);
392 
393  // Register an add-on bundle update timer.
394  /*XXXeps no way to unregister. */
395  var updateTimerMgr = Cc["@mozilla.org/updates/timer-manager;1"]
396  .createInstance(Ci.nsIUpdateTimerManager);
397  var _this = this;
398  var func = function(aTimer) { _this._handleAddOnUpdateTimer(aTimer); };
399  updateTimerMgr.registerTimer("add-on-bundle-update-timer",
400  func,
401  updateInterval);
402  },
403 
404 
409  _finalize: function sbAddOnBundleUpdateService__finalize() {
410  // Cancel the add-on bundle loader.
411  if (this._addOnBundleLoader) {
412  this._addOnBundleLoader.cancel();
413  this._addOnBundleLoader = null;
414  }
415 
416  // Remove observers.
417  if (this._observerSet) {
418  this._observerSet.removeAll();
419  this._observerSet = null;
420  }
421  },
422 
423 
428  _presentNewAddOns:
429  function sbAddOnBundleUpdateService__presentNewAddOns() {
430  // Load the add-on bundle.
431  var addOnBundle = this._loadNewAddOns();
432 
433  // Do nothing if no add-ons.
434  if (!addOnBundle || (addOnBundle.bundleExtensionCount == 0))
435  return;
436 
437  // Present the new add-ons.
438  var restartRequired = {};
439  WindowUtils.openModalDialog
440  (null,
441  "chrome://songbird/content/xul/recommendedAddOnsWizard.xul",
442  "",
443  "chrome,modal=yes,centerscreen",
444  [ addOnBundle ],
445  [ restartRequired ]);
446  this.restartRequired = (restartRequired.value == "true");
447  },
448 
449 
456  _loadNewAddOns: function sbAddOnBundleUpdateService__loadNewAddOns() {
457  // Create an add-on bundle loader.
458  var addOnBundleLoader = new AddOnBundleLoader();
459 
460  // Add all installed add-ons to the blacklist. This prevents an add-on
461  // from being presented if it was previously installed and then uninstalled.
462  AddOnBundleLoader.addInstalledAddOnsToBlacklist();
463 
464  // Load the add-on bundle from cache.
465  addOnBundleLoader.filterInstalledAddOns = true;
466  addOnBundleLoader.filterBlacklistedAddOns = true;
467  addOnBundleLoader.readFromCache = true;
468  addOnBundleLoader.start(null);
469 
470  // Check for add-on bundle loading errors.
471  if (!addOnBundleLoader.complete ||
472  !Components.isSuccessCode(addOnBundleLoader.result))
473  return null;
474 
475  return addOnBundleLoader.addOnBundle;
476  },
477 
478 
486  _updateAddOnBundleCache:
487  function sbAddOnBundleUpdateService__updateAddOnBundleCache(aSync) {
488  // Start loading the add-on bundle into the cache.
489  if (!this._addOnBundleLoader) {
490  // Create an add-on bundle loader.
491  this._addOnBundleLoader = new AddOnBundleLoader();
492 
493  // Start loading the add-on bundle into the cache.
494  var _this = this;
495  var func = function() { _this._updateAddOnBundleCacheContinue(); }
496  this._addOnBundleLoader.start(func);
497  }
498 
499  // Wait for update to complete if operating synchronously.
500  if (aSync) {
501  // Get the current thread.
502  var threadManager = Cc["@mozilla.org/thread-manager;1"]
503  .getService(Ci.nsIThreadManager);
504  currentThread = threadManager.currentThread;
505 
506  // Process events until update completes.
507  while (this._addOnBundleLoader && !this._addOnBundleLoader.complete) {
508  currentThread.processNextEvent(true);
509  }
510  }
511  },
512 
513 
518  _updateAddOnBundleCacheContinue:
519  function sbAddOnBundleUpdateService__updateAddOnBundleCacheContinue() {
520  // Clear the add-on bundle loader upon completion.
521  if (this._addOnBundleLoader.complete)
522  this._addOnBundleLoader = null;
523  },
524 
525 
532  _getApplicationWasUpdated:
533  function sbAddOnBundleUpdateService__getApplicationWasUpdated() {
534  var updated = false;
535 
536  // Get the application services.
537  var Application = Cc["@mozilla.org/fuel/application;1"]
538  .getService(Ci.fuelIApplication);
539 
540  // Get the current application version.
541  var appInfo = Cc["@mozilla.org/xre/app-info;1"]
542  .getService(Ci.nsIXULAppInfo);
543  var appVersion = appInfo.version;
544 
545  // Get the previous application version.
546  var prevAppVersion =
547  Application.prefs.getValue(this._cfg.updatePrevAppVersionPref, "");
548 
549  // Check for application update. If the previous application version
550  // preference has not been set, the application must have been updated from
551  // a version of the application before the add-on bundle update support was
552  // added.
553  if (!prevAppVersion || (prevAppVersion != appVersion))
554  updated = true;
555 
556  // Update the previous application version.
557  Application.prefs.setValue(this._cfg.updatePrevAppVersionPref, appVersion);
558 
559  return updated;
560  },
561 
562 
568  _updatePrevAppVersion:
569  function sbAddOnBundleUpdateService__updatePrevAppVersion() {
570  // Get the current application version.
571  var appInfo = Cc["@mozilla.org/xre/app-info;1"]
572  .getService(Ci.nsIXULAppInfo);
573  var appVersion = appInfo.version;
574 
575  // Update the previous application version.
576  var Application = Cc["@mozilla.org/fuel/application;1"]
577  .getService(Ci.fuelIApplication);
578  Application.prefs.setValue(this._cfg.updatePrevAppVersionPref, appVersion);
579  }
580 };
581 
582 
583 //------------------------------------------------------------------------------
584 //
585 // Add-on bundle update service component services.
586 //
587 //------------------------------------------------------------------------------
588 
589 function NSGetModule(compMgr, fileSpec) {
590  return XPCOMUtils.generateModule([sbAddOnBundleUpdateService]);
591 }
592 
GeneratorThread currentThread
const Cu
classDescription entry
Definition: FeedWriter.js:1427
const Cc
function checkForUpdates()
var Application
Definition: sbAboutDRM.js:37
sbOSDControlService prototype className
sbDeviceFirmwareAutoCheckForUpdate prototype contractID
function sbAddOnBundleUpdateService()
sbOSDControlService prototype QueryInterface
sbDeviceFirmwareAutoCheckForUpdate prototype classDescription
var sbAddOnBundleUpdateServiceCfg
function NSGetModule(compMgr, fileSpec)
var SBUtils
Definition: SBUtils.jsm:71
DataRemote prototype constructor
var _this
return null
Definition: FeedWriter.js:1143
countRef value
Definition: FeedWriter.js:1423
const Cr
const Ci
sbDeviceFirmwareAutoCheckForUpdate prototype classID
sbWindowsAutoPlayServiceCfg _xpcom_categories
function AddOnBundleLoader()
Definition: AddOnUtils.jsm:93
_updateTextAndScrollDataForFrame aData
sbDeviceFirmwareAutoCheckForUpdate prototype observe