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 |