Files.app: Add MetadataItem class.

Previously Files.app uses @typedef for expressing metadata item.
The CL introduces new class instead, for better compiler check.

BUG=410766
TEST=None

Review URL: https://codereview.chromium.org/939653002

Cr-Commit-Position: refs/heads/master@{#316991}
diff --git a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
index b43e447..6a8b6ea 100644
--- a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
+++ b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
@@ -94,6 +94,7 @@
           './metadata/metadata_cache.js',
           './metadata/metadata_cache_item.js',
           './metadata/metadata_cache_set.js',
+          './metadata/metadata_item.js',
           './metadata/new_metadata_provider.js',
           './metadata/thumbnail_model.js',
           './metadata_update_controller.js',
diff --git a/ui/file_manager/file_manager/foreground/js/main_scripts.js b/ui/file_manager/file_manager/foreground/js/main_scripts.js
index bd5a7270..43c9677 100644
--- a/ui/file_manager/file_manager/foreground/js/main_scripts.js
+++ b/ui/file_manager/file_manager/foreground/js/main_scripts.js
@@ -114,6 +114,7 @@
 //<include src="metadata/file_system_metadata_provider.js">
 //<include src="metadata/metadata_cache.js">
 //<include src="metadata/metadata_cache_item.js">
+//<include src="metadata/metadata_item.js">
 //<include src="metadata_update_controller.js">
 //<include src="naming_controller.js">
 //<include src="navigation_list_model.js">
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js
index a90450c..651c891 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js
@@ -3,28 +3,10 @@
 // found in the LICENSE file.
 
 /**
- * @typedef {{
- *  scaleX: number,
- *  scaleY: number,
- *  rotate90: number
- * }}
- */
-var ImageTransformation;
-
-/**
- * @typedef {{
- *   contentThumbnailUrl:(string|undefined),
- *   contentThumbnailTransform: (!ImageTransformation|undefined),
- *   contentImageTransform: (!ImageTransformation|undefined)
- * }}
- */
-var ContentMetadata;
-
-/**
  * @param {!MetadataProviderCache} cache
  * @param {!MessagePort=} opt_messagePort Message port overriding the default
  *     worker port.
- * @extends {NewMetadataProvider<!ContentMetadata>}
+ * @extends {NewMetadataProvider}
  * @constructor
  * @struct
  */
@@ -32,11 +14,7 @@
   NewMetadataProvider.call(
       this,
       cache,
-      [
-        'contentThumbnailUrl',
-        'contentThumbnailTransform',
-        'contentImageTransform'
-      ]);
+      ContentMetadataProvider.PROPERTY_NAMES);
 
   /**
    * Pass all URLs to the metadata reader until we have a correct filter.
@@ -72,6 +50,17 @@
 }
 
 /**
+ * @const {!Array<string>}
+ */
+ContentMetadataProvider.PROPERTY_NAMES = [
+  'contentThumbnailUrl',
+  'contentThumbnailTransform',
+  'contentImageTransform',
+  'mediaTitle',
+  'mediaArtist'
+];
+
+/**
  * Path of a worker script.
  * @const {string}
  */
@@ -82,14 +71,14 @@
 /**
  * Converts content metadata from parsers to the internal format.
  * @param {Object} metadata The content metadata.
- * @return {!ContentMetadata} Converted metadata.
+ * @return {!MetadataItem} Converted metadata.
  */
 ContentMetadataProvider.convertContentMetadata = function(metadata) {
-  return {
-    contentThumbnailUrl: metadata['thumbnailURL'],
-    contentThumbnailTransform: metadata['thumbnailTransform'],
-    contentImageTransform: metadata['imageTransform']
-  };
+  var item = new MetadataItem();
+  item.contentThumbnailUrl = metadata['thumbnailURL'];
+  item.contentThumbnailTransform = metadata['thumbnailTransform'];
+  item.contentImageTransform = metadata ['imageTransform'];
+  return item;
 };
 
 ContentMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype;
@@ -188,7 +177,8 @@
   for (var i = 0; i < callbacks.length; i++) {
     callbacks[i](
         metadata ?
-        ContentMetadataProvider.convertContentMetadata(metadata) : {});
+        ContentMetadataProvider.convertContentMetadata(metadata) :
+        new MetadataItem());
   }
 };
 
