| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 /** | |
| 6 * Thin wrapper for VolumeManager. This should be an interface proxy to talk | |
| 7 * to VolumeManager. This class also filters Drive related data/events if | |
| 8 * driveEnabled is set to false. | |
| 9 * | |
| 10 * @param {VolumeManagerWrapper.DriveEnabledStatus} driveEnabled DRIVE_ENABLED | |
| 11 * if drive should be available. DRIVE_DISABLED if drive related | |
| 12 * data/events should be hidden. | |
| 13 * @param {DOMWindow} opt_backgroundPage Window object of the background | |
| 14 * page. If this is specified, the class skips to get background page. | |
| 15 * TOOD(hirono): Let all clients of the class pass the background page and | |
| 16 * make the argument not optional. | |
| 17 * @constructor | |
| 18 * @extends {cr.EventTarget} | |
| 19 */ | |
| 20 function VolumeManagerWrapper(driveEnabled, opt_backgroundPage) { | |
| 21 cr.EventTarget.call(this); | |
| 22 | |
| 23 this.driveEnabled_ = driveEnabled; | |
| 24 this.volumeInfoList = new cr.ui.ArrayDataModel([]); | |
| 25 | |
| 26 this.volumeManager_ = null; | |
| 27 this.pendingTasks_ = []; | |
| 28 this.onEventBound_ = this.onEvent_.bind(this); | |
| 29 this.onVolumeInfoListUpdatedBound_ = | |
| 30 this.onVolumeInfoListUpdated_.bind(this); | |
| 31 | |
| 32 this.disposed_ = false; | |
| 33 | |
| 34 // Start initialize the VolumeManager. | |
| 35 var queue = new AsyncUtil.Queue(); | |
| 36 | |
| 37 if (opt_backgroundPage) { | |
| 38 this.backgroundPage_ = opt_backgroundPage; | |
| 39 } else { | |
| 40 queue.run(function(callNextStep) { | |
| 41 chrome.runtime.getBackgroundPage(function(backgroundPage) { | |
| 42 this.backgroundPage_ = backgroundPage; | |
| 43 callNextStep(); | |
| 44 }.bind(this)); | |
| 45 }.bind(this)); | |
| 46 } | |
| 47 | |
| 48 queue.run(function(callNextStep) { | |
| 49 this.backgroundPage_.VolumeManager.getInstance(function(volumeManager) { | |
| 50 this.onReady_(volumeManager); | |
| 51 callNextStep(); | |
| 52 }.bind(this)); | |
| 53 }.bind(this)); | |
| 54 } | |
| 55 | |
| 56 /** | |
| 57 * If the drive is enabled on the wrapper. | |
| 58 * @enum {boolean} | |
| 59 */ | |
| 60 VolumeManagerWrapper.DriveEnabledStatus = { | |
| 61 DRIVE_ENABLED: true, | |
| 62 DRIVE_DISABLED: false | |
| 63 }; | |
| 64 | |
| 65 /** | |
| 66 * Extends cr.EventTarget. | |
| 67 */ | |
| 68 VolumeManagerWrapper.prototype.__proto__ = cr.EventTarget.prototype; | |
| 69 | |
| 70 /** | |
| 71 * Called when the VolumeManager gets ready for post initialization. | |
| 72 * @param {VolumeManager} volumeManager The initialized VolumeManager instance. | |
| 73 * @private | |
| 74 */ | |
| 75 VolumeManagerWrapper.prototype.onReady_ = function(volumeManager) { | |
| 76 if (this.disposed_) | |
| 77 return; | |
| 78 | |
| 79 this.volumeManager_ = volumeManager; | |
| 80 | |
| 81 // Subscribe to VolumeManager. | |
| 82 this.volumeManager_.addEventListener( | |
| 83 'drive-connection-changed', this.onEventBound_); | |
| 84 this.volumeManager_.addEventListener( | |
| 85 'externally-unmounted', this.onEventBound_); | |
| 86 | |
| 87 // Cache volumeInfoList. | |
| 88 var volumeInfoList = []; | |
| 89 for (var i = 0; i < this.volumeManager_.volumeInfoList.length; i++) { | |
| 90 var volumeInfo = this.volumeManager_.volumeInfoList.item(i); | |
| 91 // TODO(hidehiko): Filter mounted volumes located on Drive File System. | |
| 92 if (!this.driveEnabled_ && volumeInfo.volumeType === util.VolumeType.DRIVE) | |
| 93 continue; | |
| 94 volumeInfoList.push(volumeInfo); | |
| 95 } | |
| 96 this.volumeInfoList.splice.apply( | |
| 97 this.volumeInfoList, | |
| 98 [0, this.volumeInfoList.length].concat(volumeInfoList)); | |
| 99 | |
| 100 // Subscribe to VolumeInfoList. | |
| 101 // In VolumeInfoList, we only use 'splice' event. | |
| 102 this.volumeManager_.volumeInfoList.addEventListener( | |
| 103 'splice', this.onVolumeInfoListUpdatedBound_); | |
| 104 | |
| 105 // Run pending tasks. | |
| 106 var pendingTasks = this.pendingTasks_; | |
| 107 this.pendingTasks_ = null; | |
| 108 for (var i = 0; i < pendingTasks.length; i++) | |
| 109 pendingTasks[i](); | |
| 110 }; | |
| 111 | |
| 112 /** | |
| 113 * Disposes the instance. After the invocation of this method, any other | |
| 114 * method should not be called. | |
| 115 */ | |
| 116 VolumeManagerWrapper.prototype.dispose = function() { | |
| 117 this.disposed_ = true; | |
| 118 | |
| 119 if (!this.volumeManager_) | |
| 120 return; | |
| 121 this.volumeManager_.removeEventListener( | |
| 122 'drive-connection-changed', this.onEventBound_); | |
| 123 this.volumeManager_.removeEventListener( | |
| 124 'externally-unmounted', this.onEventBound_); | |
| 125 this.volumeManager_.volumeInfoList.removeEventListener( | |
| 126 'splice', this.onVolumeInfoListUpdatedBound_); | |
| 127 }; | |
| 128 | |
| 129 /** | |
| 130 * Called on events sent from VolumeManager. This has responsibility to | |
| 131 * re-dispatch the event to the listeners. | |
| 132 * @param {Event} event Event object sent from VolumeManager. | |
| 133 * @private | |
| 134 */ | |
| 135 VolumeManagerWrapper.prototype.onEvent_ = function(event) { | |
| 136 if (!this.driveEnabled_) { | |
| 137 // If the drive is disabled, ignore all drive related events. | |
| 138 if (event.type === 'drive-connection-changed' || | |
| 139 (event.type === 'externally-unmounted' && | |
| 140 event.volumeInfo.volumeType === util.VolumeType.DRIVE)) | |
| 141 return; | |
| 142 } | |
| 143 | |
| 144 this.dispatchEvent(event); | |
| 145 }; | |
| 146 | |
| 147 /** | |
| 148 * Called on events of modifying VolumeInfoList. | |
| 149 * @param {Event} event Event object sent from VolumeInfoList. | |
| 150 * @private | |
| 151 */ | |
| 152 VolumeManagerWrapper.prototype.onVolumeInfoListUpdated_ = function(event) { | |
| 153 if (this.driveEnabled_) { | |
| 154 // Apply the splice as is. | |
| 155 this.volumeInfoList.splice.apply( | |
| 156 this.volumeInfoList, | |
| 157 [event.index, event.removed.length].concat(event.added)); | |
| 158 } else { | |
| 159 // Filters drive related volumes. | |
| 160 var index = event.index; | |
| 161 for (var i = 0; i < event.index; i++) { | |
| 162 if (this.volumeManager_.volumeInfoList.item(i).volumeType === | |
| 163 util.VolumeType.DRIVE) | |
| 164 index--; | |
| 165 } | |
| 166 | |
| 167 var numRemovedVolumes = 0; | |
| 168 for (var i = 0; i < event.removed.length; i++) { | |
| 169 if (event.removed[i].volumeType !== util.VolumeType.DRIVE) | |
| 170 numRemovedVolumes++; | |
| 171 } | |
| 172 | |
| 173 var addedVolumes = []; | |
| 174 for (var i = 0; i < event.added.length; i++) { | |
| 175 var volumeInfo = event.added[i]; | |
| 176 if (volumeInfo.volumeType !== util.VolumeType.DRIVE) | |
| 177 addedVolumes.push(volumeInfo); | |
| 178 } | |
| 179 | |
| 180 this.volumeInfoList.splice.apply( | |
| 181 this.volumeInfoList, | |
| 182 [index, numRemovedVolumes].concat(addedVolumes)); | |
| 183 } | |
| 184 }; | |
| 185 | |
| 186 /** | |
| 187 * Ensures the VolumeManager is initialized, and then invokes callback. | |
| 188 * If the VolumeManager is already initialized, callback will be called | |
| 189 * immediately. | |
| 190 * @param {function()} callback Called on initialization completion. | |
| 191 */ | |
| 192 VolumeManagerWrapper.prototype.ensureInitialized = function(callback) { | |
| 193 if (this.pendingTasks_) { | |
| 194 this.pendingTasks_.push(this.ensureInitialized.bind(this, callback)); | |
| 195 return; | |
| 196 } | |
| 197 | |
| 198 callback(); | |
| 199 }; | |
| 200 | |
| 201 /** | |
| 202 * @return {util.DriveConnectionType} Current drive connection state. | |
| 203 */ | |
| 204 VolumeManagerWrapper.prototype.getDriveConnectionState = function() { | |
| 205 if (!this.driveEnabled_ || !this.volumeManager_) { | |
| 206 return { | |
| 207 type: util.DriveConnectionType.OFFLINE, | |
| 208 reason: util.DriveConnectionReason.NO_SERVICE | |
| 209 }; | |
| 210 } | |
| 211 | |
| 212 return this.volumeManager_.getDriveConnectionState(); | |
| 213 }; | |
| 214 | |
| 215 /** | |
| 216 * Obtains a volume info containing the passed entry. | |
| 217 * @param {Entry} entry Entry on the volume to be returned. | |
| 218 * @return {VolumeInfo} The VolumeInfo instance or null if not found. | |
| 219 */ | |
| 220 VolumeManagerWrapper.prototype.getVolumeInfo = function(entry) { | |
| 221 return this.filterDisabledDriveVolume_( | |
| 222 this.volumeManager_ && this.volumeManager_.getVolumeInfo(entry)); | |
| 223 }; | |
| 224 | |
| 225 /** | |
| 226 * Obtains a volume information of the current profile. | |
| 227 * @param {util.VolumeType} volumeType Volume type. | |
| 228 * @return {VolumeInfo} Found volume info. | |
| 229 */ | |
| 230 VolumeManagerWrapper.prototype.getCurrentProfileVolumeInfo = | |
| 231 function(volumeType) { | |
| 232 return this.filterDisabledDriveVolume_( | |
| 233 this.volumeManager_ && | |
| 234 this.volumeManager_.getCurrentProfileVolumeInfo(volumeType)); | |
| 235 }; | |
| 236 | |
| 237 /** | |
| 238 * Obtains the default display root entry. | |
| 239 * @param {function(Entry)} callback Callback passed the default display root. | |
| 240 */ | |
| 241 VolumeManagerWrapper.prototype.getDefaultDisplayRoot = | |
| 242 function(callback) { | |
| 243 this.ensureInitialized(function() { | |
| 244 var defaultVolume = this.getCurrentProfileVolumeInfo( | |
| 245 util.VolumeType.DOWNLOADS); | |
| 246 defaultVolume.resolveDisplayRoot(callback, function() { | |
| 247 // defaultVolume is DOWNLOADS and resolveDisplayRoot should succeed. | |
| 248 throw new Error( | |
| 249 'Unexpectedly failed to obtain the default display root.'); | |
| 250 }); | |
| 251 }.bind(this)); | |
| 252 }; | |
| 253 | |
| 254 /** | |
| 255 * Obtains location information from an entry. | |
| 256 * | |
| 257 * @param {Entry} entry File or directory entry. | |
| 258 * @return {EntryLocation} Location information. | |
| 259 */ | |
| 260 VolumeManagerWrapper.prototype.getLocationInfo = function(entry) { | |
| 261 var locationInfo = | |
| 262 this.volumeManager_ && this.volumeManager_.getLocationInfo(entry); | |
| 263 if (!locationInfo) | |
| 264 return null; | |
| 265 if (!this.filterDisabledDriveVolume_(locationInfo.volumeInfo)) | |
| 266 return null; | |
| 267 return locationInfo; | |
| 268 }; | |
| 269 | |
| 270 /** | |
| 271 * Requests to mount the archive file. | |
| 272 * @param {string} fileUrl The path to the archive file to be mounted. | |
| 273 * @param {function(VolumeInfo)} successCallback Called with the VolumeInfo | |
| 274 * instance. | |
| 275 * @param {function(util.VolumeError)} errorCallback Called when an error | |
| 276 * occurs. | |
| 277 */ | |
| 278 VolumeManagerWrapper.prototype.mountArchive = function( | |
| 279 fileUrl, successCallback, errorCallback) { | |
| 280 if (this.pendingTasks_) { | |
| 281 this.pendingTasks_.push( | |
| 282 this.mountArchive.bind(this, fileUrl, successCallback, errorCallback)); | |
| 283 return; | |
| 284 } | |
| 285 | |
| 286 this.volumeManager_.mountArchive(fileUrl, successCallback, errorCallback); | |
| 287 }; | |
| 288 | |
| 289 /** | |
| 290 * Requests unmount the specified volume. | |
| 291 * @param {!VolumeInfo} volumeInfo Volume to be unmounted. | |
| 292 * @param {function()} successCallback Called on success. | |
| 293 * @param {function(util.VolumeError)} errorCallback Called when an error | |
| 294 * occurs. | |
| 295 */ | |
| 296 VolumeManagerWrapper.prototype.unmount = function( | |
| 297 volumeInfo, successCallback, errorCallback) { | |
| 298 if (this.pendingTasks_) { | |
| 299 this.pendingTasks_.push( | |
| 300 this.unmount.bind(this, volumeInfo, successCallback, errorCallback)); | |
| 301 return; | |
| 302 } | |
| 303 | |
| 304 this.volumeManager_.unmount(volumeInfo, successCallback, errorCallback); | |
| 305 }; | |
| 306 | |
| 307 /** | |
| 308 * Filters volume info by referring driveEnabled. | |
| 309 * | |
| 310 * @param {VolumeInfo} volumeInfo Volume info. | |
| 311 * @return {VolumeInfo} Null if the drive is disabled and the given volume is | |
| 312 * drive. Otherwise just returns the volume. | |
| 313 * @private | |
| 314 */ | |
| 315 VolumeManagerWrapper.prototype.filterDisabledDriveVolume_ = | |
| 316 function(volumeInfo) { | |
| 317 var isDrive = volumeInfo && volumeInfo.volumeType === util.VolumeType.DRIVE; | |
| 318 return this.driveEnabled_ || !isDrive ? volumeInfo : null; | |
| 319 }; | |
| OLD | NEW |