sbDeviceFirmwareAutoCheckForUpdate.js
Go to the documentation of this file.
1 /*
2  *=BEGIN SONGBIRD GPL
3  *
4  * This file is part of the Songbird web player.
5  *
6  * Copyright(c) 2005-2010 POTI, Inc.
7  * http://www.songbirdnest.com
8  *
9  * This file may be licensed under the terms of of the
10  * GNU General Public License Version 2 (the ``GPL'').
11  *
12  * Software distributed under the License is distributed
13  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
14  * express or implied. See the GPL for the specific language
15  * governing rights and limitations.
16  *
17  * You should have received a copy of the GPL along with this
18  * program. If not, go to http://www.gnu.org/licenses/gpl.html
19  * or write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  *=END SONGBIRD GPL
23  */
24 
25 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
26 Components.utils.import("resource://app/jsmodules/SBDataRemoteUtils.jsm");
27 Components.utils.import("resource://app/jsmodules/SBTimer.jsm");
28 Components.utils.import("resource://app/jsmodules/SBUtils.jsm");
29 Components.utils.import("resource://app/jsmodules/StringUtils.jsm");
30 Components.utils.import("resource://app/jsmodules/WindowUtils.jsm");
31 
32 const Ci = Components.interfaces;
33 const Cc = Components.classes;
34 const Cr = Components.results;
35 const Cu = Components.utils;
36 
37 const NS_QUIT_APPLICATION_GRANTED_TOPIC = "quit-application-granted";
38 const NS_TIMER_CALLBACK_TOPIC = "timer-callback";
39 const SB_FINAL_UI_STARTUP_TOPIC = "final-ui-startup";
40 const SB_TIMER_MANAGER_PREFIX = "songbird-device-firmware-update-";
41 
42 const FIRMWARE_WIZARD_ACTIVE_DATAREMOTE = "firmware.wizard.active";
43 
44 const FIRMWARE_UPDATE_INTERVAL = "songbird.firmware.update.defaultInterval";
45 
46 function DEBUG(msg) {
47  return;
48 
49  function repr(x) {
50  if (typeof(x) == "undefined") {
51  return 'undefined';
52  } else if (x == null) {
53  return 'null';
54  } else if (typeof x == 'function') {
55  return x.name+'(...)';
56  } else if (typeof x == 'string') {
57  return x.toSource().match(/^\(new String\((.*)\)\)$/)[1];
58  } else if (typeof x == 'number') {
59  return x.toSource().match(/^\(new Number\((.*)\)\)$/)[1];
60  } else if (typeof x == 'object' && x instanceof Array) {
61  var value = '';
62  for (var i=0; i<x.length; i++) {
63  if (i) value = value + ', ';
64  value = value + repr(x[i]);
65  }
66  return '['+value+']';
67  } else if (x instanceof Ci.nsISupports) {
68  return x.toString();
69  } else {
70  return x.toSource();
71  }
72  }
73  var fullMsg = 'sbDeviceFirmwareAutocheckForUpdate:: '+DEBUG.caller.name;
74  if (typeof(msg) == "undefined") {
75  // when nothing is passed in, print the arguments
76  fullMsg += '(';
77  for (var i=0; i<DEBUG.caller.length; i++) {
78  if (i) fullMsg += ', ';
79  fullMsg += repr(DEBUG.caller.arguments[i]);
80  }
81  fullMsg += ')';
82  } else {
83  fullMsg += ': ';
84  if (typeof msg != 'object' || msg instanceof Array) {
85  fullMsg += repr(msg);
86  } else {
87  fullMsg += msg.toSource();
88  }
89  }
90  fullMsg += '\n';
91 
92  Cu.reportError(fullMsg);
93 }
94 
95 
97  DEBUG();
98 
99  var obs = Cc["@mozilla.org/observer-service;1"]
100  .getService(Ci.nsIObserverService);
101  obs.addObserver(this, SB_FINAL_UI_STARTUP_TOPIC, false);
102 }
103 
105 sbDeviceFirmwareAutoCheckForUpdate.prototype._deviceFirmwareUpdater = null;
107 sbDeviceFirmwareAutoCheckForUpdate.prototype._deviceManager = null;
109 sbDeviceFirmwareAutoCheckForUpdate.prototype._registeredDevices = {};
115 sbDeviceFirmwareAutoCheckForUpdate.prototype._queueItemSuccess = false;
119 sbDeviceFirmwareAutoCheckForUpdate.prototype._timerManager = null;
120 
121 sbDeviceFirmwareAutoCheckForUpdate.prototype.classDescription =
122  'Songbird Device Firmware Auto Check For Update';
124  Components.ID("{2137a87f-2ade-448b-a093-bad4f6649fa3}");
126  '@songbirdnest.com/Songbird/Device/Firmware/AutoCheckForUpdate;1';
127 sbDeviceFirmwareAutoCheckForUpdate.prototype.flags = Ci.nsIClassInfo.SINGLETON;
129  [Ci.nsISupports, Ci.nsIClassInfo, Ci.nsIObserver, Ci.sbIDeviceEventListener];
130 sbDeviceFirmwareAutoCheckForUpdate.prototype.getHelperForLanguage = Function();
131 sbDeviceFirmwareAutoCheckForUpdate.prototype.getInterfaces =
132 function sbDeviceFirmwareAutoCheckForUpdate_getInterfaces(count) {
133  count.value = this.interfaces.length;
134  return this.interfaces;
135 }
136 sbDeviceFirmwareAutoCheckForUpdate.prototype.QueryInterface =
137  XPCOMUtils.generateQI(sbDeviceFirmwareAutoCheckForUpdate.prototype.interfaces);
138 
141 function sbDeviceFirmwareAutoCheckForUpdate_observe(subject, topic, data) {
142  DEBUG();
143 
144  var obs = Cc["@mozilla.org/observer-service;1"]
145  .getService(Ci.nsIObserverService);
146 
148  obs.removeObserver(this, SB_FINAL_UI_STARTUP_TOPIC);
149  obs.addObserver(this, NS_QUIT_APPLICATION_GRANTED_TOPIC, false);
150 
151  this._deviceFirmwareUpdater =
152  Cc['@songbirdnest.com/Songbird/Device/Firmware/Updater;1']
153  .getService(Ci.sbIDeviceFirmwareUpdater);
154 
155  this._deviceManager =
156  Cc['@songbirdnest.com/Songbird/DeviceManager;2']
157  .getService(Ci.sbIDeviceManager2);
158 
159  this._deviceManager.addEventListener(this);
160 
162  // cleanup
163  obs.removeObserver(this, NS_QUIT_APPLICATION_GRANTED_TOPIC);
164 
165  if(this._deviceManager) {
166  this._deviceManager.removeEventListener(this);
167  }
168 
169  if (this._timer) {
170  this._clearTimer();
171  }
172 
173  if (this._timerManager) {
174  for (let id in this._registeredDevices) {
175  this._unregisterTimer(id);
176  }
177  }
178 
179  if (this._queueItem && this._deviceFirmwareUpdater) {
180  this._deviceFirmwareUpdater.finalizeUpdate(this._queueItem);
181  }
182 
183  } else if (topic == NS_TIMER_CALLBACK_TOPIC) {
184  DEBUG(this._queue.length + " items, top is " + this._queueItem);
185  if(this._queue.length &&
186  !this._queueItem) {
187  // Queue has items in it and we're not currently processing an item.
188  // Grab first device in the queue.
189  let device = this._queue[0];
190  this._queueItem = device;
191  // Check for update
192  if (device.getPreference("firmware.update.enabled")) {
193  try {
194  this._deviceFirmwareUpdater.checkForUpdate(device, 0, 0, this);
195  }
196  catch (e) {
197  Cu.reportError(e);
198  }
199  }
200  }
201  else if(this._queueItem &&
202  this._queueItemSuccess) {
203  // If the device is busy, wait for the next timer callback.
204  if(this._queueItem.isBusy) {
205  return;
206  }
207 
208  this._deviceFirmwareUpdater.finalizeUpdate(this._queueItem);
209 
210  let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
211  .getService(Ci.nsIWindowMediator);
212  let parent = wm.getMostRecentWindow("Songbird:Main");
213 
214  WindowUtils.openModalDialog
215  (parent,
216  "chrome://songbird/content/xul/device/deviceFirmwareWizard.xul",
217  "device_firmware_dialog",
218  "",
219  ["", "defaultDevice=false", this._queueItem ],
220  null);
221 
222  this._queue.splice(0, 1);
223  this._queueItem = null;
224  this._queueItemSuccess = false;
225  }
226  else if(!this._queue.length &&
227  this._timer) {
228  // Queue is empty, clear timer.
229  this._timer.cancel();
230  this._timer = null;
231  }
232  }
233 }
234 
235 sbDeviceFirmwareAutoCheckForUpdate.prototype.notify =
236 function sbDeviceFirmwareAutoCheckForUpdate_notify(aDevice) {
237  DEBUG();
238  if (!this._timer) {
239  // set up the timer
240  this._timer = Cc['@mozilla.org/timer;1'].createInstance(Ci.nsITimer);
241  this._timer.init(this, 15000, Ci.nsITimer.TYPE_REPEATING_SLACK);
242  }
243  if (this._queue.indexOf(aDevice) < 0) {
244  this._queue.push(aDevice);
245  }
246 }
247 
249 sbDeviceFirmwareAutoCheckForUpdate.prototype.onDeviceEvent =
250 function sbDeviceFirmwareAutoCheckForUpdate_onDeviceEvent(aEvent) {
251  DEBUG();
252  var device = null;
253 
254  switch(aEvent.type) {
255  case Ci.sbIDeviceEvent.EVENT_DEVICE_ADDED: {
256  device = aEvent.data.QueryInterface(Ci.sbIDevice);
257  if (device.getPreference("firmware.update.enabled")) {
258  this._registerTimer(device);
259  }
260 
261  //
262  // If it's the first time the device is connected, check
263  // for a firmware update right away. We also set the
264  // auto check for firmware update pref to true. Since
265  // we only do this the first time the device is connected
266  // the user can choose not to do this and their preference
267  // will be respected. This is conditional on there being a
268  // firmware handler that can handle updating firmware for
269  // the device.
270  //
271  // Check to see if the device is in recoveryMode. If it is
272  // we do not enable automatic checks for firmware updates.
273  //
274  var hasHandler = this._deviceFirmwareUpdater.hasHandler(device, 0, 0);
275  var recoveryMode = false;
276  if (hasHandler) {
277  let handler = this._deviceFirmwareUpdater.getHandler(device, 0, 0);
278  handler.bind(device, null);
279  recoveryMode = handler.recoveryMode;
280  handler.unbind();
281  }
282 
283  if (device.getPreference("firstTime") &&
284  hasHandler &&
285  !recoveryMode &&
286  this._queue.indexOf(device) < 0) {
287  device.setPreference("firmware.update.enabled", true);
288  this._queue.push(device);
289  if (!this._timer) {
290  // set up the timer, when it's the first time, we wait 15 seconds in
291  // the hopes that the device will have finished mounting before
292  // we check for a firmware update.
293  this._timer = Cc['@mozilla.org/timer;1'].createInstance(Ci.nsITimer);
294  this._timer.init(this, 15000, Ci.nsITimer.TYPE_REPEATING_SLACK);
295  }
296  }
297 
298  // XXXAus says:
299  //
300  // Disabled this for now since we did not update the UE
301  // to consider the Tools menu entry for repairing devices.
302  //
303 
304  /*
305  // if we have a firmware handler for this device, we'll
306  // also check to see if it's recovery mode and ask the
307  // user if they wish to repair it if it is.
308  if (this._deviceFirmwareUpdater.hasHandler(device, 0, 0) &&
309  !SBDataGetBoolValue(FIRMWARE_WIZARD_ACTIVE_DATAREMOTE)) {
310  var handler = this._deviceFirmwareUpdater.getHandler(device, 0, 0);
311  handler.bind(device, null);
312 
313  var recoveryMode = handler.recoveryMode;
314  handler.unbind();
315 
316  // Also check to make sure we're not currently updating
317  // other firmware, if so, don't do anything for this device
318  if (recoveryMode) {
319  var self = this;
320  SBUtils.deferFunction(
321  function() {
322  self._promptForRepair(device);
323  });
324  }
325  }
326  */
327  }
328  break;
329 
330  case Ci.sbIDeviceEvent.EVENT_DEVICE_REMOVED: {
331  // Device removed, if in queue, remove it, also finalize any update attempt.
332  device = aEvent.data.QueryInterface(Ci.sbIDevice);
333  this._unregisterTimer(device);
334  let index = this._queue.indexOf(device);
335  if (index < 0) {
336  break;
337  }
338  this._queue.splice(index, 1);
339  if(this._queueItem == device) {
340  // currently attempting this item
341  this._deviceFirmwareUpdater.finalizeUpdate(this._queueItem);
342  this._queueItem = null;
343  this._queueItemSuccess = false;
344  }
345  }
346  break;
347 
348  case Ci.sbIDeviceEvent.EVENT_DEVICE_PREFS_CHANGED: {
349  device = aEvent.origin.QueryInterface(Ci.sbIDevice);
350  if (device.getPreference("firmware.update.enabled")) {
351  this._registerTimer(device);
352  } else {
353  this._unregisterTimer(device);
354  }
355  }
356  break;
357 
358  case Ci.sbIDeviceEvent.EVENT_FIRMWARE_CFU_END: {
359  this._queueItemSuccess = aEvent.data;
360  }
361  break;
362 
363  case Ci.sbIDeviceEvent.EVENT_FIRMWARE_CFU_ERROR: {
364  // Remove from queue
365  device = aEvent.origin.QueryInterface(Ci.sbIDevice);
366  let index = this._queue.indexOf(device);
367  if(index < 0) {
368  break;
369  }
370  this._queue.splice(index, 1);
371 
372  if(this._queueItem == device) {
373  this._deviceFirmwareUpdater.finalizeUpdate(this._queueItem);
374  this._queueItem = null;
375  this._queueItemSuccess = false;
376  }
377  }
378  break;
379  }
380 }
381 
385 sbDeviceFirmwareAutoCheckForUpdate.prototype._registerTimer =
386 function sbDeviceFirmwareAutoCheckForUpdate__registerTimer(aDevice) {
387  DEBUG();
388  if (!this._timerManager) {
389  this._timerManager = Cc['@mozilla.org/updates/timer-manager;1']
390  .getService(Ci.nsIUpdateTimerManager);
391  }
392  let self = this;
393  let callback = function(aTimer) {
394  self.notify(aDevice);
395  };
396  let interval = aDevice.getPreference("firmware.update.interval");
397  if (!interval) {
398  var prefs = Cc["@mozilla.org/fuel/application;1"]
399  .getService(Ci.fuelIApplication)
400  .prefs;
401  // Every 7 days in case there is no pref available.
402  interval = prefs.getValue(FIRMWARE_UPDATE_INTERVAL, 60 * 60 * 24 * 7);
403 
404  DEBUG("Using default interval for firmware update check: " +
405  interval);
406  }
407  this._timerManager.registerTimer(SB_TIMER_MANAGER_PREFIX + aDevice.id,
408  callback,
409  interval);
410  this._registeredDevices[aDevice.id] = true;
411 }
415 sbDeviceFirmwareAutoCheckForUpdate.prototype._unregisterTimer =
416 function sbDeviceFirmwareAutoCheckForUpdate__unregisterTimer(aDevice) {
417  DEBUG();
418  let id = aDevice;
419  if ("id" in aDevice) {
420  id = aDevice.id;
421  }
422  if (!this._registeredDevices[id]) {
423  // this device was never registerd. probably means update was disabled.
424  return;
425  }
426  delete this._registeredDevices[id];
427  // we can't actually unregister timers; instead, we can register it for
428  // a really long time (here, 136 years) and hope it doesn't get called
429  if (this._timerManager) {
430  this._timerManager.registerTimer(SB_TIMER_MANAGER_PREFIX + id,
431  null,
432  -1);
433  }
434 }
435 
436 sbDeviceFirmwareAutoCheckForUpdate.prototype._promptForRepair =
437 function sbDeviceFirmwareAutoCheckForUpdate__promptForRepair(aDevice) {
438  var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"]
439  .getService(Ci.nsIWindowMediator);
440  var songbirdWindow = windowMediator.getMostRecentWindow("Songbird:Main");
441 
442  var prompter = Cc['@songbirdnest.com/Songbird/Prompter;1']
443  .getService(Components.interfaces.sbIPrompter);
444  var confirmed =
445  prompter.confirm(songbirdWindow,
446  SBString('device.firmware.corrupt.title'),
447  SBFormattedString('device.firmware.corrupt.message',
448  [aDevice.name]));
449  if (confirmed) {
450  WindowUtils.openModalDialog
451  (songbirdWindow,
452  "chrome://songbird/content/xul/device/deviceFirmwareWizard.xul",
453  "device_firmware_dialog",
454  "",
455  [ "mode=repair", "defaultDevice=false", aDevice ],
456  null);
457  }
458 }
459 
460 var NSGetModule = XPCOMUtils.generateNSGetModule(
461  [
463  ],
464  function(aCompMgr, aFileSpec, aLocation) {
465  XPCOMUtils.categoryManager.addCategoryEntry(
466  "app-startup",
467  sbDeviceFirmwareAutoCheckForUpdate.prototype.classDescription,
468  "service," + sbDeviceFirmwareAutoCheckForUpdate.prototype.contractID,
469  true,
470  true);
471  }
472 );
function SBFormattedString(aKey, aParams, aDefault, aStringBundle)
menuItem id
Definition: FeedWriter.js:971
sbDeviceFirmwareAutoCheckForUpdate prototype _registeredDevices
sbDeviceFirmwareAutoCheckForUpdate prototype _deviceManager
const NS_QUIT_APPLICATION_GRANTED_TOPIC
function SBString(aKey, aDefault, aStringBundle)
Definition: StringUtils.jsm:93
sbDeviceFirmwareAutoCheckForUpdate prototype _timer
var count
Definition: test_bug7406.js:32
function DEBUG(msg)
function sbDeviceFirmwareAutoCheckForUpdate()
grep callback
sbDeviceFirmwareAutoCheckForUpdate prototype _queue
return null
Definition: FeedWriter.js:1143
const FIRMWARE_WIZARD_ACTIVE_DATAREMOTE
sbDeviceFirmwareAutoCheckForUpdate prototype _queueItemSuccess
var prefs
Definition: FeedWriter.js:1169
countRef value
Definition: FeedWriter.js:1423
sbDeviceFirmwareAutoCheckForUpdate prototype _timerManager
observe topic
Definition: FeedWriter.js:1326
function msg
sbDeviceFirmwareAutoCheckForUpdate prototype interfaces
observe data
Definition: FeedWriter.js:1329
_getSelectedPageStyle s i
sbDeviceFirmwareAutoCheckForUpdate prototype _deviceFirmwareUpdater
GstMessage gpointer data sbGStreamerMessageHandler * handler
sbDeviceFirmwareAutoCheckForUpdate prototype _queueItem