@@ -204,7 +194,7 @@
     function(url, step, error, metadata) {
   if (MetadataCache.log)  // Avoid log spam by default.
     console.warn('metadata: ' + url + ': ' + step + ': ' + error);
-  this.onResult_(url, {});
+  this.onResult_(url, new MetadataItem());
 };
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.html
index 1df0974..bfe2b5d 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.html
+++ b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.html
@@ -13,7 +13,8 @@
 <script src="../../../../../webui/resources/js/assert.js"></script>
 <script src="../../../common/js/lru_cache.js"></script>
 <script src="../../../common/js/unittest_util.js"></script>
-<script src="metadata_cache_item.js"></script>
 <script src="content_metadata_provider.js"></script>
+<script src="metadata_cache_item.js"></script>
+<script src="metadata_item.js"></script>
 
 <script src="content_metadata_provider_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
index 225b2e9..f6cc007 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
@@ -3,59 +3,42 @@
 // found in the LICENSE file.
 
 /**
- * @typedef {{
- *   size: number,
- *   shared: (boolean|undefined),
- *   modificationTime: Date,
- *   thumbnailUrl: (string|undefined),
- *   externalFileUrl: (string|undefined),
- *   imageWidth: (number|undefined),
- *   imageHeight: (number|undefined),
- *   imageRotation: (number|undefined),
- *   pinned: (boolean|undefined),
- *   present: (boolean|undefined),
- *   hosted: (boolean|undefined),
- *   dirty: (boolean|undefined),
- *   availableOffline: (boolean|undefined),
- *   availableWhenMetered: (boolean|undefined),
- *   customIconUrl: string,
- *   contentMimeType: string,
- *   sharedWithMe: (boolean|undefined)
- * }}
- */
-var ExternalMetadataProperties;
-
-/**
  * Metadata provider for FileEntry#getMetadata.
  * TODO(hirono): Rename thumbnailUrl with externalThumbnailUrl.
  *
  * @param {!MetadataProviderCache} cache
  * @constructor
- * @extends {NewMetadataProvider<!ExternalMetadataProperties>}
+ * @extends {NewMetadataProvider}
  * @struct
  */
 function ExternalMetadataProvider(cache) {
-  NewMetadataProvider.call(this, cache, [
-    'availableOffline',
-    'availableWhenMetered',
-    'contentMimeType',
-    'customIconUrl',
-    'dirty',
-    'externalFileUrl',
-    'hosted',
-    'imageHeight',
-    'imageRotation',
-    'imageWidth',
-    'modificationTime',
-    'pinned',
-    'present',
-    'shared',
-    'sharedWithMe',
-    'size',
-    'thumbnailUrl'
-  ]);
+  NewMetadataProvider.call(
+      this, cache, ExternalMetadataProvider.PROPERTY_NAMES);
 }
 
