home *** CD-ROM | disk | FTP | other *** search
/ Freelog 112 / FreelogNo112-NovembreDecembre2012.iso / Multimedia / Songbird / Songbird_2.0.0-2311_windows-i686-msvc8.exe / components / sbDeviceErrorMonitor.js < prev    next >
Text File  |  2012-06-08  |  28KB  |  803 lines

  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-2010 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.  
  27. /**
  28.  * \file sbDeviceErrorMonitor.js
  29.  * \brief This service monitors devices for errors and stores them for easy
  30.  *        access later.
  31.  *
  32.  */
  33. if (typeof(Cc) == "undefined")
  34.   var Cc = Components.classes;
  35. if (typeof(Ci) == "undefined")
  36.   var Ci = Components.interfaces;
  37. if (typeof(Cu) == "undefined")
  38.   var Cu = Components.utils;
  39.  
  40. Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  41. Cu.import("resource://app/jsmodules/sbProperties.jsm");
  42. Cu.import("resource://app/jsmodules/StringUtils.jsm");
  43.  
  44. /**
  45.  * Since we can't use the FUEL components until after all other components have
  46.  * been loaded we define a lazy getter here for when we need it.
  47.  */
  48. __defineGetter__("Application", function() {
  49.   delete this.Application;
  50.   return this.Application = Cc["@mozilla.org/fuel/application;1"]
  51.                               .getService(Ci.fuelIApplication);
  52. });
  53.  
  54. var deviceErrorMonitorConfig = {
  55.   className:      "Songbird Device Error Monitor Service",
  56.   cid:            Components.ID("{7a2a55d1-0270-4789-bc7c-12ffaa19b4cd}"),
  57.   contractID:     "@songbirdnest.com/device/error-monitor-service;1",
  58.  
  59.   ifList: [ Ci.sbIDeviceEventListener,
  60.             Ci.sbIDeviceErrorMonitor,
  61.             Ci.nsIObserver ],
  62.  
  63.   categoryList:
  64.   [
  65.     {
  66.       category: 'app-startup',
  67.       entry: 'service-device-error-monitor',
  68.       value: 'service,@songbirdnest.com/device/error-monitor-service;1'
  69.     }
  70.   ],
  71.  
  72.   debugPref: "songbird.device.errorMonitor.debug"
  73. };
  74.  
  75. function deviceErrorMonitor () {
  76.   this._initialized = false;
  77.   var obsSvc = Cc['@mozilla.org/observer-service;1']
  78.                  .getService(Ci.nsIObserverService);
  79.  
  80.   // We want to wait until profile-after-change to initialize
  81.   obsSvc.addObserver(this, 'profile-after-change', false);
  82.   obsSvc.addObserver(this, 'quit-application', false);
  83. }
  84.  
  85. deviceErrorMonitor.prototype = {
  86.   // XPCOM stuff
  87.   classDescription: deviceErrorMonitorConfig.className,
  88.   classID: deviceErrorMonitorConfig.cid,
  89.   contractID: deviceErrorMonitorConfig.contractID,
  90.   _xpcom_categories: deviceErrorMonitorConfig.categoryList,
  91.  
  92.   // Internal properties
  93.   _deviceList: [],
  94.   _listenerList: [],
  95.   _sbStrings: null,
  96.   NONE : "none",
  97.   _debug: false,
  98.   _direction: Ci.sbIDeviceStatus.EXPORT,
  99.  
  100.   // Internal Services
  101.   _consoleService: null,
  102.  
  103.   // Internal functions
  104.  
  105.   /**
  106.    * \brief Initialize the deviceErrorMonitor service.
  107.    */
  108.   _init: function deviceErrorMonitor__init() {
  109.     var deviceManagerSvc = Cc["@songbirdnest.com/Songbird/DeviceManager;2"]
  110.                              .getService(Ci.sbIDeviceManager2);
  111.     deviceManagerSvc.addEventListener(this);
  112.     var sbs = Cc["@mozilla.org/intl/stringbundle;1"]
  113.                 .getService(Ci.nsIStringBundleService);
  114.     this._sbStrings = sbs.createBundle("chrome://songbird/locale/songbird.properties");
  115.  
  116.     this._debug = Application.prefs.getValue(deviceErrorMonitorConfig.debugPref,
  117.                                             false);
  118.     if (this._debug) {
  119.       this._consoleService = Cc["@mozilla.org/consoleservice;1"]
  120.                               .getService(Ci.nsIConsoleService);
  121.     }
  122.   },
  123.  
  124.   /**
  125.    * \brief Shutdown (cleanup) the deviceErrorMonitorService.
  126.    */
  127.   _shutdown: function deviceErrorMonitor__shutdown() {
  128.     var deviceManagerSvc = Cc["@songbirdnest.com/Songbird/DeviceManager;2"]
  129.                              .getService(Ci.sbIDeviceManager2);
  130.     deviceManagerSvc.removeEventListener(this);
  131.     while(this._deviceList.length > 0) {
  132.       if (this._deviceList[0].device) {
  133.         this._removeDevice(this._deviceList[0].device);
  134.       }
  135.     }
  136.  
  137.     this._consoleService = null;
  138.   },
  139.  
  140.   /**
  141.    * \brief Adds a device that has just connected to the list of available
  142.    *        devices to monitor for errors.
  143.    *
  144.    * \param aDevice Device to add to the list.
  145.    */
  146.   _addDevice: function deviceErrorMonitor__addDevice(aDevice) {
  147.     var devIndex = this._findDeviceIndex(aDevice);
  148.     if (devIndex == -1) {
  149.  
  150.       var newDeviceObj = {};
  151.       newDeviceObj.device = aDevice;
  152.       newDeviceObj.errorLists = { };
  153.       this._deviceList.push(newDeviceObj);
  154.     }
  155.   },
  156.  
  157.   /**
  158.    * \brief Remove a device from the list of available devices to monitor for
  159.    *        errors.
  160.    *
  161.    * \params aDevice Device to remove from the list.
  162.    */
  163.   _removeDevice: function deviceErrorMonitor__removeDevice(aDevice) {
  164.     var devIndex = this._findDeviceIndex(aDevice);
  165.     if (devIndex > -1) {
  166.       this._deviceList.splice(devIndex, 1);
  167.     }
  168.   },
  169.  
  170.   /**
  171.    * \brief Finds a device index in the device list.
  172.    *
  173.    * \param aDevice Device to locate in the list.
  174.    * \returns index in _deviceList aDevice is located
  175.    */
  176.   _findDeviceIndex: function deviceErrorMonitor__findDeviceIndex(aDevice) {
  177.     for (var i = 0; i < this._deviceList.length; ++i) {
  178.       if (this._deviceList[i].device.id.equals(aDevice.id)) {
  179.         return i;
  180.       }
  181.     }
  182.     return -1;
  183.   },
  184.  
  185.   /**
  186.    * \brief Returns the media type given an event.
  187.    *
  188.    * \param aDeviceEvent the device event to inspect
  189.    * \return The content type of the item in the device event or "none" if
  190.    *         the event isn't device related
  191.    */
  192.   _getContentType : function deviceErrorMonitor__getContentType(aDeviceEvent) {
  193.     if (aDeviceEvent.data instanceof Ci.sbIMediaItem) {
  194.       return aDeviceEvent.data.contentType;
  195.     }
  196.     return this.NONE;
  197.   },
  198.  
  199.   /**
  200.    * \brief Returns a list of all the errors on a device.
  201.    *
  202.    * \param aDevIndex the device index in our array to get errors for.
  203.    * \return array of errors for a device.
  204.    */
  205.   _getAllErrors : function deviceErrorMonitor__getAllErrors(aDevIndex) {
  206.     var device = this._deviceList[aDevIndex];
  207.     var errorList = [];
  208.     if (!device)
  209.       return errorList;
  210.  
  211.     // Concat all the error contentType arrays together.
  212.     for (var contentType in device.errorLists) {
  213.       errorList = errorList.concat(device.errorLists[contentType]);
  214.     }
  215.     return errorList;
  216.   },
  217.  
  218.   /**
  219.    * \brief Returns a list of errors for a content type on a device.
  220.    *
  221.    * \param aDevIndex the device index in our array to get errors for.
  222.    * \param aContentType  the type of content we want errors for.
  223.    * \param aDirection sbIDeviceStatus.[EXPORT|IMPORT]
  224.    * \return array of errors for a device of a particular media type.
  225.    */
  226.   _getErrorList : function deviceErrorMonitor__getErrorList(aDevIndex,
  227.                                                             aContentType,
  228.                                                             aDirection) {
  229.     let device = this._deviceList[aDevIndex];
  230.     let errorList = device.errorLists[aDirection + aContentType];
  231.     if (!errorList) {
  232.       errorList = [];
  233.       device.errorLists[aDirection + aContentType] = errorList;
  234.     }
  235.     return errorList;
  236.    },
  237.  
  238.   /**
  239.    * \brief Save an error in the list of errors for a device.
  240.    *
  241.    * \param aDeviceEvent Event from the device.
  242.    * \param aErrorMsg Error Message to display with the item.
  243.    */
  244.   _logError: function deviceErrorMonitor__logError(aDeviceEvent, aErrorMsg) {
  245.     var device = aDeviceEvent.origin;
  246.     var mediaItem;
  247.     if (device instanceof Ci.sbIDevice) {
  248.       var devIndex = this._findDeviceIndex(device);
  249.       if (devIndex > -1) {
  250.         var mediaURL = "";
  251.         if (aDeviceEvent.data) {
  252.           if (aDeviceEvent.data instanceof Ci.sbIMediaList) {
  253.             mediaURL = aDeviceEvent.data.name;
  254.             mediaItem = aDeviceEvent.data;
  255.           } else if (aDeviceEvent.data instanceof Ci.sbIMediaItem) {
  256.             mediaURL = aDeviceEvent.data.contentSrc.spec;
  257.             mediaURL = decodeURIComponent(mediaURL);
  258.             mediaItem = aDeviceEvent.data;
  259.           } else if (aDeviceEvent.data instanceof Ci.nsIPropertyBag2) {
  260.             var bag = aDeviceEvent.data;
  261.             if (bag.hasKey("item")) {
  262.               mediaItem = bag.getPropertyAsInterface("item", Ci.sbIMediaItem);
  263.               mediaURL = mediaItem.contentSrc.spec;
  264.               mediaURL = decodeURIComponent(mediaURL);
  265.             }
  266.           } else if (aDeviceEvent.data instanceof Ci.nsIFile) {
  267.             var ios = Components.classes["@mozilla.org/network/io-service;1"]
  268.                                 .getService(Components.interfaces.nsIIOService);
  269.             var fileHandler = ios.getProtocolHandler("file")
  270.                                  .QueryInterface(Components.interfaces
  271.                                     .nsIFileProtocolHandler);
  272.             mediaURL = fileHandler.getURLSpecFromFile(aDeviceEvent.data);
  273.           }
  274.         } else {
  275.           mediaURL = SBString("device.info.unknown");
  276.         }
  277.  
  278.         // Format the error message
  279.         var errorString = aErrorMsg;
  280.         if (mediaURL) {
  281.           errorString = this._sbStrings.formatStringFromName(
  282.                                                         "device.error.format",
  283.                                                         [aErrorMsg, mediaURL],
  284.                                                         2);
  285.         }
  286.         // Store the error information
  287.         var errorInfo = {
  288.           msg : errorString,
  289.           item : mediaItem,
  290.           state : aDeviceEvent.deviceState
  291.         };
  292.         // Get the contentType and add the error information to the list.
  293.         var contentType = this._getContentType(aDeviceEvent);
  294.         // Get the error list, if one doesn't exists create it
  295.         var errorList = this._getErrorList(devIndex, 
  296.                                            contentType, 
  297.                                            this._direction);
  298.  
  299.         // Ignore error if an error has already been logged for item
  300.         if (errorInfo.item) {
  301.           for (var i = 0; i < errorList.length; i++) {
  302.             var item = errorList[i].item;
  303.             if (item && item.equals(errorInfo.item))
  304.               return;
  305.           }
  306.         }
  307.  
  308.         errorList.push(errorInfo);
  309.  
  310.         this._notifyListeners(device);
  311.       }
  312.     }
  313.   },
  314.  
  315.   /**
  316.    * \brief Notify listeners that an error has been logged for the device
  317.    *        specified by aDevice.
  318.    *
  319.    * \param aDevice device for which error was logged.
  320.    */
  321.   _notifyListeners: function deviceErrorMonitor__notifyListeners(aDevice) {
  322.     // Call listeners in reverse order so they may remove themselves.
  323.     for (var i = this._listenerList.length - 1; i >= 0; i--) {
  324.       try {
  325.         this._listenerList[i].onDeviceError(aDevice);
  326.       } catch (ex) {
  327.         Cu.reportError(ex);
  328.         // Remove the listener since it probably does not exist anymore
  329.         this._listenerList.splice(i, 1);
  330.       }
  331.     }
  332.   },
  333.  
  334.   // sbIDeviceErrorMonitor
  335.  
  336.   /**
  337.    * \brief Checks to see if a device has had any recent errors.
  338.    *
  339.    * \param aDevice device to check for errors on.
  340.    * \param aContentType type of content we want to check for errors on.
  341.    * \param aDirection sbIDeviceStatus.[EXPORT|IMPORT]
  342.    * \returns true if any errors are currently registered for this device.
  343.    */
  344.   deviceHasErrors: function deviceErrorMonitor_deviceHasErrors(aDevice,
  345.                                                                aContentType,
  346.                                                                aDirection) {
  347.     var devIndex = this._findDeviceIndex(aDevice);
  348.     if (devIndex > -1) {
  349.       var device = this._deviceList[devIndex];
  350.       var errorList;
  351.       if (!aContentType && !aDirection)
  352.         errorList = this._getAllErrors(devIndex);
  353.       else if (aContentType) {
  354.         errorList = this._getErrorList(devIndex, aContentType, aDirection);
  355.       }
  356.       else {
  357.         throw Components.results.NS_ERROR_INVALID_ARG;
  358.       }
  359.       return (errorList ? (errorList.length > 0) : false);
  360.     }
  361.     return false;
  362.   },
  363.  
  364.   /**
  365.    * \brief Gets an array of property bags containing information about the
  366.    *        errors.
  367.    *
  368.    * \param aDevice The device to get the list of errors for.
  369.    * \param aContentType type of content we want errosr for.
  370.    * \param aDirection sbIDeviceStatus.[EXPORT|IMPORT]
  371.    * \returns array of property bags that contain error information
  372.    *
  373.    * The property bag currently contains
  374.    *  msg   - nsISupportsString of the message that occured.
  375.    *  item  - sbIMediaItem that the error occured with.
  376.    *  state - State of the device at the point of the error.
  377.    */
  378.   getDeviceErrors: function deviceErrorMonitor_getDeviceErrors(aDevice,
  379.                                                                aContentType,
  380.                                                                aDirection) {
  381.     var devIndex = this._findDeviceIndex(aDevice);
  382.     var errorList = Cc["@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
  383.                       .createInstance(Ci.nsIMutableArray);
  384.  
  385.     if (devIndex == -1)
  386.       return errorList;
  387.  
  388.     var jsErrorList;
  389.     if (!aContentType && !aDirection)
  390.       jsErrorList = this._getAllErrors(devIndex);
  391.     else if (aContentType && aDirection) {
  392.       jsErrorList = this._getErrorList(devIndex, aContentType, aDirection);
  393.     }
  394.     else {
  395.       throw Cr.NS_ERROR_INVALID_ARG;
  396.     }
  397.     for (var index = 0; index < jsErrorList.length; index++) {
  398.       // Add the information to a property bag
  399.       var errorBag = Cc["@mozilla.org/hash-property-bag;1"]
  400.                        .createInstance(Ci.nsIWritablePropertyBag2);
  401.       errorBag.setPropertyAsAString("msg", jsErrorList[index].msg);
  402.       errorBag.setPropertyAsInterface("item",
  403.                                       jsErrorList[index].item,
  404.                                       Ci.sbIMediaItem);
  405.       errorBag.setPropertyAsUint32("state", jsErrorList[index].state);
  406.  
  407.       errorList.appendElement(errorBag, false);
  408.     }
  409.  
  410.     return errorList;
  411.   },
  412.  
  413.   /**
  414.    * \brief Clears the array of error strings for a device.
  415.    *
  416.    * \param aDevice device to clear error list from.
  417.    */
  418.   clearErrorsForDevice: function deviceErrorMonitor_clearErrorsForDevice(aDevice) {
  419.     var devIndex = this._findDeviceIndex(aDevice);
  420.  
  421.     if (devIndex > -1) {
  422.       this._deviceList[devIndex].errorLists = {};
  423.     }
  424.   },
  425.  
  426.   /**
  427.    * \brief Adds a listener for new device errors.
  428.    *
  429.    * \param aListener listener to call when a device error is logged.
  430.    */
  431.   addListener: function deviceErrorMonitor_addListener(aListener) {
  432.     if (this._listenerList.indexOf(aListener) < 0)
  433.       this._listenerList.push(aListener);
  434.   },
  435.  
  436.   /**
  437.    * \brief Removes a listener for new device errors.
  438.    *
  439.    * \param aListener listener to remove.
  440.    */
  441.   removeListener: function deviceErrorMonitor_addListener(aListener) {
  442.     var listenerIndex = this._listenerList.indexOf(aListener);
  443.     if (listenerIndex >= 0)
  444.       this._listenerList.splice(listenerIndex, 1);
  445.   },
  446.  
  447.   /**
  448.    * \brief Gets the current state of the device as a human readable string.
  449.    *
  450.    * \param aDeviceState device state.
  451.    * \return string version of the aDeviceState.
  452.    */
  453.   _getStateString: function deviceErrorMonitor__getStateString(aDeviceState) {
  454.     var stateString = "STATE_UNKNOWN";
  455.     switch (aDeviceState) {
  456.       case Ci.sbIDevice.STATE_IDLE:
  457.         stateString = "STATE_IDLE";
  458.         break;
  459.       case Ci.sbIDevice.STATE_SYNCING:
  460.         stateString = "STATE_SYNCING";
  461.         break;
  462.       case Ci.sbIDevice.STATE_COPYING:
  463.         stateString = "STATE_COPYING";
  464.         break;
  465.       case Ci.sbIDevice.STATE_DELETING:
  466.         stateString = "STATE_DELETING";
  467.         break;
  468.       case Ci.sbIDevice.STATE_UPDATING:
  469.         stateString = "STATE_UPDATING";
  470.         break;
  471.       case Ci.sbIDevice.STATE_MOUNTING:
  472.         stateString = "STATE_MOUNTING";
  473.         break;
  474.       case Ci.sbIDevice.STATE_DOWNLOADING:
  475.         stateString = "STATE_DOWNLOADING";
  476.         break;
  477.       case Ci.sbIDevice.STATE_UPLOADING:
  478.         stateString = "STATE_UPLOADING";
  479.         break;
  480.       case Ci.sbIDevice.STATE_DOWNLOAD_PAUSED:
  481.         stateString = "STATE_DOWNLOAD_PAUSED";
  482.         break;
  483.       case Ci.sbIDevice.STATE_UPLOAD_PAUSED:
  484.         stateString = "STATE_UPLOAD_PAUSED";
  485.         break;
  486.       case Ci.sbIDevice.STATE_DISCONNECTED:
  487.         stateString = "STATE_DISCONNECTED";
  488.         break;
  489.       case Ci.sbIDevice.STATE_BUSY:
  490.         stateString = "STATE_BUSY";
  491.         break;
  492.       case Ci.sbIDevice.STATE_CANCEL:
  493.         stateString = "STATE_CANCEL";
  494.         break;
  495.       case Ci.sbIDevice.STATE_TRANSCODE:
  496.         stateString = "STATE_TRANSCODE";
  497.         break;
  498.       case Ci.sbIDevice.STATE_FORMATTING:
  499.         stateString = "STATE_FORMATTING";
  500.         break;
  501.       case Ci.sbIDevice.STATE_SYNC_PREPARING:
  502.         stateString = "STATE_SYNC_PREPARING";
  503.         break;
  504.       case Ci.sbIDevice.STATE_SYNC_PLAYLIST:
  505.         stateString = "STATE_SYNC_PLAYLIST";
  506.         break;
  507.       case Ci.sbIDevice.STATE_COPY_PREPARING:
  508.         stateString = "STATE_COPY_PREPARING";
  509.         break;
  510.       case Ci.sbIDevice.STATE_SYNCING_TYPE:
  511.         stateString = "STATE_SYNCING_TYPE";
  512.         break;
  513.       case Ci.sbIDevice.STATE_COPYING_MUSIC:
  514.         stateString = "STATE_COPYING_MUSIC";
  515.         break;
  516.       case Ci.sbIDevice.STATE_COPYING_VIDEO:
  517.         stateString = "STATE_COPYING_VIDEO";
  518.         break;
  519.     }
  520.  
  521.     return stateString + " (" + aDeviceState + ")";
  522.   },
  523.  
  524.   /**
  525.    * \brief Gets the state and substate of a device as a human readable string.
  526.    *
  527.    * \param aDeviceEvent event information of the device
  528.    * \return string version of the device state and substate.
  529.    */
  530.   _getDeviceStateInformation:
  531.     function deviceErrorMonitor__getDeviceStateInformation(aDeviceEvent) {
  532.  
  533.     var state = aDeviceEvent.deviceState;
  534.     var substate = aDeviceEvent.deviceSubState;
  535.  
  536.     return this._getStateString(state) + " - " + this._getStateString(substate);
  537.   },
  538.  
  539.   /**
  540.    * \brief Logs the device event to the console for debugging.
  541.    *
  542.    * \param aDeviceEvent event information of the device
  543.    */
  544.   _logDeviceEvent: function deviceErrorMonitor__logDeviceEvent(aDeviceEvent) {
  545.     var evtMsg = "Unknown Event";
  546.     var evtSubMsg = "";
  547.  
  548.     // See if we can get a device
  549.     var device;
  550.     try {
  551.       device = aDeviceEvent.data.QueryInterface(Ci.sbIDevice);
  552.     } catch (err) { }
  553.  
  554.     switch (aDeviceEvent.type) {
  555.       case Ci.sbIDeviceEvent.EVENT_DEVICE_BASE:
  556.         evtMsg = "EVENT_DEVICE_BASE";
  557.         break;
  558.       case Ci.sbIDeviceEvent.EVENT_DEVICE_ADDED:
  559.         evtMsg = "EVENT_DEVICE_ADDED";
  560.         break;
  561.       case Ci.sbIDeviceEvent.EVENT_DEVICE_REMOVED:
  562.         evtMsg = "EVENT_DEVICE_REMOVED";
  563.         break;
  564.       case Ci.sbIDeviceEvent.EVENT_DEVICE_RESET:
  565.         evtMsg = "EVENT_DEVICE_RESET";
  566.         break;
  567.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_INSERTED:
  568.         evtMsg = "EVENT_DEVICE_MEDIA_INSERTED";
  569.         break;
  570.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_REMOVED:
  571.         evtMsg = "EVENT_DEVICE_MEDIA_REMOVED";
  572.         break;
  573.       case Ci.sbIDeviceEvent.EVENT_DEVICE_READY:
  574.         evtMsg = "EVENT_DEVICE_READY";
  575.         break;
  576.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_READ_START:
  577.         evtMsg = "EVENT_DEVICE_MEDIA_READ_START";
  578.         break;
  579.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_READ_END:
  580.         evtMsg = "EVENT_DEVICE_MEDIA_READ_END";
  581.         break;
  582.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_READ_FAILED:
  583.         evtMsg = "EVENT_DEVICE_MEDIA_READ_FAILED";
  584.         break;
  585.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_WRITE_START:
  586.         evtMsg = "EVENT_DEVICE_MEDIA_WRITE_START";
  587.         break;
  588.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_WRITE_END:
  589.         evtMsg = "EVENT_DEVICE_MEDIA_WRITE_END";
  590.         break;
  591.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_WRITE_FAILED:
  592.         evtMsg = "EVENT_DEVICE_MEDIA_WRITE_FAILED";
  593.         break;
  594.       case Ci.sbIDeviceEvent.EVENT_DEVICE_INFO_CHANGED:
  595.         evtMsg = "EVENT_DEVICE_INFO_CHANGED";
  596.         break;
  597.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_READ_UNSUPPORTED_TYPE:
  598.         evtMsg = "EVENT_DEVICE_MEDIA_READ_UNSUPPORTED_TYPE";
  599.         break;
  600.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_WRITE_UNSUPPORTED_TYPE:
  601.         evtMsg = "EVENT_DEVICE_MEDIA_WRITE_UNSUPPORTED_TYPE";
  602.         break;
  603.       case Ci.sbIDeviceEvent.EVENT_DEVICE_ACCESS_DENIED:
  604.         evtMsg = "EVENT_DEVICE_ACCESS_DENIED";
  605.         break;
  606.       case Ci.sbIDeviceEvent.EVENT_DEVICE_NOT_ENOUGH_FREESPACE:
  607.         evtMsg = "EVENT_DEVICE_NOT_ENOUGH_FREESPACE";
  608.         break;
  609.       case Ci.sbIDeviceEvent.EVENT_DEVICE_NOT_AVAILABLE:
  610.         evtMsg = "EVENT_DEVICE_NOT_AVAILABLE";
  611.         break;
  612.       case Ci.sbIDeviceEvent.EVENT_DEVICE_ERROR_UNEXPECTED:
  613.         evtMsg = "EVENT_DEVICE_ERROR_UNEXPECTED";
  614.         break;
  615.       case Ci.sbIDeviceEvent.EVENT_DEVICE_TRANSCODE_ERROR:
  616.         evtMsg = "EVENT_DEVICE_TRANSCODE_ERROR";
  617.         break;
  618.       case Ci.sbIDeviceEvent.EVENT_DEVICE_LIBRARY_ADDED:
  619.         evtMsg = "EVENT_DEVICE_LIBRARY_ADDED";
  620.         break;
  621.       case Ci.sbIDeviceEvent.EVENT_DEVICE_LIBRARY_REMOVED:
  622.         evtMsg = "EVENT_DEVICE_LIBRARY_REMOVED";
  623.         break;
  624.       case Ci.sbIDeviceEvent.EVENT_DEVICE_FILE_MISSING:
  625.         evtMsg = "EVENT_DEVICE_FILE_MISSING";
  626.         break;
  627.       case Ci.sbIDeviceEvent.EVENT_DEVICE_SCAN_START:
  628.         evtMsg = "EVENT_DEVICE_SCAN_START";
  629.         break;
  630.       case Ci.sbIDeviceEvent.EVENT_DEVICE_SCAN_END:
  631.         evtMsg = "EVENT_DEVICE_SCAN_END";
  632.         break;
  633.       case Ci.sbIDeviceEvent.EVENT_DEVICE_STATE_CHANGED:
  634.         evtMsg = "EVENT_DEVICE_STATE_CHANGED";
  635.         break;
  636.       case Ci.sbIDeviceEvent.EVENT_DEVICE_TRANSFER_START:
  637.         evtMsg = "EVENT_DEVICE_TRANSFER_START";
  638.         break;
  639.       case Ci.sbIDeviceEvent.EVENT_DEVICE_TRANSFER_PROGRESS:
  640.         evtMsg = "EVENT_DEVICE_TRANSFER_PROGRESS";
  641.         break;
  642.       case Ci.sbIDeviceEvent.EVENT_DEVICE_TRANSFER_END:
  643.         evtMsg = "EVENT_DEVICE_TRANSFER_END";
  644.         break;
  645.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MOUNTING_START:
  646.         evtMsg = "EVENT_DEVICE_MOUNTING_START";
  647.         break;
  648.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MOUNTING_PROGRESS:
  649.         evtMsg = "EVENT_DEVICE_MOUNTING_PROGRESS";
  650.         break;
  651.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MOUNTING_END:
  652.         evtMsg = "EVENT_DEVICE_MOUNTING_END";
  653.         break;
  654.       case Ci.sbIDeviceEvent.EVENT_DEVICE_PREFS_CHANGED:
  655.         evtMsg = "EVENT_DEVICE_PREFS_CHANGED";
  656.         break;
  657.       case Ci.sbIDeviceEvent.EVENT_DEVICE_TRANSCODE_START:
  658.         evtMsg = "EVENT_DEVICE_TRANSCODE_START";
  659.         break;
  660.       case Ci.sbIDeviceEvent.EVENT_DEVICE_TRANSCODE_PROGRESS:
  661.         evtMsg = "EVENT_DEVICE_TRANSCODE_PROGRESS";
  662.         break;
  663.       case Ci.sbIDeviceEvent.EVENT_DEVICE_TRANSCODE_END:
  664.         evtMsg = "EVENT_DEVICE_TRANSCODE_END";
  665.         break;
  666.       case Ci.sbIDeviceEvent.EVENT_DEVICE_FORMATTING_START:
  667.         evtMsg = "EVENT_DEVICE_FORMATTING_START";
  668.         break;
  669.       case Ci.sbIDeviceEvent.EVENT_DEVICE_FORMATTING_PROGRESS:
  670.         evtMsg = "EVENT_DEVICE_FORMATTING_PROGRESS";
  671.         break;
  672.       case Ci.sbIDeviceEvent.EVENT_DEVICE_FORMATTING_END:
  673.         evtMsg = "EVENT_DEVICE_FORMATTING_END";
  674.         break;
  675.     }
  676.  
  677.     var deviceGuid = "{Unknown}";
  678.     if (device)
  679.       deviceGuid = device.id + "[" + device.name + "]";
  680.  
  681.     evtSubMsg = this._getDeviceStateInformation(aDeviceEvent);
  682.  
  683.     var fullMsg = "Device Event " + deviceGuid + " - " + evtMsg + ": (" +
  684.                   aDeviceEvent.type + ")\n" +
  685.                   "       State " + evtSubMsg + "\n"
  686.  
  687.     dump(fullMsg);
  688.     this._consoleService.logStringMessage(fullMsg);
  689.   },
  690.  
  691.   // sbIDeviceEventListener
  692.   onDeviceEvent: function deviceErrorMonitor_onDeviceEvent(aDeviceEvent) {
  693.     if (this._debug) // Only log if the debug flag is set.
  694.       this._logDeviceEvent(aDeviceEvent);
  695.  
  696.     switch(aDeviceEvent.type) {
  697.       case Ci.sbIDeviceEvent.EVENT_DEVICE_ADDED:
  698.         var device = aDeviceEvent.data.QueryInterface(Ci.sbIDevice);
  699.         this._addDevice(device);
  700.       break;
  701.  
  702.       case Ci.sbIDeviceEvent.EVENT_DEVICE_REMOVED:
  703.         var device = aDeviceEvent.data.QueryInterface(Ci.sbIDevice);
  704.         this._removeDevice(device);
  705.       break;
  706.  
  707.       // An error has occurred, we need to store it for later
  708.       case Ci.sbIDeviceEvent.EVENT_DEVICE_ACCESS_DENIED:
  709.         this._logError(aDeviceEvent,
  710.                        SBString("device.error.access_denied"));
  711.       break;
  712.       case Ci.sbIDeviceEvent.EVENT_DEVICE_NOT_ENOUGH_FREESPACE:
  713.         this._logError(aDeviceEvent,
  714.                        SBString("device.error.not_enough_free_space"));
  715.       break;
  716.       case Ci.sbIDeviceEvent.EVENT_DEVICE_NOT_AVAILABLE:
  717.         this._logError(aDeviceEvent,
  718.                        SBString("device.error.not_available"));
  719.       break;
  720.       case Ci.sbIDeviceEvent.EVENT_DEVICE_ERROR_UNEXPECTED:
  721.         this._logError(aDeviceEvent,
  722.                        SBString("device.error.unexpected"));
  723.       break;
  724.       case Ci.sbIDeviceEvent.EVENT_DEVICE_FILE_MISSING:
  725.         this._logError(aDeviceEvent,
  726.                        SBString("device.error.file_missing"));
  727.       break;
  728.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_WRITE_UNSUPPORTED_TYPE:
  729.         this._logError(aDeviceEvent,
  730.                        SBString("device.error.unsupported_type"));
  731.       break;
  732.  
  733.       case Ci.sbIDeviceEvent.EVENT_DEVICE_TRANSCODE_ERROR:
  734.         // Grab the extended error info from the property bag
  735.         var message = "";
  736.         if (aDeviceEvent.data instanceof Ci.nsIPropertyBag2) {
  737.           message = aDeviceEvent.data.get("message");
  738.           if (!message && aDeviceEvent.data.hasKey("mediacore-error")) {
  739.             message = aDeviceEvent.data
  740.                                   .getPropertyAsInterface("mediacore-error",
  741.                                                           Ci.sbIMediacoreError)
  742.                                   .message;
  743.           }
  744.         }
  745.         this._logError(aDeviceEvent, message);
  746.       break;
  747.  
  748.       case Ci.sbIDeviceEvent.EVENT_DEVICE_DOWNLOAD_ERROR:
  749.         // Grab the extended error info from the property bag
  750.         var message = "";
  751.         if (aDeviceEvent.data instanceof Ci.nsIPropertyBag2) {
  752.           message = aDeviceEvent.data.get("message");
  753.         }
  754.         this._logError(aDeviceEvent, message);
  755.       break;
  756.       
  757.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_READ_START:
  758.         // Starting an import
  759.         this._direction = Ci.sbIDeviceStatus.IMPORT;
  760.       break;
  761.       
  762.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_READ_END:
  763.         // End of import
  764.         this._direction = Ci.sbIDeviceStatus.EXPORT;
  765.       break; 
  766.  
  767.       // This is just a safety in case EVENT_DEVICE_MEDIA_READ_END doesn't get
  768.       // sent
  769.       case Ci.sbIDeviceEvent.EVENT_DEVICE_MEDIA_WRITE_START:
  770.         // Starting an export
  771.         this._direction = Ci.sbIDeviceStatus.EXPORT;
  772.       break;
  773.     }
  774.   },
  775.  
  776.   // nsIObserver
  777.   observe: function deviceErrorMonitor_observer(subject, topic, data) {
  778.     var obsSvc = Cc['@mozilla.org/observer-service;1']
  779.                    .getService(Ci.nsIObserverService);
  780.  
  781.     switch (topic) {
  782.       case 'quit-application':
  783.         obsSvc.removeObserver(this, 'quit-application');
  784.         this._shutdown();
  785.       break;
  786.       case 'profile-after-change':
  787.         obsSvc.removeObserver(this, 'profile-after-change');
  788.         this._init();
  789.       break;
  790.     }
  791.   },
  792.  
  793.   // nsISupports
  794.   QueryInterface: XPCOMUtils.generateQI(deviceErrorMonitorConfig.ifList)
  795. };
  796.  
  797. /**
  798.  * /brief XPCOM initialization code
  799.  */
  800. function NSGetModule(compMgr, fileSpec) {
  801.   return XPCOMUtils.generateModule([deviceErrorMonitor]);
  802. }
  803.