Implemented API for tracking ongoing file transfers from file manager.

new method:
chrome.fileManagerPrivate.getFileTransfers(function(transfers) {
});

new event:
chrome.fileManagerPrivate.onFileTransfersUpdated.addListener(function(transfers) {
});

where:

transfers = [
{
'fileUrl': 'filesystem://.../external/gdata/myfile.txt',
'transferState': 'started|in_progress|completed|failed',
'transferType': 'upload|download',
'processed': 1234,
'total': 54331
},
...
]

BUG=chromium-os:27819
TEST=none

Review URL: https://chromiumcodereview.appspot.com/9703042

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@127362 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/chromeos/extensions/file_browser_event_router.cc b/chrome/browser/chromeos/extensions/file_browser_event_router.cc
index e16ff38c..5725cd3 100644
--- a/chrome/browser/chromeos/extensions/file_browser_event_router.cc
+++ b/chrome/browser/chromeos/extensions/file_browser_event_router.cc
@@ -16,6 +16,9 @@
 #include "chrome/browser/extensions/extension_event_router.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_dependency_manager.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "content/public/browser/notification_source.h"
 #include "grit/generated_resources.h"
 #include "webkit/fileapi/file_system_types.h"
 #include "webkit/fileapi/file_system_util.h"
@@ -23,6 +26,8 @@
 using chromeos::disks::DiskMountManager;
 using chromeos::disks::DiskMountManagerEventType;
 using content::BrowserThread;
+using gdata::GDataFileSystem;
+using gdata::GDataFileSystemFactory;
 
 namespace {
   const char kDiskAddedEventType[] = "added";
@@ -73,40 +78,57 @@
   return "";
 }
 