+/**
+ * @const {!Array<string>}
+ */
+ExternalMetadataProvider.PROPERTY_NAMES = [
+  'availableOffline',
+  'availableWhenMetered',
+  'contentMimeType',
+  'customIconUrl',
+  'dirty',
+  'externalFileUrl',
+  'hosted',
+  'imageHeight',
+  'imageRotation',
+  'imageWidth',
+  'modificationTime',
+  'pinned',
+  'present',
+  'shared',
+  'sharedWithMe',
+  'size',
+  'thumbnailUrl'
+];
+
 ExternalMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype;
 
 /**
@@ -80,7 +63,7 @@
           if (!chrome.runtime.lastError)
             fulfill(this.convertResults_(requests, results));
           else
-            fulfill(requests.map(function() { return {}; }));
+            fulfill(requests.map(function() { return new MetadataItem(); }));
         }.bind(this));
   }.bind(this));
 };
@@ -88,32 +71,32 @@
 /**
  * @param {!Array<!MetadataRequest>} requests
  * @param {!Array<!EntryProperties>} propertiesList
- * @return {!Array<!ExternalMetadataProperties>}
+ * @return {!Array<!MetadataItem>}
  */
 ExternalMetadataProvider.prototype.convertResults_ =
     function(requests, propertiesList) {
   var results = [];
   for (var i = 0; i < propertiesList.length; i++) {
     var properties = propertiesList[i];
-    results.push({
-      availableOffline: properties.availableOffline,
-      availableWhenMetered: properties.availableWhenMetered,
-      contentMimeType: properties.contentMimeType || '',
-      customIconUrl: properties.customIconUrl || '',
-      dirty: properties.dirty,
-      externalFileUrl: properties.externalFileUrl,
-      hosted: properties.hosted,
-      imageHeight: properties.imageHeight,
-      imageRotation: properties.imageRotation,
-      imageWidth: properties.imageWidth,
-      modificationTime: new Date(properties.modificationTime),
-      pinned: properties.pinned,
-      present: properties.present,
-      shared: properties.shared,
-      sharedWithMe: properties.sharedWithMe,
-      size: requests[i].entry.isFile ? (properties.size || 0) : -1,
-      thumbnailUrl: properties.thumbnailUrl
-    });
+    var item = new MetadataItem();
+    item.availableOffline = properties.availableOffline;
+    item.availableWhenMetered = properties.availableWhenMetered;
+    item.contentMimeType = properties.contentMimeType || '';
+    item.customIconUrl = properties.customIconUrl || '';
+    item.dirty = properties.dirty;
+    item.externalFileUrl = properties.externalFileUrl;
+    item.hosted = properties.hosted;
+    item.imageHeight = properties.imageHeight;
+    item.imageRotation = properties.imageRotation;
+    item.imageWidth = properties.imageWidth;
+    item.modificationTime = new Date(properties.modificationTime);
+    item.pinned = properties.pinned;
+    item.present = properties.present;
+    item.shared = properties.shared;
+    item.sharedWithMe = properties.sharedWithMe;
+    item.size = requests[i].entry.isFile ? (properties.size || 0) : -1;
+    item.thumbnailUrl = properties.thumbnailUrl;
+    results.push(item);
   }
   return results;
 };
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.html
index bc4926c..01a43ac 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.html
+++ b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.html
@@ -13,7 +13,8 @@
 <script src="../../../../../webui/resources/js/assert.js"></script>
 <script src="../../../common/js/lru_cache.js"></script>
 <script src="../../../common/js/unittest_util.js"></script>
-<script src="metadata_cache_item.js"></script>
 <script src="external_metadata_provider.js"></script>
+<script src="metadata_cache_item.js"></script>
+<script src="metadata_item.js"></script>
 
 <script src="external_metadata_provider_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata.js b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata.js
index 7c8d1c70..de312ad 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata.js
@@ -44,7 +44,7 @@
  * Obtains metadata for entries.
  * @param {!Array<!Entry>} entries Entries.
  * @param {!Array<string>} names Metadata property names to be obtained.
- * @return {!Promise<!Array<!ExternalMetadataProperties>>}
+ * @return {!Promise<!Array<!MetadataItem>>}
  */
 FileSystemMetadata.prototype.get = function(entries, names) {
   var localEntries = [];
@@ -90,7 +90,7 @@
  * Obtains metadata cache for entries.
  * @param {!Array<!Entry>} entries Entries.
  * @param {!Array<string>} names Metadata property names to be obtained.
- * @return {!Array<!ExternalMetadataProperties>}
+ * @return {!Array<!MetadataItem>}
  */
 FileSystemMetadata.prototype.getCache = function(entries, names) {
   return this.cache_.get(entries, names);
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js
index f1700a2..01c8519 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js
@@ -3,17 +3,11 @@
 // found in the LICENSE file.
 
 /**
- * @typedef {{modificationTime:Date, size:number, contentMimeType:string,
- *     present:boolean, availableOffline: boolean}}
- */
-var FileSystemMetadataProperties;
-
-/**
  * Metadata provider for FileEntry#getMetadata.
  *
  * @param {!MetadataProviderCache} cache
  * @constructor
- * @extends {NewMetadataProvider<!FileSystemMetadataProperties>}
+ * @extends {NewMetadataProvider}
  * @struct
  */
 function FileSystemMetadataProvider(cache) {
@@ -25,7 +19,7 @@
  * @const {!Array<string>}
  */
 FileSystemMetadataProvider.PROPERTY_NAMES = [
-    'modificationTime', 'size', 'present', 'availableOffline', 'contentMimeType'
+  'modificationTime', 'size', 'present', 'availableOffline', 'contentMimeType'
 ];
 
 FileSystemMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype;
@@ -48,19 +42,16 @@
           }
         })
     ]).then(function(results) {
-      var result = {
-        modificationTime: results[0].modificationTime,
-        size: request.entry.isDirectory ? -1 : results[0].size,
-        present: true,
-        availableOffline: true,
-      };
-
+      var item = new MetadataItem();
+      item.modificationTime = results[0].modificationTime;
+      item.size = request.entry.isDirectory ? -1 : results[0].size;
+      item.present = true;
+      item.availableOffline = true;
       if (results[1] !== null)
-        result['contentMimeType'] = results[1];
-
-      return result;
+        item.contentMimeType = results[1];
+      return item;
     }, function() {
-      return {};
+      return new MetadataItem();
     });
   }));
 };
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.html
index c971788..a4b10f7 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.html
+++ b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.html
@@ -13,7 +13,8 @@
 <script src="../../../../../webui/resources/js/assert.js"></script>
 <script src="../../../common/js/lru_cache.js"></script>
 <script src="../../../common/js/unittest_util.js"></script>
