Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / ui / file_manager / file_manager / foreground / js / 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 'use strict';
6
7 /**
8  * Responsible for showing following banners in the file list.
9  *  - WelcomeBanner
10  *  - AuthFailBanner
11  * @param {DirectoryModel} directoryModel The model.
12  * @param {VolumeManagerWrapper} volumeManager The manager.
13  * @param {DOMDocument} document HTML document.
14  * @param {boolean} showOffers True if we should show offer banners.
15  * @constructor
16  */
17 function FileListBannerController(
18     directoryModel, volumeManager, document, showOffers) {
19   this.directoryModel_ = directoryModel;
20   this.volumeManager_ = volumeManager;
21   this.document_ = document;
22   this.showOffers_ = showOffers;
23   this.driveEnabled_ = false;
24
25   this.initializeWelcomeBanner_();
26   this.privateOnDirectoryChangedBound_ =
27       this.privateOnDirectoryChanged_.bind(this);
28
29   var handler = this.checkSpaceAndMaybeShowWelcomeBanner_.bind(this);
30   this.directoryModel_.addEventListener('scan-completed', handler);
31   this.directoryModel_.addEventListener('rescan-completed', handler);
32   this.directoryModel_.addEventListener('directory-changed',
33       this.onDirectoryChanged_.bind(this));
34
35   this.unmountedPanel_ = this.document_.querySelector('#unmounted-panel');
36   this.volumeManager_.volumeInfoList.addEventListener(
37       'splice', this.onVolumeInfoListSplice_.bind(this));
38   this.volumeManager_.addEventListener('drive-connection-changed',
39       this.onDriveConnectionChanged_.bind(this));
40
41   chrome.storage.onChanged.addListener(this.onStorageChange_.bind(this));
42   this.welcomeHeaderCounter_ = WELCOME_HEADER_COUNTER_LIMIT;
43   this.warningDismissedCounter_ = 0;
44   chrome.storage.local.get(
45       [WELCOME_HEADER_COUNTER_KEY, WARNING_DISMISSED_KEY],
46       function(values) {
47         this.welcomeHeaderCounter_ =
48             parseInt(values[WELCOME_HEADER_COUNTER_KEY]) || 0;
49         this.warningDismissedCounter_ =
50             parseInt(values[WARNING_DISMISSED_KEY]) || 0;
51       }.bind(this));
52
53   this.authFailedBanner_ =
54       this.document_.querySelector('#drive-auth-failed-warning');
55   var authFailedText = this.authFailedBanner_.querySelector('.drive-text');
56   authFailedText.innerHTML = util.htmlUnescape(str('DRIVE_NOT_REACHED'));
57   authFailedText.querySelector('a').addEventListener('click', function(e) {
58     chrome.fileManagerPrivate.logoutUserForReauthentication();
59     e.preventDefault();
60   });
61   this.maybeShowAuthFailBanner_();
62 }
63
64 /**
65  * FileListBannerController extends cr.EventTarget.
66  */
67 FileListBannerController.prototype.__proto__ = cr.EventTarget.prototype;
68
69 /**
70  * Key in localStorage to keep number of times the Drive Welcome
71  * banner has shown.
72  */
73 var WELCOME_HEADER_COUNTER_KEY = 'driveWelcomeHeaderCounter';
74
75 // If the warning was dismissed before, this key stores the quota value
76 // (as of the moment of dismissal).
77 // If the warning was never dismissed or was reset this key stores 0.
78 var WARNING_DISMISSED_KEY = 'driveSpaceWarningDismissed';
79
80 /**
81  * Maximum times Drive Welcome banner could have shown.
82  */
83 var WELCOME_HEADER_COUNTER_LIMIT = 25;
84
85 /**
86  * Initializes the banner to promote DRIVE.
87  * This method must be called before any of showing banner functions, and
88  * also before registering them as callbacks.
89  * @private
90  */
91 FileListBannerController.prototype.initializeWelcomeBanner_ = function() {
92   this.usePromoWelcomeBanner_ = !util.boardIs('x86-mario') &&
93                                 !util.boardIs('x86-zgb') &&
94                                 !util.boardIs('x86-alex');
95 };
96
97 /**
98  * @param {number} value How many times the Drive Welcome header banner
99  * has shown.
100  * @private
101  */
102 FileListBannerController.prototype.setWelcomeHeaderCounter_ = function(value) {
103   var values = {};
104   values[WELCOME_HEADER_COUNTER_KEY] = value;
105   chrome.storage.local.set(values);
106 };
107
108 /**
109  * @param {number} value How many times the low space warning has dismissed.
110  * @private
111  */
112 FileListBannerController.prototype.setWarningDismissedCounter_ =
113     function(value) {
114   var values = {};
115   values[WARNING_DISMISSED_KEY] = value;
116   chrome.storage.local.set(values);
117 };
118
119 /**
120  * chrome.storage.onChanged event handler.
121  * @param {Object.<string, Object>} changes Changes values.
122  * @param {string} areaName "local" or "sync".
123  * @private
124  */
125 FileListBannerController.prototype.onStorageChange_ = function(changes,
126                                                                areaName) {
127   if (areaName == 'local' && WELCOME_HEADER_COUNTER_KEY in changes) {
128     this.welcomeHeaderCounter_ = changes[WELCOME_HEADER_COUNTER_KEY].newValue;
129   }
130   if (areaName == 'local' && WARNING_DISMISSED_KEY in changes) {
131     this.warningDismissedCounter_ = changes[WARNING_DISMISSED_KEY].newValue;
132   }
133 };
134
135 /**
136  * Invoked when the drive connection status is change in the volume manager.
137  * @private
138  */
139 FileListBannerController.prototype.onDriveConnectionChanged_ = function() {
140   this.maybeShowAuthFailBanner_();
141 };
142
143 /**
144  * @param {string} type 'none'|'page'|'header'.
145  * @param {string} messageId Resource ID of the message.
146  * @private
147  */
148 FileListBannerController.prototype.prepareAndShowWelcomeBanner_ =
149     function(type, messageId) {
150   this.showWelcomeBanner_(type);
151
152   var container = this.document_.querySelector('.drive-welcome.' + type);
153   if (container.firstElementChild)
154     return;  // Do not re-create.
155
156   if (!this.document_.querySelector('link[drive-welcome-style]')) {
157     var style = this.document_.createElement('link');
158     style.rel = 'stylesheet';
159     style.href = 'foreground/css/drive_welcome.css';
160     style.setAttribute('drive-welcome-style', '');
161     this.document_.head.appendChild(style);
162   }
163
164   var wrapper = util.createChild(container, 'drive-welcome-wrapper');
165   util.createChild(wrapper, 'drive-welcome-icon');
166
167   var close = util.createChild(wrapper, 'cr-dialog-close');
168   close.addEventListener('click', this.closeWelcomeBanner_.bind(this));
169
170   var message = util.createChild(wrapper, 'drive-welcome-message');
171
172   var title = util.createChild(message, 'drive-welcome-title');
173
174   var text = util.createChild(message, 'drive-welcome-text');
175   text.innerHTML = str(messageId);
176
177   var links = util.createChild(message, 'drive-welcome-links');
178
179   var more;
180   if (this.usePromoWelcomeBanner_) {
181     var welcomeTitle = str('DRIVE_WELCOME_TITLE_ALTERNATIVE');
182     if (util.boardIs('link'))
183       welcomeTitle = str('DRIVE_WELCOME_TITLE_ALTERNATIVE_1TB');
184     title.textContent = welcomeTitle;
185     more = util.createChild(links,
186         'drive-welcome-button drive-welcome-start', 'a');
187     more.textContent = str('DRIVE_WELCOME_CHECK_ELIGIBILITY');
188     more.href = str('GOOGLE_DRIVE_REDEEM_URL');
189   } else {
190     title.textContent = str('DRIVE_WELCOME_TITLE');
191     more = util.createChild(links, 'plain-link', 'a');
192     more.textContent = str('DRIVE_LEARN_MORE');
193     more.href = str('GOOGLE_DRIVE_OVERVIEW_URL');
194   }
195   more.tabIndex = '16';  // See: go/filesapp-tabindex.
196   more.target = '_blank';
197
198   var dismiss;
199   if (this.usePromoWelcomeBanner_)
200     dismiss = util.createChild(links, 'drive-welcome-button');
201   else
202     dismiss = util.createChild(links, 'plain-link');
203
204   dismiss.classList.add('drive-welcome-dismiss');
205   dismiss.textContent = str('DRIVE_WELCOME_DISMISS');
206   dismiss.addEventListener('click', this.closeWelcomeBanner_.bind(this));
207
208   this.previousDirWasOnDrive_ = false;
209 };
210
211 /**
212  * Show or hide the "Low Google Drive space" warning.
213  * @param {boolean} show True if the box need to be shown.
214  * @param {Object} sizeStats Size statistics. Should be defined when showing the
215  *     warning.
216  * @private
217  */
218 FileListBannerController.prototype.showLowDriveSpaceWarning_ =
219     function(show, sizeStats) {
220   var box = this.document_.querySelector('#volume-space-warning');
221
222   // Avoid showing two banners.
223   // TODO(kaznacheev): Unify the low space warning and the promo header.
224   if (show)
225     this.cleanupWelcomeBanner_();
226
227   if (box.hidden == !show)
228     return;
229
230   if (this.warningDismissedCounter_) {
231     if (this.warningDismissedCounter_ ==
232             sizeStats.totalSize && // Quota had not changed
233         sizeStats.remainingSize / 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) {
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(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, 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   return locationInfo &&
403       locationInfo.rootType === VolumeManagerCommon.RootType.DRIVE &&
404       locationInfo.volumeInfo.profile.isCurrentProfile;
405 };
406
407 /**
408  * Shows the Drive Welcome banner.
409  * @param {string} type 'page'|'head'|'none'.
410  * @private
411  */
412 FileListBannerController.prototype.showWelcomeBanner_ = function(type) {
413   var container = this.document_.querySelector('.dialog-container');
414   if (container.getAttribute('drive-welcome') != type) {
415     container.setAttribute('drive-welcome', type);
416     this.requestRelayout_(200);  // Resize only after the animation is done.
417   }
418 };
419
420 /**
421  * Update the UI when the current directory changes.
422  *
423  * @param {Event} event The directory-changed event.
424  * @private
425  */
426 FileListBannerController.prototype.onDirectoryChanged_ = function(event) {
427   var rootVolume = this.volumeManager_.getVolumeInfo(event.newDirEntry);
428   var previousRootVolume = event.previousDirEntry ?
429       this.volumeManager_.getVolumeInfo(event.previousDirEntry) : null;
430
431   // Show (or hide) the low space warning.
432   this.maybeShowLowSpaceWarning_(rootVolume);
433
434   // Add or remove listener to show low space warning, if necessary.
435   var isLowSpaceWarningTarget = this.isLowSpaceWarningTarget_(rootVolume);
436   if (isLowSpaceWarningTarget !==
437       this.isLowSpaceWarningTarget_(previousRootVolume)) {
438     if (isLowSpaceWarningTarget) {
439       chrome.fileManagerPrivate.onDirectoryChanged.addListener(
440           this.privateOnDirectoryChangedBound_);
441     } else {
442       chrome.fileManagerPrivate.onDirectoryChanged.removeListener(
443           this.privateOnDirectoryChangedBound_);
444     }
445   }
446
447   if (!this.isOnCurrentProfileDrive()) {
448     this.cleanupWelcomeBanner_();
449     this.authFailedBanner_.hidden = true;
450   }
451
452   this.updateDriveUnmountedPanel_();
453   if (this.isOnCurrentProfileDrive()) {
454     this.unmountedPanel_.classList.remove('retry-enabled');
455     this.maybeShowAuthFailBanner_();
456   }
457 };
458
459 /**
460  * @param {VolumeInfo} volumeInfo Volume info to be checked.
461  * @return {boolean} true if the file system specified by |root| is a target
462  *     to show low space warning. Otherwise false.
463  * @private
464  */
465 FileListBannerController.prototype.isLowSpaceWarningTarget_ =
466     function(volumeInfo) {
467   return volumeInfo &&
468       volumeInfo.profile.isCurrentProfile &&
469       (volumeInfo.volumeType === VolumeManagerCommon.VolumeType.DOWNLOADS ||
470        volumeInfo.volumeType === VolumeManagerCommon.VolumeType.DRIVE);
471 };
472
473 /**
474  * Callback which is invoked when the file system has been changed.
475  * @param {Object} event chrome.fileManagerPrivate.onDirectoryChanged event.
476  * @private
477  */
478 FileListBannerController.prototype.privateOnDirectoryChanged_ = function(
479     event) {
480   if (!this.directoryModel_.getCurrentDirEntry())
481     return;
482
483   var currentDirEntry = this.directoryModel_.getCurrentDirEntry();
484   var currentVolume = currentDirEntry &&
485       this.volumeManager_.getVolumeInfo(currentDirEntry);
486   var eventVolume = this.volumeManager_.getVolumeInfo(event.entry);
487   if (currentVolume === eventVolume) {
488     // The file system we are currently on is changed.
489     // So, check the free space.
490     this.maybeShowLowSpaceWarning_(currentVolume);
491   }
492 };
493
494 /**
495  * Shows or hides the low space warning.
496  * @param {VolumeInfo} volume Type of volume, which we are interested in.
497  * @private
498  */
499 FileListBannerController.prototype.maybeShowLowSpaceWarning_ = function(
500     volume) {
501   // TODO(kaznacheev): Unify the two low space warning.
502   var threshold = 0;
503   switch (volume.volumeType) {
504     case VolumeManagerCommon.VolumeType.DOWNLOADS:
505       this.showLowDriveSpaceWarning_(false);
506       threshold = 0.2;
507       break;
508     case VolumeManagerCommon.VolumeType.DRIVE:
509       this.showLowDownloadsSpaceWarning_(false);
510       threshold = 0.1;
511       break;
512     default:
513       // If the current file system is neither the DOWNLOAD nor the DRIVE,
514       // just hide the warning.
515       this.showLowDownloadsSpaceWarning_(false);
516       this.showLowDriveSpaceWarning_(false);
517       return;
518   }
519
520   // If not mounted correctly, then do not continue.
521   if (!volume.fileSystem)
522     return;
523
524   chrome.fileManagerPrivate.getSizeStats(
525       volume.volumeId,
526       function(sizeStats) {
527         var currentVolume = this.volumeManager_.getVolumeInfo(
528             this.directoryModel_.getCurrentDirEntry());
529         if (volume !== currentVolume) {
530           // This happens when the current directory is moved during requesting
531           // the file system size. Just ignore it.
532           return;
533         }
534         // sizeStats is undefined, if some error occurs.
535         if (!sizeStats || sizeStats.totalSize == 0)
536           return;
537
538         var remainingRatio = sizeStats.remainingSize / sizeStats.totalSize;
539         var isLowDiskSpace = remainingRatio < threshold;
540         if (volume.volumeType === VolumeManagerCommon.VolumeType.DOWNLOADS)
541           this.showLowDownloadsSpaceWarning_(isLowDiskSpace);
542         else
543           this.showLowDriveSpaceWarning_(isLowDiskSpace, sizeStats);
544       }.bind(this));
545 };
546
547 /**
548  * removes the Drive Welcome banner.
549  * @private
550  */
551 FileListBannerController.prototype.cleanupWelcomeBanner_ = function() {
552   this.showWelcomeBanner_('none');
553 };
554
555 /**
556  * Notifies the file manager what layout must be recalculated.
557  * @param {number} delay In milliseconds.
558  * @private
559  */
560 FileListBannerController.prototype.requestRelayout_ = function(delay) {
561   var self = this;
562   setTimeout(function() {
563     cr.dispatchSimpleEvent(self, 'relayout');
564   }, delay);
565 };
566
567 /**
568  * Show or hide the "Low disk space" warning.
569  * @param {boolean} show True if the box need to be shown.
570  * @private
571  */
572 FileListBannerController.prototype.showLowDownloadsSpaceWarning_ =
573     function(show) {
574   var box = this.document_.querySelector('.downloads-warning');
575
576   if (box.hidden == !show) return;
577
578   if (show) {
579     var html = util.htmlUnescape(str('DOWNLOADS_DIRECTORY_WARNING'));
580     box.innerHTML = html;
581     box.querySelector('a').addEventListener('click', function(e) {
582       util.visitURL(str('DOWNLOADS_LOW_SPACE_WARNING_HELP_URL'));
583       e.preventDefault();
584     });
585   } else {
586     box.innerHTML = '';
587   }
588
589   box.hidden = !show;
590   this.requestRelayout_(100);
591 };
592
593 /**
594  * Creates contents for the DRIVE unmounted panel.
595  * @private
596  */
597 FileListBannerController.prototype.ensureDriveUnmountedPanelInitialized_ =
598     function() {
599   var panel = this.unmountedPanel_;
600   if (panel.firstElementChild)
601     return;
602
603   var create = function(parent, tag, className, opt_textContent) {
604     var div = panel.ownerDocument.createElement(tag);
605     div.className = className;
606     div.textContent = opt_textContent || '';
607     parent.appendChild(div);
608     return div;
609   };
610
611   var loading = create(panel, 'div', 'loading', str('DRIVE_LOADING'));
612   var spinnerBox = create(loading, 'div', 'spinner-box');
613   create(spinnerBox, 'div', 'spinner');
614   create(panel, 'div', 'error', str('DRIVE_CANNOT_REACH'));
615
616   var learnMore = create(panel, 'a', 'learn-more plain-link',
617                          str('DRIVE_LEARN_MORE'));
618   learnMore.href = str('GOOGLE_DRIVE_ERROR_HELP_URL');
619   learnMore.target = '_blank';
620 };
621
622 /**
623  * Called when volume info list is updated.
624  * @param {Event} event Splice event data on volume info list.
625  * @private
626  */
627 FileListBannerController.prototype.onVolumeInfoListSplice_ = function(event) {
628   var isDriveVolume = function(volumeInfo) {
629     return volumeInfo.volumeType === VolumeManagerCommon.VolumeType.DRIVE;
630   };
631   if (event.removed.some(isDriveVolume) || event.added.some(isDriveVolume))
632     this.updateDriveUnmountedPanel_();
633 };
634
635 /**
636  * Shows the panel when current directory is DRIVE and it's unmounted.
637  * Hides it otherwise. The panel shows spinner if DRIVE is mounting or
638  * an error message if it failed.
639  * @private
640  */
641 FileListBannerController.prototype.updateDriveUnmountedPanel_ = function() {
642   var node = this.document_.body;
643   if (this.isOnCurrentProfileDrive()) {
644     var driveVolume = this.volumeManager_.getCurrentProfileVolumeInfo(
645         VolumeManagerCommon.VolumeType.DRIVE);
646     if (driveVolume && driveVolume.error) {
647       this.ensureDriveUnmountedPanelInitialized_();
648       this.unmountedPanel_.classList.add('retry-enabled');
649     } else {
650       this.unmountedPanel_.classList.remove('retry-enabled');
651     }
652     node.setAttribute('drive', status);
653   } else {
654     node.removeAttribute('drive');
655   }
656 };
657
658 /**
659  * Updates the visibility of Drive Connection Warning banner, retrieving the
660  * current connection information.
661  * @private
662  */
663 FileListBannerController.prototype.maybeShowAuthFailBanner_ = function() {
664   var connection = this.volumeManager_.getDriveConnectionState();
665   var showDriveNotReachedMessage =
666       this.isOnCurrentProfileDrive() &&
667       connection.type == VolumeManagerCommon.DriveConnectionType.OFFLINE &&
668       connection.reason == VolumeManagerCommon.DriveConnectionReason.NOT_READY;
669   this.authFailedBanner_.hidden = !showDriveNotReachedMessage;
670 };