sbIPDEventHandler.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 //=BEGIN SONGBIRD GPL
5 //
6 // This file is part of the Songbird web player.
7 //
8 // Copyright(c) 2005-2009 POTI, Inc.
9 // http://www.songbirdnest.com
10 //
11 // This file may be licensed under the terms of of the
12 // GNU General Public License Version 2 (the GPL).
13 //
14 // Software distributed under the License is distributed
15 // on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either
16 // express or implied. See the GPL for the specific language
17 // governing rights and limitations.
18 //
19 // You should have received a copy of the GPL along with this
20 // program. If not, go to http://www.gnu.org/licenses/gpl.html
21 // or write to the Free Software Foundation, Inc.,
22 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 //
24 //=END SONGBIRD GPL
25 */
26 
32 //------------------------------------------------------------------------------
33 //------------------------------------------------------------------------------
34 //
35 // iPod device event handler component.
36 //
37 // This component listens for and handle iPod device specific events. Event
38 // handling includes presenting the user with dialogs.
39 // This component must be instantiated as a service once the device manager is
40 // ready. This may be done from the iPod device object initialization.
41 //
42 //------------------------------------------------------------------------------
43 //------------------------------------------------------------------------------
44 
45 //------------------------------------------------------------------------------
46 //
47 // iPod device event handler imported services.
48 //
49 //------------------------------------------------------------------------------
50 
51 Components.utils.import("resource://app/jsmodules/ArrayConverter.jsm");
52 Components.utils.import("resource://app/jsmodules/StringUtils.jsm");
53 Components.utils.import("resource://app/jsmodules/WindowUtils.jsm");
54 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
55 
56 
57 //------------------------------------------------------------------------------
58 //
59 // iPod device event handler defs.
60 //
61 //------------------------------------------------------------------------------
62 
63 if (typeof(Cc) == "undefined")
64  var Cc = Components.classes;
65 if (typeof(Ci) == "undefined")
66  var Ci = Components.interfaces;
67 if (typeof(Cr) == "undefined")
68  var Cr = Components.results;
69 
70 
71 //------------------------------------------------------------------------------
72 //
73 // iPod device event handler configuration.
74 //
75 //------------------------------------------------------------------------------
76 
77 //
78 // className Name of component class.
79 // cid Component CID.
80 // contractID Component contract ID.
81 // ifList List of external component interfaces.
82 // categoryList List of component categories.
83 //
84 // localeBundlePath Path to locale string bundle.
85 //
86 
88  className: "Songbird iPod Device Event Handler Service",
89  cid: Components.ID("{adb505cb-75d9-4526-84df-5b69d6c571e9}"),
90  contractID: "@songbirdnest.com/Songbird/IPDEventHandler;1",
91  ifList: [ Ci.nsIObserver, Ci.sbIDeviceEventListener ],
92  categoryList: [],
93 
94  localeBundlePath: "chrome://ipod/locale/IPodDevice.properties"
95 };
96 
97 
98 //------------------------------------------------------------------------------
99 //
100 // iPod device event handler services.
101 //
102 // These services handle iPod device specific events.
103 // Processing of some events require the opening of dialog windows. While a
104 // dialog window is open, device events may still be sent, causing these
105 // services to be re-entered. In order to ensure processing of events in the
106 // proper order, an event queue is used internally.
107 //
108 //------------------------------------------------------------------------------
109 
115 {
116  // Initialize the services.
117  this._initialize();
118 }
119 
120 /* Set the constructor. */
121 sbIPDEventHandler.prototype.constructor = sbIPDEventHandler;
122 
123 sbIPDEventHandler.prototype = {
124  //
125  // iPod device event handler services fields.
126  //
127  // classDescription Description of component class.
128  // classID Component class ID.
129  // contractID Component contract ID.
130  // _xpcom_categories List of component categories.
131  //
132  // _cfg Configuration settings.
133  // _locale Locale string bundle.
134  // _observerSvc Observer service object.
135  // _devMgr Device manager object.
136  // _devInfoList List of device information.
137  // _eventQueue Queue of received device events.
138  // _eventQueueBusy True if busy processing device event queue.
139  //
140 
141  classDescription: sbIPDEventHandlerCfg.className,
142  classID: sbIPDEventHandlerCfg.cid,
143  contractID: sbIPDEventHandlerCfg.contractID,
144  _xpcom_categories: sbIPDEventHandlerCfg.categoryList,
145 
146  _cfg: sbIPDEventHandlerCfg,
147  _locale: null,
148  _observerSvc: null,
149  _devMgr: null,
150  _devInfoList: null,
151  _eventQueue: [],
152  _eventQueueBusy: false,
153 
154 
155  //----------------------------------------------------------------------------
156  //
157  // iPod device event handler sbIDeviceEventListener services.
158  //
159  //----------------------------------------------------------------------------
160 
165  onDeviceEvent: function sbIPDEventHandler_onDeviceEvent(aEvent) {
166  try { this._onDeviceEvent(aEvent); }
167  catch (ex) { dump("onDeviceEvent exception: " + ex +
168  " at " + ex.fileName +
169  ", line " + ex.lineNumber + "\n"); }
170  },
171 
172  _onDeviceEvent: function sbIPDEventHandler__onDeviceEvent(aEvent) {
173  // Enqueue the device event and process the event queue.
174  this._eventQueue.push(aEvent);
175  this._processEventQueue();
176  },
177 
178 
179  //----------------------------------------------------------------------------
180  //
181  // iPod device event handler nsIObserver services.
182  //
183  //----------------------------------------------------------------------------
184 
193  observe: function sbIPDEventHandler_observe(aSubject, aTopic, aData) {
194  try { this._observe(aSubject, aTopic, aData); }
195  catch (ex) { dump("observe exception: " + ex + "\n"); }
196  },
197 
198  _observe: function sbIPDEventHandler__observe(aSubject, aTopic, aData) {
199  // Dispatch processing of the event.
200  switch (aTopic) {
201  case "quit-application" :
202  this._handleAppQuit();
203  break;
204 
205  default :
206  break;
207  }
208  },
209 
210 
211  //----------------------------------------------------------------------------
212  //
213  // iPod device event handler nsISupports services.
214  //
215  //----------------------------------------------------------------------------
216 
217  QueryInterface: XPCOMUtils.generateQI(sbIPDEventHandlerCfg.ifList),
218 
219 
220  //----------------------------------------------------------------------------
221  //
222  // iPod device event handler event services.
223  //
224  //----------------------------------------------------------------------------
225 
230  _handleAppQuit: function sbIPDEventHandler__handleAppQuit() {
231  // Finalize the services.
232  this._finalize();
233  },
234 
235 
240  _processEventQueue: function sbIPDEventHandler__processEventQueue() {
241  // Do nothing if already busy processing event queue.
242  if (this._eventQueueBusy)
243  return;
244 
245  // Process events in the queue.
246  this._eventQueueBusy = true;
247  while (this._eventQueue.length > 0) {
248  var event = this._eventQueue.shift();
249  this._handleEvent(event);
250  }
251  this._eventQueueBusy = false;
252  },
253 
254 
261  _handleEvent: function sbIPDEventHandler__handleEvent(aEvent) {
262  // Dispatch processing of the event.
263  switch(aEvent.type) {
264  case Ci.sbIDeviceEvent.EVENT_DEVICE_ADDED :
265  this._addDevice(aEvent.data.QueryInterface(Ci.sbIDevice));
266  break;
267 
268  case Ci.sbIDeviceEvent.EVENT_DEVICE_REMOVED :
269  this._removeDevice(aEvent.data.QueryInterface(Ci.sbIDevice));
270  break;
271 
272  case Ci.sbIIPDDeviceEvent.EVENT_IPOD_FAIRPLAY_NOT_AUTHORIZED :
273  this._handleFairPlayNotAuthorized(aEvent);
274  break;
275 
276  case Ci.sbIIPDDeviceEvent.EVENT_IPOD_NOT_INITIALIZED:
277  this._handleIPodNotInitialized(aEvent);
278  break;
279 
280  case Ci.sbIIPDDeviceEvent.EVENT_IPOD_UNSUPPORTED_FILE_SYSTEM:
281  this._handleIPodUnsupportedFileSystem(aEvent);
282  break;
283 
284  case Ci.sbIIPDDeviceEvent.EVENT_IPOD_HFSPLUS_READ_ONLY:
285  this._handleIPodHFSPlusReadOnly(aEvent);
286  break;
287 
288  case Ci.sbIDeviceEvent.EVENT_DEVICE_MOUNTING_END :
289  case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_WRITE_END :
290  this._processEventInfo(aEvent.origin.QueryInterface(Ci.sbIDevice));
291  break;
292 
293  default :
294  break;
295  }
296  },
297 
298 
305  _handleFairPlayNotAuthorized:
306  function sbIPDEventHandler__handleFairPlayNotAuthorized(aEvent) {
307  // Get the event info.
308  var device = aEvent.origin.QueryInterface(Ci.sbIDevice);
309  var fairPlayEvent = aEvent.QueryInterface(Ci.sbIIPDFairPlayEvent);
310 
311  // Get the device info. Do nothing more if no device info.
312  var devInfo = this._devInfoList[device.id];
313  if (!devInfo)
314  return;
315  if (!devInfo.fairPlayNotAuthorizedInfoList)
316  devInfo.fairPlayNotAuthorizedInfoList = [];
317  fairPlayNotAuthorizedInfoList = devInfo.fairPlayNotAuthorizedInfoList;
318 
319  // Accumulate the event information for later processing.
320  var fairPlayNotAuthorizedInfo =
321  {
322  userID: fairPlayEvent.userID,
323  accountName: fairPlayEvent.accountName,
324  userName: fairPlayEvent.userName,
325  mediaItem: fairPlayEvent.mediaItem
326  };
327  fairPlayNotAuthorizedInfoList.push(fairPlayNotAuthorizedInfo);
328  },
329 
330 
337  _handleIPodNotInitialized:
338  function sbIPDEventHandler__handleIPodNotInitialized(aEvent) {
339  function promptForDeviceName(aWindow) {
340  var stringBundle = Cc["@mozilla.org/intl/stringbundle;1"]
341  .getService(Ci.nsIStringBundleService)
342  .createBundle('chrome://ipod/locale/IPodDevice.properties');
343 
344  var deviceName = { value:
345  stringBundle.GetStringFromName('initialize.default_device_name') };
346 
347  var promptService = Cc["@songbirdnest.com/Songbird/Prompter;1"]
348  .getService(Ci.nsIPromptService);
349  var accept = promptService.prompt(aWindow,
350  stringBundle.GetStringFromName('initialize.title'),
351  stringBundle.GetStringFromName('initialize.prompt'),
352  deviceName, null, {});
353  if (accept) {
354  aEvent.data.QueryInterface(Ci.sbIDevice).properties.friendlyName
355  = deviceName.value;
356  }
357  }
358  var sbWindowWatcher = Cc["@songbirdnest.com/Songbird/window-watcher;1"]
359  .getService(Ci.sbIWindowWatcher);
360  sbWindowWatcher.callWithWindow("Songbird:Main", promptForDeviceName, false);
361  },
362 
363 
370  _handleIPodUnsupportedFileSystem:
371  function sbIPDEventHandler__handleIPodUnsupportedFileSystem(aEvent) {
372  // Set up the dialog parameters.
373  var title = SBString("ipod.dialog.unsupported_file_system.title",
374  null,
375  this._locale);
376  var msg = SBString("ipod.dialog.unsupported_file_system.msg",
377  null,
378  this._locale);
379 
380  // Present the user with a dialog using the main Songbird window as the
381  // parent.
382  var dialogFunc = function(aWindow) {
383  var prompter = Cc["@songbirdnest.com/Songbird/Prompter;1"]
384  .getService(Ci.nsIPromptService);
385  prompter.alert(aWindow, title, msg);
386  };
387  var sbWindowWatcher = Cc["@songbirdnest.com/Songbird/window-watcher;1"]
388  .getService(Ci.sbIWindowWatcher);
389  sbWindowWatcher.callWithWindow("Songbird:Main", dialogFunc, false);
390  },
391 
392 
399  _handleIPodHFSPlusReadOnly:
400  function sbIPDEventHandler__handleIPodUnsupportedFileSystem(aEvent) {
401  // Set up the dialog parameters.
402  var title = SBString("ipod.dialog.hfsplus_read_only.title",
403  null,
404  this._locale);
405  var msg = SBString("ipod.dialog.hfsplus_read_only.msg",
406  null,
407  this._locale);
408 
409  // Present the user with a dialog using the main Songbird window as the
410  // parent.
411  var dialogFunc = function(aWindow) {
412  var prompter = Cc["@songbirdnest.com/Songbird/Prompter;1"]
413  .getService(Ci.nsIPromptService);
414  prompter.alert(aWindow, title, msg);
415  };
416  var sbWindowWatcher = Cc["@songbirdnest.com/Songbird/window-watcher;1"]
417  .getService(Ci.sbIWindowWatcher);
418  sbWindowWatcher.callWithWindow("Songbird:Main", dialogFunc, false);
419  },
420 
421 
429  _processEventInfo: function sbIPDEventHandler__processEventInfo(aDevice) {
430  // Process accumulated event info.
431  this._processFairPlayNotAuthorizedEventInfo(aDevice);
432  },
433 
434 
442  _processFairPlayNotAuthorizedEventInfo:
443  function sbIPDEventHandler__processFairPlayNotAuthorizedEventInfo(aDevice) {
444  // Get the device info. Do nothing more if no device info.
445  var devInfo = this._devInfoList[aDevice.id];
446  if (!devInfo)
447  return;
448 
449  // Get the FairPlay not authorized event info. Do nothing more if not
450  // present.
451  fairPlayNotAuthorizedInfoList = devInfo.fairPlayNotAuthorizedInfoList;
452  if (!fairPlayNotAuthorizedInfoList)
453  return;
454 
455  // Collect the FairPlay not authorized event track info.
456  var trackInfoList = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
457  .createInstance(Ci.nsIMutableArray);
458  for (var i = 0; i < fairPlayNotAuthorizedInfoList.length; i++) {
459  // Get the FairPlay not authorized info.
460  var fairPlayNotAuthorizedInfo = fairPlayNotAuthorizedInfoList[i];
461  var trackContentURL = fairPlayNotAuthorizedInfo
462  .mediaItem.contentSrc.QueryInterface(Ci.nsIURL);
463 
464  // Produce the track info string.
465  var trackInfo = Cc["@mozilla.org/supports-string;1"]
466  .createInstance(Ci.nsISupportsString);
467  trackInfo.data = fairPlayNotAuthorizedInfo.accountName;
468  trackInfo.data += ": " + decodeURIComponent(trackContentURL.fileName);
469 
470  // Add the track info to the track info list.
471  trackInfoList.appendElement(trackInfo, false);
472  }
473 
474  // Clear the FairPlay not authorized event info.
475  devInfo.fairPlayNotAuthorizedInfoList = null;
476 
477  // Set up the dialog parameters.
478  var title = SBString("ipod.dialog.fair_play_not_authorized_transfer.title",
479  null,
480  this._locale);
481  var errorMsg =
482  SBFormattedString("ipod.dialog.fair_play_not_authorized_transfer.msg",
483  [ aDevice.properties.friendlyName ],
484  null,
485  this._locale);
486  var listLabel =
488  ("ipod.dialog.fair_play_not_authorized_transfer.list_label",
489  fairPlayNotAuthorizedInfoList.length,
490  null,
491  null,
492  this._locale);
493 
494  // Present the user with a dialog using the main Songbird window as the
495  // parent.
496  var dialogFunc = function(aWindow) {
497  WindowUtils.openModalDialog
498  (aWindow,
499  "chrome://songbird/content/xul/device/deviceErrorDialog.xul",
500  "device_error_dialog",
501  "",
502  [ "windowTitle=" + title +
503  ",listLabel=" + listLabel +
504  ",errorMsg=" + errorMsg,
505  aDevice,
506  trackInfoList ],
507  null,
508  null);
509  };
510  var sbWindowWatcher = Cc["@songbirdnest.com/Songbird/window-watcher;1"]
511  .getService(Ci.sbIWindowWatcher);
512  sbWindowWatcher.callWithWindow("Songbird:Main", dialogFunc, false);
513  },
514 
515 
516  //----------------------------------------------------------------------------
517  //
518  // iPod device event handler services.
519  //
520  //----------------------------------------------------------------------------
521 
526  _initialize: function sbIPDEventHandler__initialize() {
527  // Initialize the device info list.
528  this._devInfoList = {};
529 
530  // Get the locale string bundle.
531  var stringBundleSvc = Cc["@mozilla.org/intl/stringbundle;1"]
532  .getService(Ci.nsIStringBundleService);
533  this._locale = stringBundleSvc.createBundle(this._cfg.localeBundlePath);
534 
535  // Set up observers.
536  this._observerSvc = Cc["@mozilla.org/observer-service;1"]
537  .getService(Ci.nsIObserverService);
538  this._observerSvc.addObserver(this, "quit-application", false);
539 
540  // Get the device manager.
541  this._devMgr = Cc["@songbirdnest.com/Songbird/DeviceManager;2"]
542  .getService(Ci.sbIDeviceManager2);
543 
544  // Add device event listener.
545  this._devMgr.addEventListener(this);
546 
547  // Add all connected devices.
548  this._addAllConnectedDevices();
549  },
550 
551 
556  _finalize: function sbIPDEventHandler__finalize() {
557  // Remove observers.
558  try {
559  this._observerSvc.removeObserver(this, "quit-application");
560  } catch(ex) {}
561 
562  // Remove device event listener.
563  this._devMgr.removeEventListener(this);
564 
565  // Remove all devices.
566  this._removeAllDevices();
567 
568  // Clear the device info list.
569  this._devInfoList = null;
570 
571  // Clear object references.
572  this._observerSvc = null;
573  this._devMgr = null;
574  },
575 
576 
583  _addDevice: function sbIPDEventHandler__addDevice(aDevice) {
584  // Do nothing if device has already been added.
585  var deviceID = aDevice.id;
586  if (this._devInfoList[deviceID])
587  return;
588 
589  // Do nothing if device is not an iPod.
590  if (aDevice.parameters.getProperty("DeviceType") != "iPod")
591  return;
592 
593  // Do nothing if device is not connected.
594  if (!aDevice.connected)
595  return;
596 
597  // Create a device info list entry.
598  this._devInfoList[deviceID] = { device: aDevice };
599  },
600 
601 
608  _removeDevice: function sbIPDEventHandler__removeDevice(aDevice) {
609  // Get the device info. Do nothing if no device info available.
610  var deviceID = aDevice.id;
611  var devInfo = this._devInfoList[deviceID];
612  if (!devInfo)
613  return;
614 
615  // Remove device info list entry.
616  delete this._devInfoList[deviceID];
617  },
618 
619 
624  _addAllConnectedDevices: function
625  sbIPDEventHandler__addAllConnectedDevices() {
626  var deviceList = ArrayConverter.JSArray(this._devMgr.devices);
627  for each (device in deviceList) {
628  this._addDevice(device.QueryInterface(Ci.sbIDevice));
629  }
630  },
631 
632 
637  _removeAllDevices: function sbIPDEventHandler__removeAllDevices() {
638  // Remove all devices.
639  for (var deviceID in this._devInfoList)
640  this._removeDevice(this._devInfoList[deviceID].device);
641  }
642 };
643 
644 
645 //------------------------------------------------------------------------------
646 //
647 // iPod device event handler component services.
648 //
649 //------------------------------------------------------------------------------
650 
651 function NSGetModule(compMgr, fileSpec) {
652  return XPCOMUtils.generateModule([sbIPDEventHandler]);
653 }
654 
const Cc
sbLibraryImporterManagerCfg categoryList
function _handleEvent(aEvent)
function SBFormattedString(aKey, aParams, aDefault, aStringBundle)
sbOSDControlService prototype className
sbDeviceFirmwareAutoCheckForUpdate prototype contractID
var event
sbOSDControlService prototype QueryInterface
sbDeviceFirmwareAutoCheckForUpdate prototype classDescription
function SBString(aKey, aDefault, aStringBundle)
Definition: StringUtils.jsm:93
function SBFormattedCountString(aKeyBase, aCount, aParams, aDefault, aStringBundle)
void callWithWindow(in AString aWindowType, in sbICallWithWindowCallback aCallback, [optional] in boolean aWait)
Call callback specified by aCallback with a window of the type specified by aWindowType. Wait until a window of the specified type is available or until shutdown. Call callback with null window on shutdown. Call callback on main thread. If aWait is true, don't return until callback is called.
return null
Definition: FeedWriter.js:1143
countRef value
Definition: FeedWriter.js:1423
const Cr
let promptService
const Ci
sbDeviceFirmwareAutoCheckForUpdate prototype classID
sbWindowsAutoPlayServiceCfg _xpcom_categories
function msg
function sbIPDEventHandler()
_getSelectedPageStyle s i
function NSGetModule(compMgr, fileSpec)
_updateTextAndScrollDataForFrame aData
sbDeviceFirmwareAutoCheckForUpdate prototype observe
var sbIPDEventHandlerCfg