-ExtensionFileBrowserEventRouter::ExtensionFileBrowserEventRouter(
+FileBrowserEventRouter::FileBrowserEventRouter(
     Profile* profile)
-    : delegate_(new ExtensionFileBrowserEventRouter::FileWatcherDelegate(this)),
+    : delegate_(new FileBrowserEventRouter::FileWatcherDelegate(this)),
       notifications_(new FileBrowserNotifications(profile)),
       profile_(profile) {
 }
 
-ExtensionFileBrowserEventRouter::~ExtensionFileBrowserEventRouter() {
-  DCHECK(file_watchers_.empty());
-  STLDeleteValues(&file_watchers_);
-
-  if (!profile_) {
-    NOTREACHED();
-    return;
-  }
-  profile_ = NULL;
-  DiskMountManager::GetInstance()->RemoveObserver(this);
+FileBrowserEventRouter::~FileBrowserEventRouter() {
 }
 
-void ExtensionFileBrowserEventRouter::ObserveFileSystemEvents() {
+void FileBrowserEventRouter::ShutdownOnUIThread() {
+  DCHECK(file_watchers_.empty());
+  STLDeleteValues(&file_watchers_);
   if (!profile_) {
     NOTREACHED();
     return;
   }
-  if (chromeos::UserManager::Get()->IsUserLoggedIn()) {
-    DiskMountManager* disk_mount_manager = DiskMountManager::GetInstance();
-    disk_mount_manager->RemoveObserver(this);
-    disk_mount_manager->AddObserver(this);
-    disk_mount_manager->RequestMountInfoRefresh();
+  DiskMountManager::GetInstance()->RemoveObserver(this);
+
+  GDataFileSystem* file_system =
+      GDataFileSystemFactory::FindForProfile(profile_);
+  if (file_system)
+    file_system->RemoveOperationObserver(this);
+
+  profile_ = NULL;
+}
+
+void FileBrowserEventRouter::ObserveFileSystemEvents() {
+  if (!profile_) {
+    NOTREACHED();
+    return;
   }
+  if (!chromeos::UserManager::Get()->IsUserLoggedIn())
+    return;
+
+  DiskMountManager* disk_mount_manager = DiskMountManager::GetInstance();
+  disk_mount_manager->RemoveObserver(this);
+  disk_mount_manager->AddObserver(this);
+  disk_mount_manager->RequestMountInfoRefresh();
+
+  GDataFileSystem* file_system =
+      GDataFileSystemFactory::GetForProfile(profile_);
+  if (!file_system) {
+    NOTREACHED();
+    return;
+  }
+  file_system->AddOperationObserver(this);
 }
 
 // File watch setup routines.
-bool ExtensionFileBrowserEventRouter::AddFileWatch(
+bool FileBrowserEventRouter::AddFileWatch(
     const FilePath& local_path,
     const FilePath& virtual_path,
     const std::string& extension_id) {
@@ -126,7 +148,7 @@
   return true;
 }
 
-void ExtensionFileBrowserEventRouter::RemoveFileWatch(
+void FileBrowserEventRouter::RemoveFileWatch(
     const FilePath& local_path,
     const std::string& extension_id) {
   base::AutoLock lock(lock_);
@@ -141,7 +163,7 @@
   }
 }
 
-void ExtensionFileBrowserEventRouter::DiskChanged(
+void FileBrowserEventRouter::DiskChanged(
     DiskMountManagerEventType event,
     const DiskMountManager::Disk* disk) {
   // Disregard hidden devices.
@@ -154,7 +176,7 @@
   }
 }
 
-void ExtensionFileBrowserEventRouter::DeviceChanged(
+void FileBrowserEventRouter::DeviceChanged(
     DiskMountManagerEventType event,
     const std::string& device_path) {
   if (event == chromeos::disks::MOUNT_DEVICE_ADDED) {
@@ -179,7 +201,7 @@
   }
 }
 
-void ExtensionFileBrowserEventRouter::MountCompleted(
+void FileBrowserEventRouter::MountCompleted(
     DiskMountManager::MountEvent event_type,
     chromeos::MountError error_code,
     const DiskMountManager::MountPointInfo& mount_info) {
@@ -202,7 +224,26 @@
   }
 }
 
-void ExtensionFileBrowserEventRouter::HandleFileWatchNotification(
+void FileBrowserEventRouter::OnProgressUpdate(
+    const std::vector<gdata::GDataOperationRegistry::ProgressStatus>& list) {
+  scoped_ptr<ListValue> event_list(
+      file_manager_util::ProgressStatusVectorToListValue(
+          profile_,
+          file_manager_util::GetFileBrowserExtensionUrl().GetOrigin(),
+          list));
+
+  std::string args_json;
+  base::JSONWriter::Write(event_list.get(),
+                          &args_json);
+
+  profile_->GetExtensionEventRouter()->DispatchEventToExtension(
+      std::string(kFileBrowserDomain),
+      extension_event_names::kOnFileTransfersUpdated, args_json,
+      NULL, GURL());
+}
+
+
+void FileBrowserEventRouter::HandleFileWatchNotification(
     const FilePath& local_path, bool got_error) {
   base::AutoLock lock(lock_);
   WatcherMap::const_iterator iter = file_watchers_.find(local_path);
@@ -214,9 +255,9 @@
                             iter->second->GetExtensions());
 }
 
-void ExtensionFileBrowserEventRouter::DispatchFolderChangeEvent(
+void FileBrowserEventRouter::DispatchFolderChangeEvent(
     const FilePath& virtual_path, bool got_error,
-    const ExtensionFileBrowserEventRouter::ExtensionUsageRegistry& extensions) {
+    const FileBrowserEventRouter::ExtensionUsageRegistry& extensions) {
   if (!profile_) {
     NOTREACHED();
     return;
@@ -245,7 +286,7 @@
   }
 }
 
-void ExtensionFileBrowserEventRouter::DispatchDiskEvent(
+void FileBrowserEventRouter::DispatchDiskEvent(
     const DiskMountManager::Disk* disk, bool added) {
   if (!profile_) {
     NOTREACHED();
@@ -267,7 +308,7 @@
       GURL());
 }
 
-void ExtensionFileBrowserEventRouter::DispatchMountCompletedEvent(
+void FileBrowserEventRouter::DispatchMountCompletedEvent(
     DiskMountManager::MountEvent event,
     chromeos::MountError error_code,
     const DiskMountManager::MountPointInfo& mount_info) {
@@ -331,7 +372,7 @@
   }
 }
 
-void ExtensionFileBrowserEventRouter::OnDiskAdded(
+void FileBrowserEventRouter::OnDiskAdded(
     const DiskMountManager::Disk* disk) {
   VLOG(1) << "Disk added: " << disk->device_path();
   if (disk->device_path().empty()) {
@@ -348,7 +389,7 @@
   DispatchDiskEvent(disk, true);
 }
 
-void ExtensionFileBrowserEventRouter::OnDiskRemoved(
+void FileBrowserEventRouter::OnDiskRemoved(
     const DiskMountManager::Disk* disk) {
   VLOG(1) << "Disk removed: " << disk->device_path();
 
@@ -358,7 +399,7 @@
   DispatchDiskEvent(disk, false);
 }
 
-void ExtensionFileBrowserEventRouter::OnDeviceAdded(
+void FileBrowserEventRouter::OnDeviceAdded(
     const std::string& device_path) {
   VLOG(1) << "Device added : " << device_path;
 
@@ -368,7 +409,7 @@
                                           4000);
 }
 
-void ExtensionFileBrowserEventRouter::OnDeviceRemoved(
+void FileBrowserEventRouter::OnDeviceRemoved(
     const std::string& device_path) {
   VLOG(1) << "Device removed : " << device_path;
   notifications_->HideNotification(FileBrowserNotifications::DEVICE,
@@ -378,12 +419,12 @@
   notifications_->UnregisterDevice(device_path);
 }
 
-void ExtensionFileBrowserEventRouter::OnDeviceScanned(
+void FileBrowserEventRouter::OnDeviceScanned(
     const std::string& device_path) {
   VLOG(1) << "Device scanned : " << device_path;
 }
 
-void ExtensionFileBrowserEventRouter::OnFormattingStarted(
+void FileBrowserEventRouter::OnFormattingStarted(
     const std::string& device_path, bool success) {
   if (success) {
     notifications_->ShowNotification(FileBrowserNotifications::FORMAT_START,
@@ -394,7 +435,7 @@
   }
 }
 
-void ExtensionFileBrowserEventRouter::OnFormattingFinished(
+void FileBrowserEventRouter::OnFormattingFinished(
     const std::string& device_path, bool success) {
   if (success) {
     notifications_->HideNotification(FileBrowserNotifications::FORMAT_START,
@@ -415,12 +456,12 @@
   }
 }
 
-// ExtensionFileBrowserEventRouter::WatcherDelegate methods.
-ExtensionFileBrowserEventRouter::FileWatcherDelegate::FileWatcherDelegate(
-    ExtensionFileBrowserEventRouter* router) : router_(router) {
+// FileBrowserEventRouter::WatcherDelegate methods.
+FileBrowserEventRouter::FileWatcherDelegate::FileWatcherDelegate(
+    FileBrowserEventRouter* router) : router_(router) {
 }
 
-void ExtensionFileBrowserEventRouter::FileWatcherDelegate::OnFilePathChanged(
+void FileBrowserEventRouter::FileWatcherDelegate::OnFilePathChanged(
     const FilePath& local_path) {
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
@@ -428,7 +469,7 @@
                  this, local_path, false));
 }
 
-void ExtensionFileBrowserEventRouter::FileWatcherDelegate::OnFilePathError(
+void FileBrowserEventRouter::FileWatcherDelegate::OnFilePathError(
     const FilePath& local_path) {
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
@@ -437,14 +478,14 @@
 }
 
 void
-ExtensionFileBrowserEventRouter::FileWatcherDelegate::HandleFileWatchOnUIThread(
+FileBrowserEventRouter::FileWatcherDelegate::HandleFileWatchOnUIThread(
      const FilePath& local_path, bool got_error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   router_->HandleFileWatchNotification(local_path, got_error);
 }
 
 
-ExtensionFileBrowserEventRouter::FileWatcherExtensions::FileWatcherExtensions(
+FileBrowserEventRouter::FileWatcherExtensions::FileWatcherExtensions(
     const FilePath& path, const std::string& extension_id)
     : ref_count(0) {
   file_watcher.reset(new base::files::FilePathWatcher());
@@ -452,7 +493,7 @@
   AddExtension(extension_id);
 }
 
-void ExtensionFileBrowserEventRouter::FileWatcherExtensions::AddExtension(
+void FileBrowserEventRouter::FileWatcherExtensions::AddExtension(
     const std::string& extension_id) {
   ExtensionUsageRegistry::iterator it = extensions.find(extension_id);
   if (it != extensions.end()) {
@@ -464,7 +505,7 @@
   ref_count++;
 }
 
-void ExtensionFileBrowserEventRouter::FileWatcherExtensions::RemoveExtension(
+void FileBrowserEventRouter::FileWatcherExtensions::RemoveExtension(
     const std::string& extension_id) {
   ExtensionUsageRegistry::iterator it = extensions.find(extension_id);
 
@@ -485,22 +526,50 @@
   }
 }
 
-const ExtensionFileBrowserEventRouter::ExtensionUsageRegistry&
-ExtensionFileBrowserEventRouter::FileWatcherExtensions::GetExtensions() const {
+const FileBrowserEventRouter::ExtensionUsageRegistry&
+FileBrowserEventRouter::FileWatcherExtensions::GetExtensions() const {
   return extensions;
 }
 
 unsigned int
-ExtensionFileBrowserEventRouter::FileWatcherExtensions::GetRefCount() const {
+FileBrowserEventRouter::FileWatcherExtensions::GetRefCount() const {
   return ref_count;
 }
 
 const FilePath&
-ExtensionFileBrowserEventRouter::FileWatcherExtensions::GetVirtualPath() const {
+FileBrowserEventRouter::FileWatcherExtensions::GetVirtualPath() const {
   return virtual_path;
 }
 
-bool ExtensionFileBrowserEventRouter::FileWatcherExtensions::Watch
+bool FileBrowserEventRouter::FileWatcherExtensions::Watch
     (const FilePath& path, FileWatcherDelegate* delegate) {
   return file_watcher->Watch(path, delegate);
 }
+
+// static
+scoped_refptr<FileBrowserEventRouter>
+FileBrowserEventRouterFactory::GetForProfile(Profile* profile) {
+  return static_cast<FileBrowserEventRouter*>(
+      GetInstance()->GetServiceForProfile(profile, true).get());
+}
+
+// static
+FileBrowserEventRouterFactory*
+FileBrowserEventRouterFactory::GetInstance() {
+  return Singleton<FileBrowserEventRouterFactory>::get();
+}
+
+FileBrowserEventRouterFactory::FileBrowserEventRouterFactory()
+    : RefcountedProfileKeyedServiceFactory("FileBrowserEventRouter",
+          ProfileDependencyManager::GetInstance()) {
+  DependsOn(GDataFileSystemFactory::GetInstance());
+}
+
+FileBrowserEventRouterFactory::~FileBrowserEventRouterFactory() {
+}
+
+scoped_refptr<RefcountedProfileKeyedService>
+FileBrowserEventRouterFactory::BuildServiceInstanceFor(Profile* profile) const {
+  return scoped_refptr<RefcountedProfileKeyedService>(
+      new FileBrowserEventRouter(profile));
+}
diff --git a/chrome/browser/chromeos/extensions/file_browser_event_router.h b/chrome/browser/chromeos/extensions/file_browser_event_router.h
index e5464557..8b606f00 100644
--- a/chrome/browser/chromeos/extensions/file_browser_event_router.h
+++ b/chrome/browser/chromeos/extensions/file_browser_event_router.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 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.
 
@@ -16,17 +16,24 @@
 #include "base/string16.h"
 #include "base/synchronization/lock.h"
 #include "chrome/browser/chromeos/disks/disk_mount_manager.h"
+#include "chrome/browser/chromeos/gdata/gdata_file_system.h"
+#include "chrome/browser/chromeos/gdata/gdata_operation_registry.h"
+#include "chrome/browser/profiles/refcounted_profile_keyed_service.h"
+#include "chrome/browser/profiles/refcounted_profile_keyed_service_factory.h"
 
 class FileBrowserNotifications;
 class Profile;
 
 // Used to monitor disk mount changes and signal when new mounted usb device is
 // found.
-class ExtensionFileBrowserEventRouter
-    : public chromeos::disks::DiskMountManager::Observer {
+class FileBrowserEventRouter
+    : public RefcountedProfileKeyedService,
+      public chromeos::disks::DiskMountManager::Observer,
+      public gdata::GDataOperationRegistry::Observer {
  public:
-  explicit ExtensionFileBrowserEventRouter(Profile* profile);
-  virtual ~ExtensionFileBrowserEventRouter();
+  // RefcountedProfileKeyedService overrides.
+  virtual void ShutdownOnUIThread() OVERRIDE;
+
   // Starts observing file system change events. Currently only
   // CrosDisksClient events are being observed.
   void ObserveFileSystemEvents();
@@ -50,11 +57,18 @@
       const chromeos::disks::DiskMountManager::MountPointInfo& mount_info)
       OVERRIDE;
 
+  // GDataOperationRegistry::Observer overrides.
+  virtual void OnProgressUpdate(
+      const std::vector<gdata::GDataOperationRegistry::ProgressStatus>& list)
+          OVERRIDE;
+
  private:
+  friend class FileBrowserEventRouterFactory;
+
   // Helper class for passing through file watch notification events.
   class FileWatcherDelegate : public base::files::FilePathWatcher::Delegate {
    public:
-    explicit FileWatcherDelegate(ExtensionFileBrowserEventRouter* router);
+    explicit FileWatcherDelegate(FileBrowserEventRouter* router);
 
    private:
     // base::files::FilePathWatcher::Delegate overrides.
@@ -63,7 +77,7 @@
 
     void HandleFileWatchOnUIThread(const FilePath& local_path, bool got_error);
 
-    ExtensionFileBrowserEventRouter* router_;
+    FileBrowserEventRouter* router_;
   };
 
   typedef std::map<std::string, int> ExtensionUsageRegistry;
@@ -97,6 +111,9 @@
 
   typedef std::map<FilePath, FileWatcherExtensions*> WatcherMap;
 
+  explicit FileBrowserEventRouter(Profile* profile);
+  virtual ~FileBrowserEventRouter();
+
   // USB mount event handlers.
   void OnDiskAdded(const chromeos::disks::DiskMountManager::Disk* disk);
   void OnDiskRemoved(const chromeos::disks::DiskMountManager::Disk* disk);
@@ -139,7 +156,30 @@
   Profile* profile_;
   base::Lock lock_;
 
-  DISALLOW_COPY_AND_ASSIGN(ExtensionFileBrowserEventRouter);
+  DISALLOW_COPY_AND_ASSIGN(FileBrowserEventRouter);
+};
+
+// Singleton that owns all FileBrowserEventRouter and associates
+// them with Profiles.
+class FileBrowserEventRouterFactory
+    : public RefcountedProfileKeyedServiceFactory {
+ public:
+  // Returns the FileBrowserEventRouter for |profile|, creating it if
+  // it is not yet created.
+  static scoped_refptr<FileBrowserEventRouter> GetForProfile(Profile* profile);
+
+  // Returns the FileBrowserEventRouterFactory instance.
+  static FileBrowserEventRouterFactory* GetInstance();
+
+ private:
+  friend struct DefaultSingletonTraits<FileBrowserEventRouterFactory>;
+
+  FileBrowserEventRouterFactory();
+  virtual ~FileBrowserEventRouterFactory();
+
+  // ProfileKeyedServiceFactory:
+  virtual scoped_refptr<RefcountedProfileKeyedService> BuildServiceInstanceFor(
+      Profile* profile) const OVERRIDE;
 };
 
 #endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_BROWSER_EVENT_ROUTER_H_
diff --git a/chrome/browser/chromeos/extensions/file_browser_private_api.cc b/chrome/browser/chromeos/extensions/file_browser_private_api.cc
index e8ce2aa..6d78b754a 100644
--- a/chrome/browser/chromeos/extensions/file_browser_private_api.cc
+++ b/chrome/browser/chromeos/extensions/file_browser_private_api.cc
@@ -13,10 +13,10 @@
 #include "base/stringprintf.h"
 #include "base/time.h"
 #include "base/values.h"
-#include "chrome/browser/chromeos/extensions/file_browser_event_router.h"
 #include "chrome/browser/chromeos/extensions/file_handler_util.h"
 #include "chrome/browser/chromeos/extensions/file_manager_util.h"
 #include "chrome/browser/chromeos/gdata/gdata_file_system_proxy.h"
+#include "chrome/browser/chromeos/gdata/gdata_operation_registry.h"
 #include "chrome/browser/chromeos/gdata/gdata_util.h"
 #include "chrome/browser/extensions/extension_function_dispatcher.h"
 #include "chrome/browser/extensions/extension_process_manager.h"
@@ -60,6 +60,7 @@
 using content::SiteInstance;
 using content::WebContents;
 using file_handler_util::FileTaskExecutor;
+using gdata::GDataOperationRegistry;
 
 namespace {
 
@@ -483,6 +484,7 @@
       base::Bind(
           &FileWatchBrowserFunctionBase::RunFileWatchOperationOnFileThread,
           this,
+          FileBrowserEventRouterFactory::GetForProfile(profile_),
           file_watch_url,
           extension_id()));
 
@@ -490,6 +492,7 @@
 }
 
 void FileWatchBrowserFunctionBase::RunFileWatchOperationOnFileThread(
+    scoped_refptr<FileBrowserEventRouter> event_router,
     const GURL& file_url, const std::string& extension_id) {
   FilePath local_path;
   FilePath virtual_path;
@@ -502,7 +505,10 @@
             this,
             false));
   }
-  if (!PerformFileWatchOperation(local_path, virtual_path, extension_id)) {
+  if (!PerformFileWatchOperation(event_router,
+                                 local_path,
+                                 virtual_path,
+                                 extension_id)) {
     BrowserThread::PostTask(
         BrowserThread::UI, FROM_HERE,
         base::Bind(
@@ -519,22 +525,22 @@
 }
 
 bool AddFileWatchBrowserFunction::PerformFileWatchOperation(
+    scoped_refptr<FileBrowserEventRouter> event_router,
     const FilePath& local_path, const FilePath& virtual_path,
     const std::string& extension_id) {
 #if defined(OS_CHROMEOS)
-  return profile_->GetExtensionService()->file_browser_event_router()->
-      AddFileWatch(local_path, virtual_path, extension_id);
+  return event_router->AddFileWatch(local_path, virtual_path, extension_id);
 #else
   return true;
 #endif  // defined(OS_CHROMEOS)
 }
 
 bool RemoveFileWatchBrowserFunction::PerformFileWatchOperation(
+    scoped_refptr<FileBrowserEventRouter> event_router,
     const FilePath& local_path, const FilePath& unused,
     const std::string& extension_id) {
 #if defined(OS_CHROMEOS)
-  profile_->GetExtensionService()->file_browser_event_router()->
-      RemoveFileWatch(local_path, extension_id);
+  event_router->RemoveFileWatch(local_path, extension_id);
 #endif
   return true;
 }
@@ -1004,10 +1010,8 @@
       chromeos::MOUNT_TYPE_GDATA,
       chromeos::disks::MOUNT_CONDITION_NONE);
   // Raise mount event
-  profile_->GetExtensionService()->file_browser_event_router()->MountCompleted(
-      DiskMountManager::MOUNTING,
-      error_code,
-      mount_info);
+  FileBrowserEventRouterFactory::GetForProfile(profile_)->
+      MountCompleted(DiskMountManager::MOUNTING, error_code, mount_info);
 }
 
 void AddMountFunction::OnGDataAuthentication(gdata::GDataErrorCode error,
@@ -1714,3 +1718,32 @@
   // Start getting the next file.
   GetFileOrSendResponse();
 }
+
+GetFileTransfersFunction::GetFileTransfersFunction() {}
+
+GetFileTransfersFunction::~GetFileTransfersFunction() {}
+
+ListValue* GetFileTransfersFunction::GetFileTransfersList() {
+  gdata::GDataFileSystem* file_system =
+      gdata::GDataFileSystemFactory::GetForProfile(profile_);
+  if (!file_system)
+    return NULL;
+
+  std::vector<gdata::GDataOperationRegistry::ProgressStatus>
+      list = file_system->GetProgressStatusList();
+  return file_manager_util::ProgressStatusVectorToListValue(
+      profile_, source_url_.GetOrigin(), list);
+}
+
+bool GetFileTransfersFunction::RunImpl() {
+  scoped_ptr<ListValue> progress_status_list(GetFileTransfersList());
+  if (!progress_status_list.get()) {
+    SendResponse(false);
+    return false;
+  }
+
+  result_.reset(progress_status_list.release());
+  SendResponse(true);
+  return true;
+}
+
diff --git a/chrome/browser/chromeos/extensions/file_browser_private_api.h b/chrome/browser/chromeos/extensions/file_browser_private_api.h
index 6d2bffc9..dd2a121 100644
--- a/chrome/browser/chromeos/extensions/file_browser_private_api.h
+++ b/chrome/browser/chromeos/extensions/file_browser_private_api.h
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "base/platform_file.h"
+#include "chrome/browser/chromeos/extensions/file_browser_event_router.h"
 #include "chrome/browser/chromeos/gdata/gdata.h"
 #include "chrome/browser/extensions/extension_function.h"
 #include "googleurl/src/url_util.h"
@@ -42,6 +43,7 @@
 class FileWatchBrowserFunctionBase : public AsyncExtensionFunction {
  protected:
   virtual bool PerformFileWatchOperation(
+      scoped_refptr<FileBrowserEventRouter> event_router,
       const FilePath& local_path, const FilePath& virtual_path,
       const std::string& extension_id) = 0;
 
@@ -52,14 +54,17 @@
   bool GetLocalFilePath(const GURL& file_url, FilePath* local_path,
                         FilePath* virtual_path);
   void RespondOnUIThread(bool success);
-  void RunFileWatchOperationOnFileThread(const GURL& file_url,
-                                         const std::string& extension_id);
+  void RunFileWatchOperationOnFileThread(
+      scoped_refptr<FileBrowserEventRouter> event_router,
+      const GURL& file_url,
+      const std::string& extension_id);
 };
 
 // Implements the chrome.fileBrowserPrivate.addFileWatch method.
 class AddFileWatchBrowserFunction : public FileWatchBrowserFunctionBase {
  protected:
   virtual bool PerformFileWatchOperation(
+      scoped_refptr<FileBrowserEventRouter> event_router,
       const FilePath& local_path, const FilePath& virtual_path,
       const std::string& extension_id) OVERRIDE;
 
@@ -72,6 +77,7 @@
 class RemoveFileWatchBrowserFunction : public FileWatchBrowserFunctionBase {
  protected:
   virtual bool PerformFileWatchOperation(
+      scoped_refptr<FileBrowserEventRouter> event_router,
       const FilePath& local_path, const FilePath& virtual_path,
       const std::string& extension_id) OVERRIDE;
 
@@ -481,4 +487,20 @@
   DECLARE_EXTENSION_FUNCTION_NAME("fileBrowserPrivate.getGDataFiles");
 };
 
+// Implements the chrome.fileBrowserPrivate.executeTask method.
+class GetFileTransfersFunction : public AsyncExtensionFunction {
+ public:
+  GetFileTransfersFunction();
+  virtual ~GetFileTransfersFunction();
+
+ protected:
+  // AsyncExtensionFunction overrides.
+  virtual bool RunImpl() OVERRIDE;
+
+ private:
+  ListValue* GetFileTransfersList();
+
+  DECLARE_EXTENSION_FUNCTION_NAME("fileBrowserPrivate.getFileTransfers");
+};
+
 #endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_BROWSER_PRIVATE_API_H_
diff --git a/chrome/browser/chromeos/extensions/file_manager_util.cc b/chrome/browser/chromeos/extensions/file_manager_util.cc
index 509a4d3..caee01b8 100644
--- a/chrome/browser/chromeos/extensions/file_manager_util.cc
+++ b/chrome/browser/chromeos/extensions/file_manager_util.cc
@@ -12,6 +12,7 @@
 #include "base/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/extensions/file_handler_util.h"
+#include "chrome/browser/chromeos/gdata/gdata_operation_registry.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/extension_install_ui.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -40,14 +41,17 @@
 #include "chrome/browser/chromeos/media/media_player.h"
 #endif
 
+using base::DictionaryValue;
+using base::ListValue;
 using content::BrowserContext;
 using content::BrowserThread;
 using content::PluginService;
 using content::UserMetricsAction;
 using file_handler_util::FileTaskExecutor;
+using gdata::GDataOperationRegistry;
 
-#define FILEBROWSER_DOMAIN "hhaomjibdihmijegdhdafkllkbggdgoj"
-const char kFileBrowserDomain[] = FILEBROWSER_DOMAIN;
+#define FILEBROWSER_EXTENSON_ID "hhaomjibdihmijegdhdafkllkbggdgoj"
+const char kFileBrowserDomain[] = FILEBROWSER_EXTENSON_ID;
 
 const char kFileBrowserGalleryTaskId[] = "gallery";
 const char kFileBrowserMountArchiveTaskId[] = "mount-archive";
@@ -56,7 +60,7 @@
 namespace {
 
 #define FILEBROWSER_URL(PATH) \
-    ("chrome-extension://" FILEBROWSER_DOMAIN "/" PATH)
+    ("chrome-extension://" FILEBROWSER_EXTENSON_ID "/" PATH)
 // This is the "well known" url for the file manager extension from
 // browser/resources/file_manager.  In the future we may provide a way to swap
 // out this file manager for an aftermarket part, but not yet.
@@ -65,7 +69,7 @@
 const char kMediaPlayerUrl[] = FILEBROWSER_URL("mediaplayer.html");
 const char kMediaPlayerPlaylistUrl[] = FILEBROWSER_URL("playlist.html");
 #undef FILEBROWSER_URL
-#undef FILEBROWSER_DOMAIN
+#undef FILEBROWSER_EXTENSON_ID
 
 const char kCRXExtension[] = ".crx";
 const char kPdfExtension[] = ".pdf";
@@ -164,6 +168,29 @@
   return type_str;
 }
 
+DictionaryValue* ProgessStatusToDictionaryValue(
+    Profile* profile,
+    const GURL& origin_url,
+    const GDataOperationRegistry::ProgressStatus& status) {
+  scoped_ptr<DictionaryValue> result(new DictionaryValue());
+  GURL file_url;
+  if (file_manager_util::ConvertFileToFileSystemUrl(profile,
+          FilePath(status.file_path),
+          origin_url,
+          &file_url)) {
+    result->SetString("fileUrl", file_url.spec());
+  }
+
+  result->SetString("transferState",
+      GDataOperationRegistry::OperationTransferStateToString(
+          status.transfer_state));
+  result->SetString("transferType",
+      GDataOperationRegistry::OperationTypeToString(status.operation_type));
+  result->SetInteger("processed", static_cast<int>(status.progress_current));
+  result->SetInteger("total", static_cast<int>(status.progress_total));
+  return result.release();
+}
+
 }  // namespace
 
 GURL GetFileBrowserExtensionUrl() {
@@ -495,4 +522,18 @@
   return plugin_prefs->IsPluginEnabled(plugin);
 }
 
+ListValue* ProgressStatusVectorToListValue(
+    Profile* profile, const GURL& origin_url,
+    const std::vector<GDataOperationRegistry::ProgressStatus>& list) {
+  scoped_ptr<ListValue> result_list(new ListValue());
+  for (std::vector<
+          GDataOperationRegistry::ProgressStatus>::const_iterator iter =
+              list.begin();
+       iter != list.end(); ++iter) {
+    result_list->Append(
+        ProgessStatusToDictionaryValue(profile, origin_url, *iter));
+  }
+  return result_list.release();
+}
+
 }  // namespace file_manager_util
diff --git a/chrome/browser/chromeos/extensions/file_manager_util.h b/chrome/browser/chromeos/extensions/file_manager_util.h
index 7e520ef..9645b8a 100644
--- a/chrome/browser/chromeos/extensions/file_manager_util.h
+++ b/chrome/browser/chromeos/extensions/file_manager_util.h
@@ -7,13 +7,19 @@
 #pragma once
 
 #include <string>
+#include <vector>
 
 #include "base/file_path.h"
+#include "chrome/browser/chromeos/gdata/gdata_operation_registry.h"
 #include "chrome/browser/ui/select_file_dialog.h"
 #include "googleurl/src/gurl.h"
 
 class Profile;
 
+namespace base {
+class ListValue;
+}
+
 extern const char kFileBrowserDomain[];
 
 // File manager helper methods.
@@ -68,6 +74,11 @@
 
 bool ShouldBeOpenedWithPdfPlugin(const char* file_extension);
 
+// Converts the vector of progress status to their JSON (Value) form.
+base::ListValue* ProgressStatusVectorToListValue(
+    Profile* profile, const GURL& origin_url,
+    const std::vector<gdata::GDataOperationRegistry::ProgressStatus>& list);
+
 }  // namespace file_manager_util
 
 #endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_UTIL_H_
diff --git a/chrome/browser/chromeos/gdata/gdata.cc b/chrome/browser/chromeos/gdata/gdata.cc
index 9b7d666c..7bffcb76 100644
--- a/chrome/browser/chromeos/gdata/gdata.cc
+++ b/chrome/browser/chromeos/gdata/gdata.cc
@@ -196,6 +196,10 @@
   gdata_auth_service_->Initialize(profile);
 }
 
+GDataOperationRegistry* DocumentsService::operation_registry() const {
+  return operation_registry_.get();
+}
+
 void DocumentsService::CancelAll() {
   operation_registry_->CancelAll();
 }
diff --git a/chrome/browser/chromeos/gdata/gdata.h b/chrome/browser/chromeos/gdata/gdata.h
index 1bf42193..81295cdb 100644
--- a/chrome/browser/chromeos/gdata/gdata.h
+++ b/chrome/browser/chromeos/gdata/gdata.h
@@ -144,6 +144,9 @@
   // Initializes the documents service tied with |profile|.
   virtual void Initialize(Profile* profile) = 0;
 
+  // Retrieves the operation registry.
+  virtual GDataOperationRegistry* operation_registry() const = 0;
+
   // Cancels all in-flight operations.
   virtual void CancelAll() = 0;
 
@@ -269,6 +272,7 @@
 
   // DocumentsServiceInterface Overrides
   virtual void Initialize(Profile* profile) OVERRIDE;
+  virtual GDataOperationRegistry* operation_registry() const OVERRIDE;
   virtual void CancelAll() OVERRIDE;
   virtual void Authenticate(const AuthStatusCallback& callback) OVERRIDE;
   virtual void GetDocuments(const GURL& feed_url,
diff --git a/chrome/browser/chromeos/gdata/gdata_file_system.cc b/chrome/browser/chromeos/gdata/gdata_file_system.cc
index 9540b0b1..5be91da 100644
--- a/chrome/browser/chromeos/gdata/gdata_file_system.cc
+++ b/chrome/browser/chromeos/gdata/gdata_file_system.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/gdata/gdata.h"
 #include "chrome/browser/chromeos/gdata/gdata_download_observer.h"
-#include "chrome/browser/chromeos/gdata/gdata_parser.h"
 #include "chrome/browser/download/download_service.h"
 #include "chrome/browser/download/download_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -1223,6 +1222,22 @@
                feed->quota_bytes_used());
 }
 
+std::vector<GDataOperationRegistry::ProgressStatus>
+    GDataFileSystem::GetProgressStatusList() {
+  return documents_service_->operation_registry()->GetProgressStatusList();
+}
+
+void GDataFileSystem::AddOperationObserver(
+    GDataOperationRegistry::Observer* observer) {
+  return documents_service_->operation_registry()->AddObserver(observer);
+}
+
+void GDataFileSystem::RemoveOperationObserver(
+    GDataOperationRegistry::Observer* observer) {
+  return documents_service_->operation_registry()->RemoveObserver(observer);
+}
+
+
 void GDataFileSystem::OnCreateDirectoryCompleted(
     const CreateDirectoryParams& params,
     GDataErrorCode status,
@@ -2240,6 +2255,13 @@
 }
 
 // static
+GDataFileSystem* GDataFileSystemFactory::FindForProfile(
+    Profile* profile) {
+  return static_cast<GDataFileSystem*>(
+      GetInstance()->GetServiceForProfile(profile, false));
+}
+
+// static
 GDataFileSystemFactory* GDataFileSystemFactory::GetInstance() {
   return Singleton<GDataFileSystemFactory>::get();
 }
@@ -2247,6 +2269,7 @@
 GDataFileSystemFactory::GDataFileSystemFactory()
     : ProfileKeyedServiceFactory("GDataFileSystem",
                                  ProfileDependencyManager::GetInstance()) {
+  DependsOn(DownloadServiceFactory::GetInstance());
 }
 
 GDataFileSystemFactory::~GDataFileSystemFactory() {
diff --git a/chrome/browser/chromeos/gdata/gdata_file_system.h b/chrome/browser/chromeos/gdata/gdata_file_system.h
index 8464f00..ee2d406 100644
--- a/chrome/browser/chromeos/gdata/gdata_file_system.h
+++ b/chrome/browser/chromeos/gdata/gdata_file_system.h
@@ -19,6 +19,7 @@
 #include "base/platform_file.h"
 #include "base/synchronization/lock.h"
 #include "chrome/browser/chromeos/gdata/gdata_files.h"
+#include "chrome/browser/chromeos/gdata/gdata_operation_registry.h"
 #include "chrome/browser/chromeos/gdata/gdata_params.h"
 #include "chrome/browser/chromeos/gdata/gdata_parser.h"
 #include "chrome/browser/chromeos/gdata/gdata_uploader.h"
@@ -233,6 +234,13 @@
   void GetFromCacheForPath(const FilePath& gdata_file_path,
                            const GetFromCacheCallback& callback);
 
+  // Obtains the list of currently active operations.
+  std::vector<GDataOperationRegistry::ProgressStatus> GetProgressStatusList();
+  // Add operation observer.
+  void AddOperationObserver(GDataOperationRegistry::Observer* observer);
+  // Remove operation observer.
+  void RemoveOperationObserver(GDataOperationRegistry::Observer* observer);
+
   // Finds file object by |file_path| and returns its |file_info|.
   // Returns true if file was found.
   bool GetFileInfoFromPath(const FilePath& gdata_file_path,
@@ -682,6 +690,9 @@
   // Returns the GDataFileSystem for |profile|, creating it if it is not
   // yet created.
   static GDataFileSystem* GetForProfile(Profile* profile);
+  // Returns the GDataFileSystem that is already associated with |profile|,
+  // if it is not yet created it will return NULL.
+  static GDataFileSystem* FindForProfile(Profile* profile);
 
   // Returns the GDataFileSystemFactory instance.
   static GDataFileSystemFactory* GetInstance();
diff --git a/chrome/browser/chromeos/gdata/gdata_mock.h b/chrome/browser/chromeos/gdata/gdata_mock.h
index d967c01..bd848e0 100644
--- a/chrome/browser/chromeos/gdata/gdata_mock.h
+++ b/chrome/browser/chromeos/gdata/gdata_mock.h
@@ -28,6 +28,7 @@
 
   // DocumentServiceInterface overrides.
   MOCK_METHOD1(Initialize, void(Profile* profile));
+  MOCK_CONST_METHOD0(operation_registry, GDataOperationRegistry*());
   MOCK_METHOD0(CancelAll, void(void));
   MOCK_METHOD1(Authenticate, void(const AuthStatusCallback& callback));
   MOCK_METHOD2(GetDocuments, void(const GURL& feed_url,
diff --git a/chrome/browser/extensions/extension_event_names.cc b/chrome/browser/extensions/extension_event_names.cc
index 9f25a7a1..c127cd59 100644
--- a/chrome/browser/extensions/extension_event_names.cc
+++ b/chrome/browser/extensions/extension_event_names.cc
@@ -31,6 +31,8 @@
 const char kOnFileChanged[] = "fileBrowserPrivate.onFileChanged";
 const char kOnFileBrowserMountCompleted[] =
     "fileBrowserPrivate.onMountCompleted";
+const char kOnFileTransfersUpdated[] =
+    "fileBrowserPrivate.onFileTransfersUpdated";
 
 const char kOnInputMethodChanged[] = "inputMethodPrivate.onChanged";
 
diff --git a/chrome/browser/extensions/extension_event_names.h b/chrome/browser/extensions/extension_event_names.h
index d18c1f11..200328d 100644
--- a/chrome/browser/extensions/extension_event_names.h
+++ b/chrome/browser/extensions/extension_event_names.h
@@ -38,6 +38,7 @@
 extern const char kOnFileBrowserDiskChanged[];
 extern const char kOnFileChanged[];
 extern const char kOnFileBrowserMountCompleted[];
+extern const char kOnFileTransfersUpdated[];
 
 // InputMethod.
 extern const char kOnInputMethodChanged[];
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index af61980d2..5b1258b 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -541,9 +541,8 @@
   web_navigation_event_router_->Init();
 
 #if defined(OS_CHROMEOS)
-  file_browser_event_router_.reset(
-      new ExtensionFileBrowserEventRouter(profile_));
-  file_browser_event_router_->ObserveFileSystemEvents();
+  FileBrowserEventRouterFactory::GetForProfile(
+      profile_)->ObserveFileSystemEvents();
 
   input_method_event_router_.reset(
       new chromeos::ExtensionInputMethodEventRouter);
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 4c133d8a..7f884ad 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -53,7 +53,6 @@
 class ExtensionContentSettingsStore;
 class ExtensionCookiesEventRouter;
 class ExtensionDownloadsEventRouter;
-class ExtensionFileBrowserEventRouter;
 class ExtensionGlobalError;
 class ExtensionManagementEventRouter;
 class ExtensionPreferenceEventRouter;
@@ -477,9 +476,6 @@
   }
 
 #if defined(OS_CHROMEOS)
-  ExtensionFileBrowserEventRouter* file_browser_event_router() {
-    return file_browser_event_router_.get();
-  }
   chromeos::ExtensionInputMethodEventRouter* input_method_event_router() {
     return input_method_event_router_.get();
   }
@@ -814,7 +810,6 @@
   scoped_ptr<ExtensionWebNavigationEventRouter> web_navigation_event_router_;
 
 #if defined(OS_CHROMEOS)
-  scoped_ptr<ExtensionFileBrowserEventRouter> file_browser_event_router_;
   scoped_ptr<chromeos::ExtensionInputMethodEventRouter>
       input_method_event_router_;
 #endif
diff --git a/chrome/browser/resources/file_manager/js/directory_model.js b/chrome/browser/resources/file_manager/js/directory_model.js
index eb981005..f7457ae 100644
--- a/chrome/browser/resources/file_manager/js/directory_model.js
+++ b/chrome/browser/resources/file_manager/js/directory_model.js
@@ -763,11 +763,15 @@
     }
 
     function onGData(entry) {
+      console.log('onGData');
+      console.log(entry);
       groups.gdata = [entry];
       done();
     }
 
     function onGDataError(error) {
+      console.log('onGDataError');
+      console.log(error);
       groups.gdata = [];
       done();
     }
@@ -784,8 +788,11 @@
   },
 
   updateRoots: function(opt_callback) {
+    console.log('directoryModel_.updateRoots');
     var self = this;
     this.resolveRoots_(function(rootEntries) {
+      console.log('rootsList_ = ');
+      console.log(self.rootsList_);
       var dm = self.rootsList_;
       var args = [0, dm.length].concat(rootEntries);
       dm.splice.apply(dm, args);