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 |