diff options
author | kaznacheev@chromium.org <kaznacheev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-18 17:02:21 +0000 |
---|---|---|
committer | kaznacheev@chromium.org <kaznacheev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-18 17:02:21 +0000 |
commit | b10ff6aa7fb3d5a3d31d5c1552e330ace58c3614 (patch) | |
tree | 5950bfa6c4cb8f0678753ab3564b93e02d015499 | |
parent | 0c4b5c9d23d43a790479f8c944c8bc865bf31c09 (diff) | |
download | chromium_src-b10ff6aa7fb3d5a3d31d5c1552e330ace58c3614.zip chromium_src-b10ff6aa7fb3d5a3d31d5c1552e330ace58c3614.tar.gz chromium_src-b10ff6aa7fb3d5a3d31d5c1552e330ace58c3614.tar.bz2 |
[File Manager] Show better error message when cannot load images/play media from offline GDrive
BUG=128524
TEST=
Review URL: https://chromiumcodereview.appspot.com/10568010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@142741 0039d316-1c4b-4281-b951-d872f2087c98
7 files changed, 167 insertions, 30 deletions
diff --git a/chrome/browser/chromeos/extensions/file_browser_private_api.cc b/chrome/browser/chromeos/extensions/file_browser_private_api.cc index 3d8edbd..0215449 100644 --- a/chrome/browser/chromeos/extensions/file_browser_private_api.cc +++ b/chrome/browser/chromeos/extensions/file_browser_private_api.cc @@ -1358,6 +1358,9 @@ bool FileDialogStringsFunction::RunImpl() { SET_STRING(IDS_FILE_BROWSER, GALLERY_IMAGE_ERROR); SET_STRING(IDS_FILE_BROWSER, GALLERY_VIDEO_ERROR); SET_STRING(IDS_FILE_BROWSER, AUDIO_ERROR); + SET_STRING(IDS_FILE_BROWSER, GALLERY_IMAGE_OFFLINE); + SET_STRING(IDS_FILE_BROWSER, GALLERY_VIDEO_OFFLINE); + SET_STRING(IDS_FILE_BROWSER, AUDIO_OFFLINE); // Reusing the string, but with alias starting with GALLERY. dict->SetString("GALLERY_FILE_HIDDEN_NAME", l10n_util::GetStringUTF16(IDS_FILE_BROWSER_ERROR_HIDDEN_NAME)); diff --git a/chrome/browser/resources/file_manager/js/image_editor/gallery.js b/chrome/browser/resources/file_manager/js/image_editor/gallery.js index a75ef93..d6ce88e 100644 --- a/chrome/browser/resources/file_manager/js/image_editor/gallery.js +++ b/chrome/browser/resources/file_manager/js/image_editor/gallery.js @@ -605,6 +605,8 @@ Gallery.prototype.openImage = function(id, url, metadata, slide, callback) { self.showSpinner_(false); if (loadType == ImageView.LOAD_TYPE_ERROR) { self.showErrorBanner_(video? 'VIDEO_ERROR' : 'IMAGE_ERROR'); + } else if (loadType = ImageView.LOAD_TYPE_OFFLINE) { + self.showErrorBanner_(video? 'VIDEO_OFFLINE' : 'IMAGE_OFFLINE'); } if (video) { diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_view.js b/chrome/browser/resources/file_manager/js/image_editor/image_view.js index 5ba2e33..2b45387 100644 --- a/chrome/browser/resources/file_manager/js/image_editor/image_view.js +++ b/chrome/browser/resources/file_manager/js/image_editor/image_view.js @@ -89,9 +89,14 @@ ImageView.LOAD_TYPE_VIDEO_FILE = 3; ImageView.LOAD_TYPE_ERROR = 4; /** + * Image load type: the file contents is not available offline. + */ +ImageView.LOAD_TYPE_OFFLINE = 5; + +/** * The total number of load types. */ -ImageView.LOAD_TYPE_TOTAL = 5; +ImageView.LOAD_TYPE_TOTAL = 6; ImageView.prototype = {__proto__: ImageBuffer.Overlay.prototype}; @@ -438,6 +443,12 @@ ImageView.prototype.load = function( } ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('LoadMode'), loadType, ImageView.LOAD_TYPE_TOTAL); + + if (loadType == ImageView.LOAD_TYPE_ERROR && + !navigator.onLine && metadata.streaming) { + // |streaming| is set only when the file is not locally cached. + loadType = ImageView.LOAD_TYPE_OFFLINE; + } if (opt_callback) opt_callback(loadType); } }; diff --git a/chrome/browser/resources/file_manager/js/media/audio_player.js b/chrome/browser/resources/file_manager/js/media/audio_player.js index c8ff1dc..b5fe9d0 100644 --- a/chrome/browser/resources/file_manager/js/media/audio_player.js +++ b/chrome/browser/resources/file_manager/js/media/audio_player.js @@ -12,11 +12,10 @@ document.addEventListener('DOMContentLoaded', function() { }); /** - * @param {HTMLElement} container - * @param {string} filesystemRootURL + * @param {HTMLElement} container Container element. * @constructor */ -function AudioPlayer(container, filesystemRootURL) { +function AudioPlayer(container) { this.container_ = container; this.metadataCache_ = MetadataCache.createFull(); this.currentTrack_ = -1; @@ -52,18 +51,23 @@ function AudioPlayer(container, filesystemRootURL) { chrome.fileBrowserPrivate.getStrings(function(strings) { container.ownerDocument.title = strings['AUDIO_PLAYER_TITLE']; this.errorString_ = strings['AUDIO_ERROR']; + this.offlineString_ = strings['AUDIO_OFFLINE']; AudioPlayer.TrackInfo.DEFAULT_ARTIST = strings['AUDIO_PLAYER_DEFAULT_ARTIST']; }.bind(this)); } +/** + * Initial load method (static). + */ AudioPlayer.load = function() { document.ondragstart = function(e) { e.preventDefault() }; document.oncontextmenu = function(e) { e.preventDefault(); }; - chrome.fileBrowserPrivate.requestLocalFileSystem(function(filesystem) { - var player = new AudioPlayer(document.querySelector('.audio-player'), - filesystem.root.toURL()); + // If the audio player is starting before the first instance of the File + // Manager then it does not have access to filesystem URLs. Request it now. + chrome.fileBrowserPrivate.requestLocalFileSystem(function() { + var player = new AudioPlayer(document.querySelector('.audio-player')); function getPlaylist() { chrome.mediaPlayerPrivate.getPlaylist(player.load.bind(player)); } @@ -72,6 +76,10 @@ AudioPlayer.load = function() { }); }; +/** + * Load a new playlist. + * @param {Playlist} playlist Playlist object passed via mediaPlayerPrivate. + */ AudioPlayer.prototype.load = function(playlist) { this.playlistGeneration_++; @@ -119,16 +127,35 @@ AudioPlayer.prototype.load = function(playlist) { } }; +/** + * Load metadata for a track. + * @param {number} track Track number + * @private + */ AudioPlayer.prototype.loadMetadata_ = function(track) { this.fetchMetadata_( this.urls_[track], this.displayMetadata_.bind(this, track)); }; -AudioPlayer.prototype.displayMetadata_ = function(track, metadata) { - this.trackListItems_[track].setMetadata(metadata, this.container_); - this.trackStackItems_[track].setMetadata(metadata, this.container_); +/** + * Display track's metadata. + * @param {number} track Track number. + * @param {object} metadata Metadata object. + * @param {string} opt_error Error message. + * @private + */ +AudioPlayer.prototype.displayMetadata_ = function(track, metadata, opt_error) { + this.trackListItems_[track]. + setMetadata(metadata, this.container_, opt_error); + this.trackStackItems_[track]. + setMetadata(metadata, this.container_, opt_error); }; +/** + * Select a new track to play. + * @param {number} newTrack New track number. + * @private + */ AudioPlayer.prototype.select_ = function(newTrack) { if (this.currentTrack_ == newTrack) return; @@ -150,6 +177,11 @@ AudioPlayer.prototype.select_ = function(newTrack) { }.bind(this)); }; +/** + * @param {string} url Track file url. + * @param {function(object)} callback Callback. + * @private + */ AudioPlayer.prototype.fetchMetadata_ = function(url, callback) { this.metadataCache_.get(url, 'thumbnail|media|streaming', function(generation, metadata) { @@ -159,6 +191,11 @@ AudioPlayer.prototype.fetchMetadata_ = function(url, callback) { }.bind(this, this.playlistGeneration_)); }; +/** + * @param {number} oldTrack Old track number. + * @param {number} newTrack New track number. + * @private + */ AudioPlayer.prototype.changeSelectionInList_ = function(oldTrack, newTrack) { this.trackListItems_[newTrack].getBox().classList.add('selected'); @@ -167,6 +204,11 @@ AudioPlayer.prototype.changeSelectionInList_ = function(oldTrack, newTrack) { } }; +/** + * @param {number} oldTrack Old track number. + * @param {number} newTrack New track number. + * @private + */ AudioPlayer.prototype.changeSelectionInStack_ = function(oldTrack, newTrack) { var newBox = this.trackStackItems_[newTrack].getBox(); newBox.classList.add('selected'); // Put on top immediately. @@ -175,7 +217,7 @@ AudioPlayer.prototype.changeSelectionInStack_ = function(oldTrack, newTrack) { if (oldTrack >= 0) { var oldBox = this.trackStackItems_[oldTrack].getBox(); oldBox.classList.remove('selected'); // Put under immediately. - setTimeout(function () { + setTimeout(function() { if (!oldBox.classList.contains('selected')) { // This will start fading out which is not really necessary because // oldBox is already completely obscured by newBox. @@ -190,6 +232,7 @@ AudioPlayer.prototype.changeSelectionInStack_ = function(oldTrack, newTrack) { * * @param {boolean} keepAtBottom If true, make the selected track the last * of the visible (if possible). If false, perform minimal scrolling. + * @private */ AudioPlayer.prototype.scrollToCurrent_ = function(keepAtBottom) { var box = this.trackListItems_[this.currentTrack_].getBox(); @@ -198,11 +241,21 @@ AudioPlayer.prototype.scrollToCurrent_ = function(keepAtBottom) { box.offsetTop + box.offsetHeight - this.trackList_.clientHeight); }; +/** + * @return {boolean} True if the player is be displayed in compact mode. + * @private + */ AudioPlayer.prototype.isCompact_ = function() { return this.container_.classList.contains('collapsed') || this.container_.classList.contains('single-track'); }; +/** + * Go to the previous or the next track. + * @param {boolean} forward True if next, false if previous. + * @param {boolean} opt_onlyIfValid True if invalid tracks should be selected. + * @private + */ AudioPlayer.prototype.advance_ = function(forward, opt_onlyIfValid) { this.cancelAutoAdvance_(); @@ -214,6 +267,10 @@ AudioPlayer.prototype.advance_ = function(forward, opt_onlyIfValid) { this.select_(newTrack); }; +/** + * Media error handler. + * @private + */ AudioPlayer.prototype.onError_ = function() { var track = this.currentTrack_; @@ -222,13 +279,17 @@ AudioPlayer.prototype.onError_ = function() { this.fetchMetadata_( this.urls_[track], function(metadata) { - metadata.error = true; - metadata.media = { artist: this.errorString_ }; - this.displayMetadata_(track, metadata); + var error = (!navigator.onLine && metadata.streaming) ? + this.offlineString_ : this.errorString_; + this.displayMetadata_(track, metadata, error); this.scheduleAutoAdvance_(); }.bind(this)); }; +/** + * Schedule automatic advance to the next track after a timeout. + * @private + */ AudioPlayer.prototype.scheduleAutoAdvance_ = function() { this.cancelAutoAdvance_(); this.autoAdvanceTimer_ = setTimeout( @@ -242,6 +303,10 @@ AudioPlayer.prototype.scheduleAutoAdvance_ = function() { 3000); }; +/** + * Cancel the scheduled auto advance. + * @private + */ AudioPlayer.prototype.cancelAutoAdvance_ = function() { if (this.autoAdvanceTimer_) { clearTimeout(this.autoAdvanceTimer_); @@ -249,6 +314,10 @@ AudioPlayer.prototype.cancelAutoAdvance_ = function() { } }; +/** + * Expand/collapse button click handler. + * @private + */ AudioPlayer.prototype.onExpandCollapse_ = function() { this.container_.classList.toggle('collapsed'); this.syncHeight_(); @@ -257,11 +326,27 @@ AudioPlayer.prototype.onExpandCollapse_ = function() { }; /* Keep the below constants in sync with the CSS. */ -// TODO(kaznacheev): Set to 30 when the audio player is title-less. + +/** + * Player header height. + * TODO(kaznacheev): Set to 30 when the audio player is title-less. + */ AudioPlayer.HEADER_HEIGHT = 0; + +/** + * Track height. + */ AudioPlayer.TRACK_HEIGHT = 58; + +/** + * Controls bar height. + */ AudioPlayer.CONTROLS_HEIGHT = 35; +/** + * Set the correct player window height. + * @private + */ AudioPlayer.prototype.syncHeight_ = function() { var expandedListHeight = Math.min(this.urls_.length, 3) * AudioPlayer.TRACK_HEIGHT; @@ -278,9 +363,9 @@ AudioPlayer.prototype.syncHeight_ = function() { /** * Create a TrackInfo object encapsulating the information about one track. * - * @param {HTMLElement} container - * @param {string} url - * @param {function} onClick + * @param {HTMLElement} container Container element. + * @param {string} url Track url. + * @param {function} onClick Click handler. * @constructor */ AudioPlayer.TrackInfo = function(container, url, onClick) { @@ -313,8 +398,14 @@ AudioPlayer.TrackInfo = function(container, url, onClick) { this.data_.appendChild(this.artist_); }; +/** + * @return {HTMLDivElement} The wrapper element for the track. + */ AudioPlayer.TrackInfo.prototype.getBox = function() { return this.box_ }; +/** + * @return {string} Default track title (file name extracted from the url). + */ AudioPlayer.TrackInfo.prototype.getDefaultTitle = function() { var title = this.url_.split('/').pop(); var dotIndex = title.lastIndexOf('.'); @@ -322,8 +413,14 @@ AudioPlayer.TrackInfo.prototype.getDefaultTitle = function() { return title; }; +/** + * TODO(kaznacheev): Localize. + */ AudioPlayer.TrackInfo.DEFAULT_ARTIST = 'Unknown Artist'; +/** + * @return {string} 'Unknown artist' string. + */ AudioPlayer.TrackInfo.prototype.getDefaultArtist = function() { return AudioPlayer.TrackInfo.DEFAULT_ARTIST; }; @@ -331,9 +428,11 @@ AudioPlayer.TrackInfo.prototype.getDefaultArtist = function() { /** * @param {Object} metadata The metadata object. * @param {HTMLElement} container The container for the tracks. + * @param {string} error Error string. */ -AudioPlayer.TrackInfo.prototype.setMetadata = function(metadata, container) { - if (metadata.error) { +AudioPlayer.TrackInfo.prototype.setMetadata = function( + metadata, container, error) { + if (error) { this.art_.classList.add('blank'); this.art_.classList.add('error'); container.classList.remove('noart'); @@ -346,5 +445,6 @@ AudioPlayer.TrackInfo.prototype.setMetadata = function(metadata, container) { this.img_.src = metadata.thumbnail.url; } this.title_.textContent = metadata.media.title || this.getDefaultTitle(); - this.artist_.textContent = metadata.media.artist || this.getDefaultArtist(); + this.artist_.textContent = + error || metadata.media.artist || this.getDefaultArtist(); }; diff --git a/chrome/browser/resources/file_manager/js/media/video_player.js b/chrome/browser/resources/file_manager/js/media/video_player.js index 4385a01..2c5ebfc 100644 --- a/chrome/browser/resources/file_manager/js/media/video_player.js +++ b/chrome/browser/resources/file_manager/js/media/video_player.js @@ -4,10 +4,12 @@ /** * Display error message. + * @param {string} opt_message Message id. */ -function onError() { +function onError(opt_message) { var errorBanner = document.querySelector('#error'); - errorBanner.textContent = loadTimeData.getString('GALLERY_VIDEO_ERROR'); + errorBanner.textContent = + loadTimeData.getString(opt_message || 'GALLERY_VIDEO_ERROR'); errorBanner.setAttribute('visible', 'true'); } @@ -102,13 +104,28 @@ function loadVideoPlayer() { document.querySelector('#video-container'), document.querySelector('#controls')); - // If the video player is starting before the first instance of the File - // Manager then it does not have access to filesystem URLs. Request it now. - chrome.fileBrowserPrivate.requestLocalFileSystem(function() { - var video = document.querySelector('video'); - video.src = src; - video.load(); - controls.attachMedia(video); + var metadataCache = MetadataCache.createFull(); + metadataCache.get(src, 'streaming', function(streaming) { + if (streaming && streaming.url) { + if (!navigator.onLine) { + onError('GALLERY_VIDEO_OFFLINE'); + return; + } + src = streaming.url; + console.log('Streaming: ' + src); + } else { + console.log('Playing local file: ' + src); + } + + // If the video player is starting before the first instance of the File + // Manager then it does not have access to filesystem URLs. + // Request it now. + chrome.fileBrowserPrivate.requestLocalFileSystem(function() { + var video = document.querySelector('video'); + video.src = src; + video.load(); + controls.attachMedia(video); + }); }); }); } diff --git a/chrome/browser/resources/file_manager/js/media/video_player_scripts.js b/chrome/browser/resources/file_manager/js/media/video_player_scripts.js index f6f571c..8ea0123 100644 --- a/chrome/browser/resources/file_manager/js/media/video_player_scripts.js +++ b/chrome/browser/resources/file_manager/js/media/video_player_scripts.js @@ -10,6 +10,8 @@ //<include src="../metrics.js"/> //<include src="../../../shared/js/load_time_data.js"/> +//<include src="../file_type.js"/> //<include src="media_controls.js"/> //<include src="util.js"/> //<include src="video_player.js"/> +//<include src="../metadata/metadata_cache.js"/> diff --git a/chrome/browser/resources/file_manager/video_player.html b/chrome/browser/resources/file_manager/video_player.html index b37751e..35db252 100644 --- a/chrome/browser/resources/file_manager/video_player.html +++ b/chrome/browser/resources/file_manager/video_player.html @@ -21,9 +21,11 @@ Keep the list in sync with video_player_scripts.js. --> <script src="js/metrics.js"></script> <script src="../shared/js/load_time_data.js"></script> + <script src="js/file_type.js"></script> <script src="js/media/media_controls.js"></script> <script src="js/media/util.js"></script> <script src="js/media/video_player.js"></script> + <script src="js/metadata/metadata_cache.js"></script> </if> </head> <body> |