-<script src="metadata_cache_item.js"></script>
 <script src="file_system_metadata_provider.js"></script>
+<script src="metadata_cache_item.js"></script>
+<script src="metadata_item.js"></script>
 
 <script src="file_system_metadata_provider_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.html
index 6be027b..7c23ebc7 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.html
+++ b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.html
@@ -14,9 +14,11 @@
 <script src="../../../common/js/lru_cache.js"></script>
 <script src="../../../common/js/unittest_util.js"></script>
 <script src="../../../common/js/volume_manager_common.js"></script>
+<script src="content_metadata_provider.js"></script>
 <script src="external_metadata_provider.js"></script>
 <script src="file_system_metadata.js"></script>
 <script src="file_system_metadata_provider.js"></script>
 <script src="metadata_cache_item.js"></script>
+<script src="metadata_item.js"></script>
 
 <script src="file_system_metadata_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item.js
index 1efae04..5f0b8a2f4 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item.js
@@ -54,11 +54,12 @@
 /**
  * Feeds the result of startRequests.
  * @param {number} requestId Request ID passed when calling startRequests.
- * @param {!Object} object Map of property name and value.
+ * @param {!MetadataItem} typedObject Map of property name and value.
  * @return {boolean} Whether at least one property is updated or not.
  */
-MetadataCacheItem.prototype.storeProperties = function(requestId, object) {
+MetadataCacheItem.prototype.storeProperties = function(requestId, typedObject) {
   var changed = false;
+  var object = /** @type {!Object} */(typedObject);
   for (var name in object) {
     if (!this.properties_[name])
       this.properties_[name] = new MetadataCacheItemProperty();
@@ -93,16 +94,16 @@
  * Obtains property for entries and names.
  * Note that it returns invalidated properties also.
  * @param {!Array<string>} names
- * @return {!Object}
+ * @return {!MetadataItem}
  */
 MetadataCacheItem.prototype.get = function(names) {
-  var result = {};
+  var result = /** @type {!Object} */(new MetadataItem());
   for (var i = 0; i < names.length; i++) {
     var name = names[i];
     if (this.properties_[name])
       result[name] = this.properties_[name].value;
   }
-  return result;
+  return /** @type {!MetadataItem} */(result);
 };
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item_unittest.html
index 06f6f7a..a08dff0 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item_unittest.html
+++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_item_unittest.html
@@ -6,5 +6,6 @@
 <script src="../../../../../webui/resources/js/assert.js"></script>
 <script src="../../../common/js/unittest_util.js"></script>
 <script src="metadata_cache_item.js"></script>
+<script src="metadata_item.js"></script>
 
 <script src="metadata_cache_item_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set.js
index 6a0dc31..5d499509 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set.js
@@ -63,7 +63,7 @@
  * @param {number} requestId Request ID. If a newer operation has already been
  *     done, the results must be ingored.
  * @param {!Array<!Entry>} entries
- * @param {!Array<!Object>} results
+ * @param {!Array<!MetadataItem>} results
  * @return {boolean} Whether at least one result is stored or not.
  */
 MetadataCacheSet.prototype.storeProperties = function(
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set_unittest.html
index a086524..b6f8d05 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set_unittest.html
+++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_cache_set_unittest.html
@@ -13,5 +13,6 @@
 <script src="../../../common/js/unittest_util.js"></script>
 <script src="metadata_cache_item.js"></script>
 <script src="metadata_cache_set.js"></script>
+<script src="metadata_item.js"></script>
 
 <script src="metadata_cache_set_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js
new file mode 100644
index 0000000..cdf9d91
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_item.js
@@ -0,0 +1,131 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @typedef {{
+ *  scaleX: number,
+ *  scaleY: number,
+ *  rotate90: number
+ * }}
+ */
+var ImageTransformation;
+
+/**
+ * @constructor
+ * @struct
+ */
+function MetadataItem() {
+  /**
+   * Size of the file. -1 for directory.
+   * @public {number|undefined}
+   */
+  this.size;
+
+  /**
+   * @public {!Date|undefined}
+   */
+  this.modificationTime;
+
+  /**
+   * Thumbnail URL obtained from external provider.
+   * @public {string|undefined}
+   */
+  this.thumbnailUrl;
+
+  /**
+   * @public {number|undefined}
+   */
+  this.imageWidth;
+
+  /**
+   * @public {number|undefined}
+   */
+  this.imageHeight;
+
+  /**
+   * @public {number|undefined}
+   */
+  this.imageRotation;
+
+  /**
+   * Thumbnail obtained from content provider.
+   * @public {string|undefined}
+   */
+  this.contentThumbnailUrl;
+
+  /**
+   * Thumbnail transformation obtained from content provider.
+   * @public {!ImageTransformation|undefined}
+   */
+  this.contentThumbnailTransform;
+
+  /**
+   * Image transformation obtained from content provider.
+   * @public {!ImageTransformation|undefined}
+   */
+  this.contentImageTransform;
+
+  /**
+   * Whether the entry is pinned for ensuring it is available offline.
+   * @public {boolean|undefined}
+   */
+  this.pinned;
+
+  /**
+   * Whether the entry is cached locally.
+   * @public {boolean|undefined}
+   */
+  this.present;
+
+  /**
+   * Whether the entry is hosted document of google drive.
+   * @public {boolean|undefined}
+   */
+  this.hosted;
+
+  /**
+   * Whether the entry is modified locally and not synched yet.
+   * @public {boolean|undefined}
+   */
+  this.dirty;
+
+  /**
+   * Whether the entry is present or hosted;
+   * @public {boolean|undefined}
+   */
+  this.availableOffline;
+
+  /**
+   * @public {boolean|undefined}
+   */
+  this.availableWhenMetered;
+
+  /**
+   * @public {string|undefined}
+   */
+  this.customIconUrl;
+
+  /**
+   * @public {string|undefined}
+   */
+  this.contentMimeType;
+
+  /**
+   * Whether the entry is shared explicitly with me.
+   * @public {boolean|undefined}
+   */
+  this.sharedWithMe;
+
+  /**
+   * Whether the entry is shared publicly.
+   * @public {boolean|undefined}
+   */
+  this.shared;
+
+  /**
+   * URL for open a file in browser tab.
+   * @public {string|undefined}
+   */
+  this.externalFileUrl;
+}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider.js
index ae53dc7..fc088271 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider.js
@@ -8,7 +8,6 @@
  * @param {!Array<string>} validPropertyNames
  * @constructor
  * @struct
- * @template T
  */
 function NewMetadataProvider(cache, validPropertyNames) {
   /**
@@ -38,9 +37,10 @@
 /**
  * Obtains the metadata for the request.
  * @param {!Array<!MetadataRequest>} requests
- * @return {!Promise<!Array<!T>>} Promise with obtained metadata. It should not
- *     return rejected promise. Instead it should return undefined property for
- *     property error, and should return empty object for entry error.
+ * @return {!Promise<!Array<!MetadataItem>>} Promise with obtained metadata. It
+ *     should not return rejected promise. Instead it should return undefined
+ *     property for property error, and should return empty MetadataItem for
+ *     entry error.
  * @protected
  */
 NewMetadataProvider.prototype.getImpl;
@@ -49,7 +49,7 @@
  * Obtains metadata for entries.
  * @param {!Array<!Entry>} entries Entries.
  * @param {!Array<string>} names Metadata property names to be obtained.
- * @return {!Promise<!Array<!T>>}
+ * @return {!Promise<!Array<!MetadataItem>>}
  */
 NewMetadataProvider.prototype.get = function(entries, names) {
   // Check if the property name is correct or not.
@@ -70,9 +70,9 @@
   this.cache_.startRequests(requestId, requests);
 
   // Register callback.
-  var promise = new Promise(function(fulfill, reject) {
+  var promise = new Promise(function(fulfill) {
     this.callbackRequests_.push(new MetadataProviderCallbackRequest(
-        entries, names, snapshot, fulfill, reject));
+        entries, names, snapshot, fulfill));
   }.bind(this));
 
   // If the requests are not empty, call the requests.
@@ -114,7 +114,7 @@
  * Obtains metadata cache for entries.
  * @param {!Array<!Entry>} entries Entries.
  * @param {!Array<string>} names Metadata property names to be obtained.
- * @return {!Array<!T>}
+ * @return {!Array<!MetadataItem>}
  */
 NewMetadataProvider.prototype.getCache = function(entries, names) {
   // Check if the property name is correct or not.
@@ -128,14 +128,11 @@
  * @param {!Array<!Entry>} entries
  * @param {!Array<string>} names
  * @param {!MetadataCacheSet} cache
- * @param {function(!T):undefined} fulfill
- * @param {function():undefined} reject
+ * @param {function(!MetadataItem):undefined} fulfill
  * @constructor
  * @struct
- * @template T
  */
-function MetadataProviderCallbackRequest(
-    entries, names, cache, fulfill, reject) {
+function MetadataProviderCallbackRequest(entries, names, cache, fulfill) {
   /**
    * @private {!Array<!Entry>}
    * @const
@@ -155,16 +152,10 @@
   this.cache_ = cache;
 
   /**
-   * @private {function(!T):undefined}
+   * @private {function(!MetadataItem):undefined}
    * @const
    */
   this.fulfill_ = fulfill;
-
-  /**
-   * @private {function():undefined}
-   * @const
-   */
-  this.reject_ = reject;
 }
 
 /**
@@ -172,7 +163,7 @@
  * If all the requested property are served, it invokes the callback.
  * @param {number} requestId
  * @param {!Array<!Entry>} entries
- * @param {!Array<!Object>} objects
+ * @param {!Array<!MetadataItem>} objects
  * @return {boolean} Whether the callback is invoked or not.
  */
 MetadataProviderCallbackRequest.prototype.storeProperties = function(
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.html
index 10e32f7..476242cd 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.html
+++ b/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.html
@@ -13,6 +13,7 @@
 <script src="../../../common/js/lru_cache.js"></script>
 <script src="../../../common/js/unittest_util.js"></script>
 <script src="metadata_cache_item.js"></script>
+<script src="metadata_item.js"></script>
 <script src="new_metadata_provider.js"></script>
 
 <script src="new_metadata_provider_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model_unittest.html
index d1367a1..bb10cdcb 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model_unittest.html
+++ b/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model_unittest.html
@@ -5,6 +5,7 @@
   -->
 <script src="../../../common/js/file_type.js"></script>
 <script src="../../../common/js/unittest_util.js"></script>
+<script src="metadata_item.js"></script>
 <script src="thumbnail_model.js"></script>
 
 <script src="thumbnail_model_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index 78dfa4b..2fbfed1a 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -135,6 +135,7 @@
       <script src="foreground/js/metadata/file_system_metadata_provider.js"></script>
       <script src="foreground/js/metadata/metadata_cache.js"></script>
       <script src="foreground/js/metadata/metadata_cache_item.js"></script>
+      <script src="foreground/js/metadata/metadata_item.js"></script>
       <script src="foreground/js/metadata_update_controller.js"></script>
       <script src="foreground/js/naming_controller.js"></script>
       <script src="foreground/js/navigation_list_model.js"></script>