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.
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.
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.
18 * @extends {cr.EventTarget}
20 function VolumeManagerWrapper(driveEnabled, opt_backgroundPage) {
21 cr.EventTarget.call(this);
23 this.driveEnabled_ = driveEnabled;
24 this.volumeInfoList = new cr.ui.ArrayDataModel([]);
26 this.volumeManager_ = null;
27 this.pendingTasks_ = [];
28 this.onEventBound_ = this.onEvent_.bind(this);
29 this.onVolumeInfoListUpdatedBound_ =
30 this.onVolumeInfoListUpdated_.bind(this);
32 this.disposed_ = false;
34 // Start initialize the VolumeManager.
35 var queue = new AsyncUtil.Queue();
37 if (opt_backgroundPage) {
38 this.backgroundPage_ = opt_backgroundPage;
40 queue.run(function(callNextStep) {
41 chrome.runtime.getBackgroundPage(function(backgroundPage) {
42 this.backgroundPage_ = backgroundPage;
48 queue.run(function(callNextStep) {
49 this.backgroundPage_.VolumeManager.getInstance(function(volumeManager) {
50 this.onReady_(volumeManager);
57 * If the drive is enabled on the wrapper.
60 VolumeManagerWrapper.DriveEnabledStatus = {
66 * Extends cr.EventTarget.
68 VolumeManagerWrapper.prototype.__proto__ = cr.EventTarget.prototype;
71 * Called when the VolumeManager gets ready for post initialization.
72 * @param {VolumeManager} volumeManager The initialized VolumeManager instance.
75 VolumeManagerWrapper.prototype.onReady_ = function(volumeManager) {
79 this.volumeManager_ = volumeManager;
81 // Subscribe to VolumeManager.
82 this.volumeManager_.addEventListener(
83 'drive-connection-changed', this.onEventBound_);
84 this.volumeManager_.addEventListener(
85 'externally-unmounted', this.onEventBound_);
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 ===
93 VolumeManagerCommon.VolumeType.DRIVE)
95 volumeInfoList.push(volumeInfo);
97 this.volumeInfoList.splice.apply(
99 [0, this.volumeInfoList.length].concat(volumeInfoList));
101 // Subscribe to VolumeInfoList.
102 // In VolumeInfoList, we only use 'splice' event.
103 this.volumeManager_.volumeInfoList.addEventListener(
104 'splice', this.onVolumeInfoListUpdatedBound_);
106 // Run pending tasks.
107 var pendingTasks = this.pendingTasks_;
108 this.pendingTasks_ = null;
109 for (var i = 0; i < pendingTasks.length; i++)
114 * Disposes the instance. After the invocation of this method, any other
115 * method should not be called.
117 VolumeManagerWrapper.prototype.dispose = function() {
118 this.disposed_ = true;
120 if (!this.volumeManager_)
122 this.volumeManager_.removeEventListener(
123 'drive-connection-changed', this.onEventBound_);
124 this.volumeManager_.removeEventListener(
125 'externally-unmounted', this.onEventBound_);
126 this.volumeManager_.volumeInfoList.removeEventListener(
127 'splice', this.onVolumeInfoListUpdatedBound_);
131 * Called on events sent from VolumeManager. This has responsibility to
132 * re-dispatch the event to the listeners.
133 * @param {Event} event Event object sent from VolumeManager.
136 VolumeManagerWrapper.prototype.onEvent_ = function(event) {
137 if (!this.driveEnabled_) {
138 // If the drive is disabled, ignore all drive related events.
139 if (event.type === 'drive-connection-changed' ||
140 (event.type === 'externally-unmounted' &&
141 event.volumeInfo.volumeType ===
142 VolumeManagerCommon.VolumeType.DRIVE)) {
147 this.dispatchEvent(event);
151 * Called on events of modifying VolumeInfoList.
152 * @param {Event} event Event object sent from VolumeInfoList.
155 VolumeManagerWrapper.prototype.onVolumeInfoListUpdated_ = function(event) {
156 if (this.driveEnabled_) {
157 // Apply the splice as is.
158 this.volumeInfoList.splice.apply(
160 [event.index, event.removed.length].concat(event.added));
162 // Filters drive related volumes.
163 var index = event.index;
164 for (var i = 0; i < event.index; i++) {
165 if (this.volumeManager_.volumeInfoList.item(i).volumeType ===
166 VolumeManagerCommon.VolumeType.DRIVE)
170 var numRemovedVolumes = 0;
171 for (var i = 0; i < event.removed.length; i++) {
172 if (event.removed[i].volumeType !== VolumeManagerCommon.VolumeType.DRIVE)
176 var addedVolumes = [];
177 for (var i = 0; i < event.added.length; i++) {
178 var volumeInfo = event.added[i];
179 if (volumeInfo.volumeType !== VolumeManagerCommon.VolumeType.DRIVE)
180 addedVolumes.push(volumeInfo);
183 this.volumeInfoList.splice.apply(
185 [index, numRemovedVolumes].concat(addedVolumes));
190 * Ensures the VolumeManager is initialized, and then invokes callback.
191 * If the VolumeManager is already initialized, callback will be called
193 * @param {function()} callback Called on initialization completion.
195 VolumeManagerWrapper.prototype.ensureInitialized = function(callback) {
196 if (this.pendingTasks_) {
197 this.pendingTasks_.push(this.ensureInitialized.bind(this, callback));
205 * @return {VolumeManagerCommon.DriveConnectionType} Current drive connection
208 VolumeManagerWrapper.prototype.getDriveConnectionState = function() {
209 if (!this.driveEnabled_ || !this.volumeManager_) {
211 type: VolumeManagerCommon.DriveConnectionType.OFFLINE,
212 reason: VolumeManagerCommon.DriveConnectionReason.NO_SERVICE
216 return this.volumeManager_.getDriveConnectionState();
220 * Obtains a volume info containing the passed entry.
221 * @param {Entry} entry Entry on the volume to be returned.
222 * @return {VolumeInfo} The VolumeInfo instance or null if not found.
224 VolumeManagerWrapper.prototype.getVolumeInfo = function(entry) {
225 return this.filterDisabledDriveVolume_(
226 this.volumeManager_ && this.volumeManager_.getVolumeInfo(entry));
230 * Obtains a volume information of the current profile.
231 * @param {VolumeManagerCommon.VolumeType} volumeType Volume type.
232 * @return {VolumeInfo} Found volume info.
234 VolumeManagerWrapper.prototype.getCurrentProfileVolumeInfo =
235 function(volumeType) {
236 return this.filterDisabledDriveVolume_(
237 this.volumeManager_ &&
238 this.volumeManager_.getCurrentProfileVolumeInfo(volumeType));
242 * Obtains the default display root entry.
243 * @param {function(Entry)} callback Callback passed the default display root.
245 VolumeManagerWrapper.prototype.getDefaultDisplayRoot =
247 this.ensureInitialized(function() {
248 var defaultVolume = this.getCurrentProfileVolumeInfo(
249 VolumeManagerCommon.VolumeType.DOWNLOADS);
250 defaultVolume.resolveDisplayRoot(callback, function() {
251 // defaultVolume is DOWNLOADS and resolveDisplayRoot should succeed.
253 'Unexpectedly failed to obtain the default display root.');
259 * Obtains location information from an entry.
261 * @param {Entry} entry File or directory entry.
262 * @return {EntryLocation} Location information.
264 VolumeManagerWrapper.prototype.getLocationInfo = function(entry) {
266 this.volumeManager_ && this.volumeManager_.getLocationInfo(entry);
269 if (!this.filterDisabledDriveVolume_(locationInfo.volumeInfo))
275 * Requests to mount the archive file.
276 * @param {string} fileUrl The path to the archive file to be mounted.
277 * @param {function(VolumeInfo)} successCallback Called with the VolumeInfo
279 * @param {function(VolumeManagerCommon.VolumeError)} errorCallback Called when
282 VolumeManagerWrapper.prototype.mountArchive = function(
283 fileUrl, successCallback, errorCallback) {
284 if (this.pendingTasks_) {
285 this.pendingTasks_.push(
286 this.mountArchive.bind(this, fileUrl, successCallback, errorCallback));
290 this.volumeManager_.mountArchive(fileUrl, successCallback, errorCallback);
294 * Requests unmount the specified volume.
295 * @param {!VolumeInfo} volumeInfo Volume to be unmounted.
296 * @param {function()} successCallback Called on success.
297 * @param {function(VolumeManagerCommon.VolumeError)} errorCallback Called when
300 VolumeManagerWrapper.prototype.unmount = function(
301 volumeInfo, successCallback, errorCallback) {
302 if (this.pendingTasks_) {
303 this.pendingTasks_.push(
304 this.unmount.bind(this, volumeInfo, successCallback, errorCallback));
308 this.volumeManager_.unmount(volumeInfo, successCallback, errorCallback);
312 * Filters volume info by referring driveEnabled.
314 * @param {VolumeInfo} volumeInfo Volume info.
315 * @return {VolumeInfo} Null if the drive is disabled and the given volume is
316 * drive. Otherwise just returns the volume.
319 VolumeManagerWrapper.prototype.filterDisabledDriveVolume_ =
320 function(volumeInfo) {
321 var isDrive = volumeInfo && volumeInfo.volumeType ===
322 VolumeManagerCommon.VolumeType.DRIVE;
323 return this.driveEnabled_ || !isDrive ? volumeInfo : null;