Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / ui / file_manager / file_manager / foreground / js / ui / drive_banners.js
1 // Copyright (c) 2012 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  * Responsible for showing following banners in the file list.
7  *  - WelcomeBanner
8  *  - AuthFailBanner
9  * @param {DirectoryModel} directoryModel The model.
10  * @param {VolumeManagerWrapper} volumeManager The manager.
11  * @param {Document} document HTML document.
12  * @param {boolean} showOffers True if we should show offer banners.
13  * @constructor
14  * @extends {cr.EventTarget}
15  */
16 function FileListBannerController(
17     directoryModel, volumeManager, document, showOffers) {
18   this.directoryModel_ = directoryModel;
19   this.volumeManager_ = volumeManager;
20   this.document_ = document;
21   this.showOffers_ = showOffers;
22   this.driveEnabled_ = false;
23
24   this.initializeWelcomeBanner_();
25   this.privateOnDirectoryChangedBound_ =
26       this.privateOnDirectoryChanged_.bind(this);
27
28   var handler = this.checkSpaceAndMaybeShowWelcomeBanner_.bind(this);
29   this.directoryModel_.addEventListener('scan-completed', handler);
30   this.directoryModel_.addEventListener('rescan-completed', handler);
31   this.directoryModel_.addEventListener('directory-changed',
32       this.onDirectoryChanged_.bind(this));
33
34   this.unmountedPanel_ = this.document_.querySelector('#unmounted-panel');
35   this.volumeManager_.volumeInfoList.addEventListener(
36       'splice', this.onVolumeInfoListSplice_.bind(this));
37   this.volumeManager_.addEventListener('drive-connection-changed',
38       this.onDriveConnectionChanged_.bind(this));
39
40   chrome.storage.onChanged.addListener(this.onStorageChange_.bind(this));
41   this.welcomeHeaderCounter_ = WELCOME_HEADER_COUNTER_LIMIT;
42   this.warningDismissedCounter_ = 0;
43   chrome.storage.local.get(
44       [WELCOME_HEADER_COUNTER_KEY, WARNING_DISMISSED_KEY],
45       function(values) {
46         this.welcomeHeaderCounter_ =
47             parseInt(values[WELCOME_HEADER_COUNTER_KEY], 10) || 0;
48         this.warningDismissedCounter_ =
49             parseInt(values[WARNING_DISMISSED_KEY], 10) || 0;
50       }.bind(this));
51
52   this.authFailedBanner_ =
53       this.document_.querySelector('#drive-auth-failed-warning');
54   var authFailedText = this.authFailedBanner_.querySelector('.drive-text');
55   authFailedText.innerHTML = util.htmlUnescape(str('DRIVE_NOT_REACHED'));
56   authFailedText.querySelector('a').addEventListener('click', function(e) {
57     chrome.fileManagerPrivate.logoutUserForReauthentication();
58     e.preventDefault();
59   });
60   this.maybeShowAuthFailBanner_();
61 }
62
63 /**
64  * FileListBannerController extends cr.EventTarget.
65  */
66 FileListBannerController.prototype.__proto__ = cr.EventTarget.prototype;
67
68 /**
69  * Key in localStorage to keep number of times the Drive Welcome
70  * banner has shown.
71  */
72 var WELCOME_HEADER_COUNTER_KEY = 'driveWelcomeHeaderCounter';
73
74 // If the warning was dismissed before, this key stores the quota value
75 // (as of the moment of dismissal).
76 // If the warning was never dismissed or was reset this key stores 0.
77 var WARNING_DISMISSED_KEY = 'driveSpaceWarningDismissed';
78
79 /**
80  * Maximum times Drive Welcome banner could have shown.
81  */
82 var WELCOME_HEADER_COUNTER_LIMIT = 25;
83
84 /**
85  * Initializes the banner to promote DRIVE.
86  * This method must be called before any of showing banner functions, and
87  * also before registering them as callbacks.
88  * @private
89  */
90 FileListBannerController.prototype.initializeWelcomeBanner_ = function() {
91   this.usePromoWelcomeBanner_ = !util.boardIs('x86-mario') &&
92                                 !util.boardIs('x86-zgb') &&
93                                 !util.boardIs('x86-alex');
94 };
95
96 /**
97  * @param {number} value How many times the Drive Welcome header banner
98  * has shown.
99  * @private
100  */
101 FileListBannerController.prototype.setWelcomeHeaderCounter_ = function(value) {
102   var values = {};
103   values[WELCOME_HEADER_COUNTER_KEY] = value;
104   chrome.storage.local.set(values);
105 };
106
107 /**
108  * @param {number} value How many times the low space warning has dismissed.
109  * @private
110  */
111 FileListBannerController.prototype.setWarningDismissedCounter_ =
112     function(value) {
113   var values = {};
114   values[WARNING_DISMISSED_KEY] = value;
115   chrome.storage.local.set(values);
116 };
117
118 /**
119  * chrome.storage.onChanged event handler.
120  * @param {Object.<string, Object>} changes Changes values.
121  * @param {string} areaName "local" or "sync".
122  * @private
123  */
124 FileListBannerController.prototype.onStorageChange_ = function(changes,
125                                                                areaName) {
126   if (areaName == 'local' && WELCOME_HEADER_COUNTER_KEY in changes) {
127     this.welcomeHeaderCounter_ = changes[WELCOME_HEADER_COUNTER_KEY].newValue;
128   }
129   if (areaName == 'local' && WARNING_DISMISSED_KEY in changes) {
130     this.warningDismissedCounter_ = changes[WARNING_DISMISSED_KEY].newValue;
131   }
132 };
133
134 /**
135  * Invoked when the drive connection status is change in the volume manager.
136  * @private
137  */
138 FileListBannerController.prototype.onDriveConnectionChanged_ = function() {
139   this.maybeShowAuthFailBanner_();
140 };
141
142 /**
143  * @param {string} type 'none'|'page'|'header'.
144  * @param {string} messageId Resource ID of the message.
145  * @private
146  */
147 FileListBannerController.prototype.prepareAndShowWelcomeBanner_ =
148     function(type, messageId) {
149   this.showWelcomeBanner_(type);
150
151   var container = this.document_.querySelector('.drive-welcome.' + type);
152   if (container.firstElementChild)
153     return;  // Do not re-create.
154
155   if (!this.document_.querySelector('link[drive-welcome-style]')) {
156     var style = this.document_.createElement('link');
157     style.rel = 'stylesheet';
158     style.href = 'foreground/css/drive_welcome.css';
159     style.setAttribute('drive-welcome-style', '');
160     this.document_.head.appendChild(style);
161   }
162
163   var wrapper = util.createChild(container, 'drive-welcome-wrapper');
164   util.createChild(wrapper, 'drive-welcome-icon');
165
166   var close = util.createChild(wrapper, 'cr-dialog-close');
167   close.addEventListener('click', this.closeWelcomeBanner_.bind(this));
168
169   var message = util.createChild(wrapper, 'drive-welcome-message');
170
171   var title = util.createChild(message, 'drive-welcome-title');
172
173   var text = util.createChild(message, 'drive-welcome-text');
174   text.innerHTML = str(messageId);
175
176   var links = util.createChild(message, 'drive-welcome-links');
177
178   var more;
179   if (this.usePromoWelcomeBanner_) {
180     var welcomeTitle = str('DRIVE_WELCOME_TITLE_ALTERNATIVE');
181     if (util.boardIs('link'))
182       welcomeTitle = str('DRIVE_WELCOME_TITLE_ALTERNATIVE_1TB');
183     title.textContent = welcomeTitle;
184     more = util.createChild(links,
185         'drive-welcome-button drive-welcome-start', 'a');
186     more.textContent = str('DRIVE_WELCOME_CHECK_ELIGIBILITY');
187     more.href = str('GOOGLE_DRIVE_REDEEM_URL');
188   } else {
189     title.textContent = str('DRIVE_WELCOME_TITLE');
190     more = util.createChild(links, 'plain-link', 'a');
191     more.textContent = str('DRIVE_LEARN_MORE');
192     more.href = str('GOOGLE_DRIVE_OVERVIEW_URL');
193   }
194   more.tabIndex = '16';  // See: go/filesapp-tabindex.
195   more.target = '_blank';
196
197   var dismiss;
198   if (this.usePromoWelcomeBanner_)
199     dismiss = util.createChild(links, 'drive-welcome-button');
200   else
201     dismiss = util.createChild(links, 'plain-link');
202
203   dismiss.classList.add('drive-welcome-dismiss');
204   dismiss.textContent = str('DRIVE_WELCOME_DISMISS');
205   dismiss.addEventListener('click', this.closeWelcomeBanner_.bind(this));
206
207   this.previousDirWasOnDrive_ = false;
208 };
209
210 /**
211  * Show or hide the "Low Google Drive space" warning.
212  * @param {boolean} show True if the box need to be shown.
213  * @param {Object=} opt_sizeStats Size statistics. Should be defined when
214  *     showing the warning.
215  * @private
216  */
217 FileListBannerController.prototype.showLowDriveSpaceWarning_ =
218     function(show, opt_sizeStats) {
219   var box = this.document_.querySelector('#volume-space-warning');
220
221   // Avoid showing two banners.
222   // TODO(kaznacheev): Unify the low space warning and the promo header.
223   if (show)
224     this.cleanupWelcomeBanner_();
225
226   if (box.hidden == !show)
227     return;
228
229   if (this.warningDismissedCounter_) {
230     if (opt_sizeStats &&
231         // Quota had not changed
232         this.warningDismissedCounter_ == opt_sizeStats.totalSize &&
233         opt_sizeStats.remainingSize / opt_sizeStats.totalSize < 0.15) {
234       // Since the last dismissal decision the quota has not changed AND
235       // the user did not free up significant space. Obey the dismissal.
236       show = false;
237     } else {
238       // Forget the dismissal. Warning will be shown again.
239       this.setWarningDismissedCounter_(0);
240     }
241   }
242
243   box.textContent = '';
244   if (show && opt_sizeStats) {
245     var icon = this.document_.createElement('div');
246     icon.className = 'drive-icon';
247     box.appendChild(icon);
248
249     var text = this.document_.createElement('div');
250     text.className = 'drive-text';
251     text.textContent = strf('DRIVE_SPACE_AVAILABLE_LONG',
252         util.bytesToString(opt_sizeStats.remainingSize));
253     box.appendChild(text);
254
255     var link = this.document_.createElement('a');
256     link.className = 'plain-link';
257     link.textContent = str('DRIVE_BUY_MORE_SPACE_LINK');
258     link.href = str('GOOGLE_DRIVE_BUY_STORAGE_URL');
259     link.target = '_blank';
260     box.appendChild(link);
261
262     var close = this.document_.createElement('div');
263     close.className = 'cr-dialog-close';
264     box.appendChild(close);
265     close.addEventListener('click', function(total) {
266       var values = {};
267       values[WARNING_DISMISSED_KEY] = total;
268       chrome.storage.local.set(values);
269       box.hidden = true;
270       this.requestRelayout_(100);
271     }.bind(this, opt_sizeStats.totalSize));
272   }
273
274   if (box.hidden != !show) {
275     box.hidden = !show;
276     this.requestRelayout_(100);
277   }
278 };
279 /**
280  * Closes the Drive Welcome banner.
281  * @private
282  */
283 FileListBannerController.prototype.closeWelcomeBanner_ = function() {
284   this.cleanupWelcomeBanner_();
285   // Stop showing the welcome banner.
286   this.setWelcomeHeaderCounter_(WELCOME_HEADER_COUNTER_LIMIT);
287 };
288
289 /**
290  * Shows or hides the welcome banner for drive.
291  * @private
292  */
293 FileListBannerController.prototype.checkSpaceAndMaybeShowWelcomeBanner_ =
294     function() {
295   if (!this.isOnCurrentProfileDrive()) {
296     // We are not on the drive file system. Do not show (close) the welcome
297     // banner.
298     this.cleanupWelcomeBanner_();
299     this.previousDirWasOnDrive_ = false;
300     return;
301   }
302
303   var driveVolume = this.volumeManager_.getCurrentProfileVolumeInfo(
304       VolumeManagerCommon.VolumeType.DRIVE);
305   if (this.welcomeHeaderCounter_ >= WELCOME_HEADER_COUNTER_LIMIT ||
306       !driveVolume || driveVolume.error) {
307     // The banner is already shown enough times or the drive FS is not mounted.
308     // So, do nothing here.
309     return;
310   }
311
312   if (!this.showOffers_) {
313     // Because it is not necessary to show the offer, set
314     // |usePromoWelcomeBanner_| false here. Note that it probably should be able
315     // to do this in the constructor, but there remains non-trivial path,
316     // which may be causes |usePromoWelcomeBanner_| == true's behavior even
317     // if |showOffers_| is false.
318     // TODO(hidehiko): Make sure if it is expected or not, and simplify
319     // |showOffers_| if possible.
320     this.usePromoWelcomeBanner_ = false;
321   }
322
323   // Perform asynchronous tasks in parallel.
324   var group = new AsyncUtil.Group();
325
326   // Choose the offer basing on the board name. The default one is 100 GB.
327   var offerSize = 100;  // In GB.
328   var offerServiceId = 'drive.cros.echo.1';
329
330   if (util.boardIs('link')) {
331     offerSize = 1024;  // 1 TB.
332     offerServiceId = 'drive.cros.echo.2';
333   }
334
335   // If the offer has been checked, then do not show the promo anymore.
336   group.add(function(onCompleted) {
337     chrome.echoPrivate.getOfferInfo(offerServiceId, function(offerInfo) {
338       // If the offer has not been checked, then an error is raised.
339       if (!chrome.runtime.lastError)
340         this.usePromoWelcomeBanner_ = false;
341       onCompleted();
342     }.bind(this));
343   }.bind(this));
344
345   if (this.usePromoWelcomeBanner_) {
346     // getSizeStats for Drive file system accesses to the server, so we should
347     // minimize the invocation.
348     group.add(function(onCompleted) {
349       // Current directory must be set, since this code is called after
350       // scanning is completed. However, the volumeInfo may be gone.
351       chrome.fileManagerPrivate.getSizeStats(
352           driveVolume.volumeId,
353           function(result) {
354             if (result && result.totalSize >= offerSize * 1024 * 1024 * 1024)
355               this.usePromoWelcomeBanner_ = false;
356             onCompleted();
357           }.bind(this));
358     }.bind(this));
359   }
360
361   group.run(this.maybeShowWelcomeBanner_.bind(this));
362 };
363
364 /**
365  * Decides which banner should be shown, and show it. This method is designed
366  * to be called only from checkSpaceAndMaybeShowWelcomeBanner_.
367  * @private
368  */
369 FileListBannerController.prototype.maybeShowWelcomeBanner_ = function() {
370   if (this.directoryModel_.getFileList().length == 0 &&
371       this.welcomeHeaderCounter_ == 0) {
372     // Only show the full page banner if the header banner was never shown.
373     // Do not increment the counter.
374     // The timeout below is required because sometimes another
375     // 'rescan-completed' event arrives shortly with non-empty file list.
376     setTimeout(function() {
377       if (this.isOnCurrentProfileDrive() && this.welcomeHeaderCounter_ == 0) {
378         this.prepareAndShowWelcomeBanner_('page', 'DRIVE_WELCOME_TEXT_LONG');
379       }
380     }.bind(this), 2000);
381   } else {
382     // We do not want to increment the counter when the user navigates
383     // between different directories on Drive, but we increment the counter
384     // once anyway to prevent the full page banner from showing.
385     if (!this.previousDirWasOnDrive_ || this.welcomeHeaderCounter_ == 0) {
386       this.setWelcomeHeaderCounter_(this.welcomeHeaderCounter_ + 1);
387       this.prepareAndShowWelcomeBanner_('header', 'DRIVE_WELCOME_TEXT_SHORT');
388     }
389   }
390   this.previousDirWasOnDrive_ = true;
391 };
392
393 /**
394  * @return {boolean} True if current directory is on Drive root of current
395  * profile.
396  */
397 FileListBannerController.prototype.isOnCurrentProfileDrive = function() {
398   var entry = this.directoryModel_.getCurrentDirEntry();
399   if (!entry || util.isFakeEntry(entry))
400     return false;
401   var locationInfo = this.volumeManager_.getLocationInfo(entry);
402   if (!locationInfo)
403     return false;
404   return locationInfo.rootType === VolumeManagerCommon.RootType.DRIVE &&
405          locationInfo.volumeInfo.profile.isCurrentProfile;
406 };
407
408 /**
409  * Shows the Drive Welcome banner.
410  * @param {string} type 'page'|'head'|'none'.
411  * @private
412  */
413 FileListBannerController.prototype.showWelcomeBanner_ = function(type) {
414   var container = this.document_.querySelector('.dialog-container');
415   if (container.getAttribute('drive-welcome') != type) {
416     container.setAttribute('drive-welcome', type);
417     this.requestRelayout_(200);  // Resize only after the animation is done.
418   }
419 };
420
421 /**
422  * Update the UI when the current directory changes.
423  *
424  * @param {Event} event The directory-changed event.
425  * @private
426  */
427 FileListBannerController.prototype.onDirectoryChanged_ = function(event) {
428   var rootVolume = this.volumeManager_.getVolumeInfo(event.newDirEntry);
429   var previousRootVolume = event.previousDirEntry ?
430       this.volumeManager_.getVolumeInfo(event.previousDirEntry) : null;
431
432   // Show (or hide) the low space warning.
433   this.maybeShowLowSpaceWarning_(rootVolume);
434
435   // Add or remove listener to show low space warning, if necessary.
436   var isLowSpaceWarningTarget = this.isLowSpaceWarningTarget_(rootVolume);
437   if (isLowSpaceWarningTarget !==
438       this.isLowSpaceWarningTarget_(previousRootVolume)) {
439     if (isLowSpaceWarningTarget) {
440       chrome.fileManagerPrivate.onDirectoryChanged.addListener(
441           this.privateOnDirectoryChangedBound_);
442     } else {
443       chrome.fileManagerPrivate.onDirectoryChanged.removeListener(
444           this.privateOnDirectoryChangedBound_);
445     }
446   }
447
448   if (!this.isOnCurrentProfileDrive()) {
449     this.cleanupWelcomeBanner_();
450     this.authFailedBanner_.hidden = true;
451   }
452
453   this.updateDriveUnmountedPanel_();
454   if (this.isOnCurrentProfileDrive()) {
455     this.unmountedPanel_.classList.remove('retry-enabled');
456     this.maybeShowAuthFailBanner_();
457   }
458 };
459
460 /**
461  * @param {VolumeInfo} volumeInfo Volume info to be checked.
462  * @return {boolean} true if the file system specified by |root| is a target
463  *     to show low space warning. Otherwise false.
464  * @private
465  */
466 FileListBannerController.prototype.isLowSpaceWarningTarget_ =
467     function(volumeInfo) {
468   if (!volumeInfo)
469     return false;
470   return volumeInfo.profile.isCurrentProfile &&
471          (volumeInfo.volumeType === VolumeManagerCommon.VolumeType.DOWNLOADS ||
472           volumeInfo.volumeType === VolumeManagerCommon.VolumeType.DRIVE);
473 };
474
475 /**
476  * Callback which is invoked when the file system has been changed.
477  * @param {Object} event chrome.fileManagerPrivate.onDirectoryChanged event.
478  * @private
479  */
480 FileListBannerController.prototype.privateOnDirectoryChanged_ = function(
481     event) {
482   if (!this.directoryModel_.getCurrentDirEntry())
483     return;
484
485   var currentDirEntry = this.directoryModel_.getCurrentDirEntry();
486   var currentVolume = currentDirEntry &&
487       this.volumeManager_.getVolumeInfo(currentDirEntry);
488   var eventVolume = this.volumeManager_.getVolumeInfo(event.entry);
489   if (currentVolume === eventVolume) {
490     // The file system we are currently on is changed.
491     // So, check the free space.
492     this.maybeShowLowSpaceWarning_(currentVolume);
493   }
494 };
495
496 /**
497  * Shows or hides the low space warning.
498  * @param {VolumeInfo} volume Type of volume, which we are interested in.
499  * @private
500  */
501 FileListBannerController.prototype.maybeShowLowSpaceWarning_ = function(
502     volume) {
503   // TODO(kaznacheev): Unify the two low space warning.
504   var threshold = 0;
505   switch (volume.volumeType) {
506     case VolumeManagerCommon.VolumeType.DOWNLOADS:
507       this.showLowDriveSpaceWarning_(false);
508       threshold = 0.2;
509       break;
510     case VolumeManagerCommon.VolumeType.DRIVE:
511       this.showLowDownloadsSpaceWarning_(false);
512       threshold = 0.1;
513       break;
514     default:
515       // If the current file system is neither the DOWNLOAD nor the DRIVE,
516       // just hide the warning.
517       this.showLowDownloadsSpaceWarning_(false);
518       this.showLowDriveSpaceWarning_(false);
519       return;
520   }
521
522   // If not mounted correctly, then do not continue.
523   if (!volume.fileSystem)
524     return;
525
526   chrome.fileManagerPrivate.getSizeStats(
527       volume.volumeId,
528       function(sizeStats) {
529         var currentVolume = this.volumeManager_.getVolumeInfo(
530             this.directoryModel_.getCurrentDirEntry());
531         if (volume !== currentVolume) {
532           // This happens when the current directory is moved during requesting
533           // the file system size. Just ignore it.
534           return;
535         }
536         // sizeStats is undefined, if some error occurs.
537         if (!sizeStats || sizeStats.totalSize == 0)
538           return;
539
540         var remainingRatio = sizeStats.remainingSize / sizeStats.totalSize;
541         var isLowDiskSpace = remainingRatio < threshold;
542         if (volume.volumeType === VolumeManagerCommon.VolumeType.DOWNLOADS)
543           this.showLowDownloadsSpaceWarning_(isLowDiskSpace);
544         else
545           this.showLowDriveSpaceWarning_(isLowDiskSpace, sizeStats);
546       }.bind(this));
547 };
548
549 /**
550  * removes the Drive Welcome banner.
551  * @private
552  */
553 FileListBannerController.prototype.cleanupWelcomeBanner_ = function() {
554   this.showWelcomeBanner_('none');
555 };
556
557 /**
558  * Notifies the file manager what layout must be recalculated.
559  * @param {number} delay In milliseconds.
560  * @private
561  */
562 FileListBannerController.prototype.requestRelayout_ = function(delay) {
563   var self = this;
564   setTimeout(function() {
565     cr.dispatchSimpleEvent(self, 'relayout');
566   }, delay);
567 };
568
569 /**
570  * Show or hide the "Low disk space" warning.
571  * @param {boolean} show True if the box need to be shown.
572  * @private
573  */
574 FileListBannerController.prototype.showLowDownloadsSpaceWarning_ =
575     function(show) {
576   var box = this.document_.querySelector('.downloads-warning');
577
578   if (box.hidden == !show) return;
579
580   if (show) {
581     var html = util.htmlUnescape(str('DOWNLOADS_DIRECTORY_WARNING'));
582     box.innerHTML = html;
583     box.querySelector('a').addEventListener('click', function(e) {
584       util.visitURL(str('DOWNLOADS_LOW_SPACE_WARNING_HELP_URL'));
585       e.preventDefault();
586     });
587   } else {
588     box.innerHTML = '';
589   }
590
591   box.hidden = !show;
592   this.requestRelayout_(100);
593 };
594
595 /**
596  * Creates contents for the DRIVE unmounted panel.
597  * @private
598  */
599 FileListBannerController.prototype.ensureDriveUnmountedPanelInitialized_ =
600     function() {
601   var panel = this.unmountedPanel_;
602   if (panel.firstElementChild)
603     return;
604
605   /**
606    * Creates an element using given parameters.
607    * @param {!Element} parent Parent element of the new element.
608    * @param {string} tag Tag of the new element.
609    * @param {string} className Class name of the new element.
610    * @param {string=} opt_textContent Text content of the new element.
611    * @return {!Element} The newly created element.
612    */
613   var create = function(parent, tag, className, opt_textContent) {
614     var div = panel.ownerDocument.createElement(tag);
615     div.className = className;
616     div.textContent = opt_textContent || '';
617     parent.appendChild(div);
618     return div;
619   };
620
621   var loading = create(panel, 'div', 'loading', str('DRIVE_LOADING'));
622   var spinnerBox = create(loading, 'div', 'spinner-box');
623   create(spinnerBox, 'div', 'spinner');
624   create(panel, 'div', 'error', str('DRIVE_CANNOT_REACH'));
625
626   var learnMore = create(panel, 'a', 'learn-more plain-link',
627                          str('DRIVE_LEARN_MORE'));
628   learnMore.href = str('GOOGLE_DRIVE_ERROR_HELP_URL');
629   learnMore.target = '_blank';
630 };
631
632 /**
633  * Called when volume info list is updated.
634  * @param {Event} event Splice event data on volume info list.
635  * @private
636  */
637 FileListBannerController.prototype.onVolumeInfoListSplice_ = function(event) {
638   var isDriveVolume = function(volumeInfo) {
639     return volumeInfo.volumeType === VolumeManagerCommon.VolumeType.DRIVE;
640   };
641   if (event.removed.some(isDriveVolume) || event.added.some(isDriveVolume))
642     this.updateDriveUnmountedPanel_();
643 };
644
645 /**
646  * Shows the panel when current directory is DRIVE and it's unmounted.
647  * Hides it otherwise. The panel shows spinner if DRIVE is mounting or
648  * an error message if it failed.
649  * @private
650  */
651 FileListBannerController.prototype.updateDriveUnmountedPanel_ = function() {
652   var node = this.document_.body;
653   if (this.isOnCurrentProfileDrive()) {
654     var driveVolume = this.volumeManager_.getCurrentProfileVolumeInfo(
655         VolumeManagerCommon.VolumeType.DRIVE);
656     if (driveVolume && driveVolume.error) {
657       this.ensureDriveUnmountedPanelInitialized_();
658       this.unmountedPanel_.classList.add('retry-enabled');
659     } else {
660       this.unmountedPanel_.classList.remove('retry-enabled');
661     }
662     node.setAttribute('drive', status);
663   } else {
664     node.removeAttribute('drive');
665   }
666 };
667
668 /**
669  * Updates the visibility of Drive Connection Warning banner, retrieving the
670  * current connection information.
671  * @private
672  */
673 FileListBannerController.prototype.maybeShowAuthFailBanner_ = function() {
674   var connection = this.volumeManager_.getDriveConnectionState();
675   var showDriveNotReachedMessage =
676       this.isOnCurrentProfileDrive() &&
677       connection.type == VolumeManagerCommon.DriveConnectionType.OFFLINE &&
678       connection.reason == VolumeManagerCommon.DriveConnectionReason.NOT_READY;
679   this.authFailedBanner_.hidden = !showDriveNotReachedMessage;
680 };