summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaznacheev@chromium.org <kaznacheev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-18 17:02:21 +0000
committerkaznacheev@chromium.org <kaznacheev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-18 17:02:21 +0000
commitb10ff6aa7fb3d5a3d31d5c1552e330ace58c3614 (patch)
tree5950bfa6c4cb8f0678753ab3564b93e02d015499
parent0c4b5c9d23d43a790479f8c944c8bc865bf31c09 (diff)
downloadchromium_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
-rw-r--r--chrome/browser/chromeos/extensions/file_browser_private_api.cc3
-rw-r--r--chrome/browser/resources/file_manager/js/image_editor/gallery.js2
-rw-r--r--chrome/browser/resources/file_manager/js/image_editor/image_view.js13
-rw-r--r--chrome/browser/resources/file_manager/js/media/audio_player.js140
-rw-r--r--chrome/browser/resources/file_manager/js/media/video_player.js35
-rw-r--r--chrome/browser/resources/file_manager/js/media/video_player_scripts.js2
-rw-r--r--chrome/browser/resources/file_manager/video_player.html2
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>