| 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 == '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.mountPath == RootDirectory.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 == 'drive') | |
| 163 index--; | |
| 164 } | |
| 165 | |
| 166 var numRemovedVolumes = 0; | |
| 167 for (var i = 0; i < event.removed.length; i++) { | |
| 168 if (event.removed[i].volumeType != 'drive') | |
| 169 numRemovedVolumes++; | |
| 170 } | |
| 171 | |
| 172 var addedVolumes = []; | |
| 173 for (var i = 0; i < event.added.length; i++) { | |
| 174 var volumeInfo = event.added[i]; | |
| 175 if (volumeInfo.volumeType != 'drive') | |
| 176 addedVolumes.push(volumeInfo); | |
| 177 } | |
| 178 | |
| 179 this.volumeInfoList.splice.apply( | |
| 180 this.volumeInfoList, | |
| 181 [index, numRemovedVolumes].concat(addedVolumes)); | |
| 182 } | |
| 183 }; | |
| 184 | |
| 185 /** | |
| 186 * Ensures the VolumeManager is initialized, and then invokes callback. | |
| 187 * If the VolumeManager is already initialized, callback will be called | |
| 188 * immediately. | |
| 189 * @param {function()} callback Called on initialization completion. | |
| 190 */ | |
| 191 VolumeManagerWrapper.prototype.ensureInitialized = function(callback) { | |
| 192 if (this.pendingTasks_) { | |
| 193 this.pendingTasks_.push(this.ensureInitialized.bind(this, callback)); | |
| 194 return; | |
| 195 } | |
| 196 | |
| 197 callback(); | |
| 198 }; | |
| 199 | |
| 200 /** | |
| 201 * @return {util.DriveConnectionType} Current drive connection state. | |
| 202 */ | |
| 203 VolumeManagerWrapper.prototype.getDriveConnectionState = function() { | |
| 204 if (!this.driveEnabled_ || !this.volumeManager_) { | |
| 205 return { | |
| 206 type: util.DriveConnectionType.OFFLINE, | |
| 207 reasons: [util.DriveConnectionReason.NO_SERVICE] | |
| 208 }; | |
| 209 } | |
| 210 | |
| 211 return this.volumeManager_.getDriveConnectionState(); | |
| 212 }; | |
| 213 | |
| 214 /** | |
| 215 * @param {string} mountPath The path to mount location of the volume. | |
| 216 * @return {VolumeInfo} The VolumeInfo instance for the volume mounted at | |
| 217 * mountPath, or null if no volume is found | |
| 218 */ | |
| 219 VolumeManagerWrapper.prototype.getVolumeInfo = function(mountPath) { | |
| 220 if (!this.volumeManager_) | |
| 221 return null; | |
| 222 | |
| 223 var volumeInfo = this.volumeManager_.getVolumeInfo(mountPath); | |
| 224 if (!this.driveEnabled_ && volumeInfo.volumeType == 'drive') | |
| 225 return null; | |
| 226 | |
| 227 return volumeInfo; | |
| 228 }; | |
| 229 | |
| 230 /** | |
| 231 * Requests to mount the archive file. | |
| 232 * @param {string} fileUrl The path to the archive file to be mounted. | |
| 233 * @param {function(string)} successCallback Called with mount path on success. | |
| 234 * @param {function(util.VolumeError)} errorCallback Called when an error | |
| 235 * occurs. | |
| 236 */ | |
| 237 VolumeManagerWrapper.prototype.mountArchive = function( | |
| 238 fileUrl, successCallback, errorCallback) { | |
| 239 if (this.pendingTasks_) { | |
| 240 this.pendingTasks_.push( | |
| 241 this.mountArchive.bind(this, fileUrl, successCallback, errorCallback)); | |
| 242 return; | |
| 243 } | |
| 244 | |
| 245 this.volumeManager_.mountArchive(fileUrl, successCallback, errorCallback); | |
| 246 }; | |
| 247 | |
| 248 /** | |
| 249 * Requests unmount the volume at mountPath. | |
| 250 * @param {string} mountPath The path to the mount location of the volume. | |
| 251 * @param {function(string)} successCallback Called with the mount path | |
| 252 * on success. | |
| 253 * @param {function(util.VolumeError)} errorCallback Called when an error | |
| 254 * occurs. | |
| 255 */ | |
| 256 VolumeManagerWrapper.prototype.unmount = function( | |
| 257 mountPath, successCallback, errorCallback) { | |
| 258 if (this.pendingTasks_) { | |
| 259 this.pendingTasks_.push( | |
| 260 this.unmount.bind(this, mountPath, successCallback, errorCallback)); | |
| 261 return; | |
| 262 } | |
| 263 | |
| 264 this.volumeManager_.unmount(mountPath, successCallback, errorCallback); | |
| 265 }; | |
| 266 | |
| 267 /** | |
| 268 * Resolves the path to an entry instance. | |
| 269 * @param {string} path The path to be resolved. | |
| 270 * @param {function(Entry)} successCallback Called with the resolved entry | |
| 271 * on success. | |
| 272 * @param {function(FileError)} errorCallback Called with the error on error. | |
| 273 */ | |
| 274 VolumeManagerWrapper.prototype.resolvePath = function( | |
| 275 path, successCallback, errorCallback) { | |
| 276 if (this.pendingTasks_) { | |
| 277 this.pendingTasks_.push( | |
| 278 this.resolvePath.bind(this, path, successCallback, errorCallback)); | |
| 279 return; | |
| 280 } | |
| 281 | |
| 282 // If the drive is disabled, any resolving the path under drive should be | |
| 283 // failed. | |
| 284 if (!this.driveEnabled_ && PathUtil.isDriveBasedPath(path)) { | |
| 285 errorCallback(util.createFileError(FileError.NOT_FOUND_ERR)); | |
| 286 return; | |
| 287 } | |
| 288 | |
| 289 this.volumeManager_.resolvePath(path, successCallback, errorCallback); | |
| 290 }; | |
| OLD | NEW |