Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / media_galleries / media_galleries_api.cc
index 8f1c48d..d5f033d 100644 (file)
 #include <string>
 #include <vector>
 
-#include "apps/shell_window.h"
-#include "apps/shell_window_registry.h"
+#include "base/callback.h"
 #include "base/lazy_instance.h"
-#include "base/platform_file.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
 #include "chrome/browser/extensions/blob_reader.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/media_galleries/fileapi/safe_media_metadata_parser.h"
+#include "chrome/browser/media_galleries/gallery_watch_manager.h"
 #include "chrome/browser/media_galleries/media_file_system_registry.h"
-#include "chrome/browser/media_galleries/media_galleries_dialog_controller.h"
 #include "chrome/browser/media_galleries/media_galleries_histograms.h"
+#include "chrome/browser/media_galleries/media_galleries_permission_controller.h"
 #include "chrome/browser/media_galleries/media_galleries_preferences.h"
-#include "chrome/browser/media_galleries/media_galleries_scan_result_dialog_controller.h"
+#include "chrome/browser/media_galleries/media_galleries_scan_result_controller.h"
 #include "chrome/browser/media_galleries/media_scan_manager.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/storage_monitor/storage_info.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
 #include "chrome/common/extensions/api/media_galleries.h"
-#include "chrome/common/extensions/permissions/media_galleries_permission.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/storage_monitor/storage_info.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "content/public/browser/blob_handle.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "extensions/browser/event_router.h"
+#include "extensions/browser/app_window/app_window.h"
+#include "extensions/browser/app_window/app_window_registry.h"
+#include "extensions/browser/blob_holder.h"
 #include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_system.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/media_galleries_permission.h"
 #include "extensions/common/permissions/permissions_data.h"
-#include "grit/generated_resources.h"
 #include "net/base/mime_sniffer.h"
+#include "storage/browser/blob/blob_data_handle.h"
 #include "ui/base/l10n/l10n_util.h"
 
 using content::WebContents;
+using storage_monitor::MediaStorageUtil;
+using storage_monitor::StorageInfo;
 using web_modal::WebContentsModalDialogManager;
 
 namespace extensions {
 
 namespace MediaGalleries = api::media_galleries;
+namespace DropPermissionForMediaFileSystem =
+    MediaGalleries::DropPermissionForMediaFileSystem;
 namespace GetMediaFileSystems = MediaGalleries::GetMediaFileSystems;
+namespace AddGalleryWatch = MediaGalleries::AddGalleryWatch;
+namespace RemoveGalleryWatch = MediaGalleries::RemoveGalleryWatch;
+namespace GetAllGalleryWatch = MediaGalleries::GetAllGalleryWatch;
 
 namespace {
 
 const char kDisallowedByPolicy[] =
     "Media Galleries API is disallowed by policy: ";
-const char kMissingEventListener[] =
-    "Missing event listener registration.";
+const char kFailedToSetGalleryPermission[] =
+    "Failed to set gallery permission.";
+const char kInvalidGalleryIdMsg[] = "Invalid gallery id.";
+const char kMissingEventListener[] = "Missing event listener registration.";
+const char kNonExistentGalleryId[] = "Non-existent gallery id.";
+const char kNoScanPermission[] = "No permission to scan.";
 
 const char kDeviceIdKey[] = "deviceId";
 const char kGalleryIdKey[] = "galleryId";
@@ -72,10 +90,22 @@ const char kIsMediaDeviceKey[] = "isMediaDevice";
 const char kIsRemovableKey[] = "isRemovable";
 const char kNameKey[] = "name";
 
+const char kMetadataKey[] = "metadata";
+const char kAttachedImagesBlobInfoKey[] = "attachedImagesBlobInfo";
+const char kBlobUUIDKey[] = "blobUUID";
+const char kTypeKey[] = "type";
+const char kSizeKey[] = "size";
+
+const char kInvalidGalleryId[] = "-1";
+
 MediaFileSystemRegistry* media_file_system_registry() {
   return g_browser_process->media_file_system_registry();
 }
 
+GalleryWatchManager* gallery_watch_manager() {
+  return media_file_system_registry()->gallery_watch_manager();
+}
+
 MediaScanManager* media_scan_manager() {
   return media_file_system_registry()->media_scan_manager();
 }
@@ -96,6 +126,27 @@ bool Setup(Profile* profile, std::string* error, base::Closure callback) {
   return true;
 }
 
+// Returns true and sets |gallery_file_path| and |gallery_pref_id| if the
+// |gallery_id| is valid and returns false otherwise.
+bool GetGalleryFilePathAndId(const std::string& gallery_id,
+                             Profile* profile,
+                             const Extension* extension,
+                             base::FilePath* gallery_file_path,
+                             MediaGalleryPrefId* gallery_pref_id) {
+  MediaGalleryPrefId pref_id;
+  if (!base::StringToUint64(gallery_id, &pref_id))
+    return false;
+  MediaGalleriesPreferences* preferences =
+      g_browser_process->media_file_system_registry()->GetPreferences(profile);
+  base::FilePath file_path(
+      preferences->LookUpGalleryPathForExtension(pref_id, extension, false));
+  if (file_path.empty())
+    return false;
+  *gallery_pref_id = pref_id;
+  *gallery_file_path = file_path;
+  return true;
+}
+
 WebContents* GetWebContents(content::RenderViewHost* rvh,
                             Profile* profile,
                             const std::string& app_id) {
@@ -104,10 +155,10 @@ WebContents* GetWebContents(content::RenderViewHost* rvh,
       WebContentsModalDialogManager::FromWebContents(contents);
   if (!web_contents_modal_dialog_manager) {
     // If there is no WebContentsModalDialogManager, then this contents is
-    // probably the background page for an app. Try to find a shell window to
+    // probably the background page for an app. Try to find a app window to
     // host the dialog.
-    apps::ShellWindow* window = apps::ShellWindowRegistry::Get(
-        profile)->GetCurrentShellWindowForApp(app_id);
+    AppWindow* window = AppWindowRegistry::Get(profile)
+                            ->GetCurrentAppWindowForApp(app_id);
     contents = window ? window->web_contents() : NULL;
   }
   return contents;
@@ -122,16 +173,17 @@ base::ListValue* ConstructFileSystemList(
 
   MediaGalleriesPermission::CheckParam read_param(
       MediaGalleriesPermission::kReadPermission);
-  bool has_read_permission = PermissionsData::CheckAPIPermissionWithParam(
-      extension, APIPermission::kMediaGalleries, &read_param);
+  const PermissionsData* permissions_data = extension->permissions_data();
+  bool has_read_permission = permissions_data->CheckAPIPermissionWithParam(
+      APIPermission::kMediaGalleries, &read_param);
   MediaGalleriesPermission::CheckParam copy_to_param(
       MediaGalleriesPermission::kCopyToPermission);
-  bool has_copy_to_permission = PermissionsData::CheckAPIPermissionWithParam(
-      extension, APIPermission::kMediaGalleries, &copy_to_param);
+  bool has_copy_to_permission = permissions_data->CheckAPIPermissionWithParam(
+      APIPermission::kMediaGalleries, &copy_to_param);
   MediaGalleriesPermission::CheckParam delete_param(
       MediaGalleriesPermission::kDeletePermission);
-  bool has_delete_permission = PermissionsData::CheckAPIPermissionWithParam(
-      extension, APIPermission::kMediaGalleries, &delete_param);
+  bool has_delete_permission = permissions_data->CheckAPIPermissionWithParam(
+      APIPermission::kMediaGalleries, &delete_param);
 
   const int child_id = rvh->GetProcess()->GetID();
   scoped_ptr<base::ListValue> list(new base::ListValue());
@@ -168,11 +220,11 @@ base::ListValue* ConstructFileSystemList(
     if (has_read_permission) {
       content::ChildProcessSecurityPolicy* policy =
           content::ChildProcessSecurityPolicy::GetInstance();
-      policy->GrantReadFileSystem(child_id, filesystems[i].fsid);
+      policy->GrantReadFile(child_id, filesystems[i].path);
       if (has_delete_permission) {
-        policy->GrantDeleteFromFileSystem(child_id, filesystems[i].fsid);
+        policy->GrantDeleteFrom(child_id, filesystems[i].path);
         if (has_copy_to_permission) {
-          policy->GrantCopyIntoFileSystem(child_id, filesystems[i].fsid);
+          policy->GrantCopyInto(child_id, filesystems[i].path);
         }
       }
     }
@@ -181,6 +233,20 @@ base::ListValue* ConstructFileSystemList(
   return list.release();
 }
 
+bool CheckScanPermission(const extensions::Extension* extension,
+                         std::string* error) {
+  DCHECK(extension);
+  DCHECK(error);
+  MediaGalleriesPermission::CheckParam scan_param(
+      MediaGalleriesPermission::kScanPermission);
+  bool has_scan_permission =
+      extension->permissions_data()->CheckAPIPermissionWithParam(
+          APIPermission::kMediaGalleries, &scan_param);
+  if (!has_scan_permission)
+    *error = kNoScanPermission;
+  return has_scan_permission;
+}
+
 class SelectDirectoryDialog : public ui::SelectFileDialog::Listener,
                               public base::RefCounted<SelectDirectoryDialog> {
  public:
@@ -203,31 +269,31 @@ class SelectDirectoryDialog : public ui::SelectFileDialog::Listener,
       NULL,
       0,
       base::FilePath::StringType(),
-      platform_util::GetTopLevel(web_contents_->GetView()->GetNativeView()),
+      platform_util::GetTopLevel(web_contents_->GetNativeView()),
       NULL);
   }
 
   // ui::SelectFileDialog::Listener implementation.
-  virtual void FileSelected(const base::FilePath& path,
-                            int index,
-                            void* params) OVERRIDE {
+  void FileSelected(const base::FilePath& path,
+                    int index,
+                    void* params) override {
     callback_.Run(path);
     Release();  // Balanced in Show().
   }
 
-  virtual void MultiFilesSelected(const std::vector<base::FilePath>& files,
-                                  void* params) OVERRIDE {
+  void MultiFilesSelected(const std::vector<base::FilePath>& files,
+                          void* params) override {
     NOTREACHED() << "Should not be able to select multiple files";
   }
 
-  virtual void FileSelectionCanceled(void* params) OVERRIDE {
+  void FileSelectionCanceled(void* params) override {
     callback_.Run(base::FilePath());
     Release();  // Balanced in Show().
   }
 
  private:
   friend class base::RefCounted<SelectDirectoryDialog>;
-  virtual ~SelectDirectoryDialog() {}
+  ~SelectDirectoryDialog() override {}
 
   scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
   WebContents* web_contents_;
@@ -238,11 +304,16 @@ class SelectDirectoryDialog : public ui::SelectFileDialog::Listener,
 
 }  // namespace
 
-MediaGalleriesEventRouter::MediaGalleriesEventRouter(Profile* profile)
-    : profile_(profile),
-      weak_ptr_factory_(this) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+MediaGalleriesEventRouter::MediaGalleriesEventRouter(
+    content::BrowserContext* context)
+    : profile_(Profile::FromBrowserContext(context)), weak_ptr_factory_(this) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(profile_);
+
+  EventRouter::Get(profile_)->RegisterObserver(
+      this, MediaGalleries::OnGalleryChanged::kEventName);
+
+  gallery_watch_manager()->AddObserver(profile_, this);
   media_scan_manager()->AddObserver(profile_, this);
 }
 
@@ -250,35 +321,45 @@ MediaGalleriesEventRouter::~MediaGalleriesEventRouter() {
 }
 
 void MediaGalleriesEventRouter::Shutdown() {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   weak_ptr_factory_.InvalidateWeakPtrs();
+
+  EventRouter::Get(profile_)->UnregisterObserver(this);
+
+  gallery_watch_manager()->RemoveObserver(profile_);
   media_scan_manager()->RemoveObserver(profile_);
   media_scan_manager()->CancelScansForProfile(profile_);
 }
 
-static base::LazyInstance<ProfileKeyedAPIFactory<MediaGalleriesEventRouter> >
-g_factory = LAZY_INSTANCE_INITIALIZER;
+static base::LazyInstance<
+    BrowserContextKeyedAPIFactory<MediaGalleriesEventRouter> > g_factory =
+    LAZY_INSTANCE_INITIALIZER;
 
 // static
-ProfileKeyedAPIFactory<MediaGalleriesEventRouter>*
+BrowserContextKeyedAPIFactory<MediaGalleriesEventRouter>*
 MediaGalleriesEventRouter::GetFactoryInstance() {
   return g_factory.Pointer();
 }
 
 // static
-MediaGalleriesEventRouter* MediaGalleriesEventRouter::Get(Profile* profile) {
-  DCHECK(media_file_system_registry()->GetPreferences(profile)->
-             IsInitialized());
-  return ProfileKeyedAPIFactory<MediaGalleriesEventRouter>::GetForProfile(
-      profile);
+MediaGalleriesEventRouter* MediaGalleriesEventRouter::Get(
+    content::BrowserContext* context) {
+  DCHECK(media_file_system_registry()
+             ->GetPreferences(Profile::FromBrowserContext(context))
+             ->IsInitialized());
+  return BrowserContextKeyedAPIFactory<MediaGalleriesEventRouter>::Get(context);
+}
+
+bool MediaGalleriesEventRouter::ExtensionHasGalleryChangeListener(
+    const std::string& extension_id) const {
+  return EventRouter::Get(profile_)->ExtensionHasEventListener(
+      extension_id, MediaGalleries::OnGalleryChanged::kEventName);
 }
 
 bool MediaGalleriesEventRouter::ExtensionHasScanProgressListener(
     const std::string& extension_id) const {
-  EventRouter* router = ExtensionSystem::Get(profile_)->event_router();
-  return router->ExtensionHasEventListener(
-      extension_id,
-      MediaGalleries::OnScanProgress::kEventName);
+  return EventRouter::Get(profile_)->ExtensionHasEventListener(
+      extension_id, MediaGalleries::OnScanProgress::kEventName);
 }
 
 void MediaGalleriesEventRouter::OnScanStarted(const std::string& extension_id) {
@@ -301,14 +382,25 @@ void MediaGalleriesEventRouter::OnScanCancelled(
 }
 
 void MediaGalleriesEventRouter::OnScanFinished(
-    const std::string& extension_id, int gallery_count, int image_count,
-    int audio_count, int video_count) {
+    const std::string& extension_id, int gallery_count,
+    const MediaGalleryScanResult& file_counts) {
+  media_galleries::UsageCount(media_galleries::SCAN_FINISHED);
   MediaGalleries::ScanProgressDetails details;
   details.type = MediaGalleries::SCAN_PROGRESS_TYPE_FINISH;
   details.gallery_count.reset(new int(gallery_count));
-  details.image_count.reset(new int(image_count));
-  details.audio_count.reset(new int(audio_count));
-  details.video_count.reset(new int(video_count));
+  details.audio_count.reset(new int(file_counts.audio_count));
+  details.image_count.reset(new int(file_counts.image_count));
+  details.video_count.reset(new int(file_counts.video_count));
+  DispatchEventToExtension(
+      extension_id,
+      MediaGalleries::OnScanProgress::kEventName,
+      MediaGalleries::OnScanProgress::Create(details).Pass());
+}
+
+void MediaGalleriesEventRouter::OnScanError(
+    const std::string& extension_id) {
+  MediaGalleries::ScanProgressDetails details;
+  details.type = MediaGalleries::SCAN_PROGRESS_TYPE_ERROR;
   DispatchEventToExtension(
       extension_id,
       MediaGalleries::OnScanProgress::kEventName,
@@ -319,9 +411,8 @@ void MediaGalleriesEventRouter::DispatchEventToExtension(
     const std::string& extension_id,
     const std::string& event_name,
     scoped_ptr<base::ListValue> event_args) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  EventRouter* router =
-      extensions::ExtensionSystem::Get(profile_)->event_router();
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  EventRouter* router = EventRouter::Get(profile_);
   if (!router->ExtensionHasEventListener(extension_id, event_name))
     return;
 
@@ -330,10 +421,43 @@ void MediaGalleriesEventRouter::DispatchEventToExtension(
   router->DispatchEventToExtension(extension_id, event.Pass());
 }
 
+void MediaGalleriesEventRouter::OnGalleryChanged(
+    const std::string& extension_id, MediaGalleryPrefId gallery_id) {
+  MediaGalleries::GalleryChangeDetails details;
+  details.type = MediaGalleries::GALLERY_CHANGE_TYPE_CONTENTS_CHANGED;
+  details.gallery_id = base::Uint64ToString(gallery_id);
+  DispatchEventToExtension(
+      extension_id,
+      MediaGalleries::OnGalleryChanged::kEventName,
+      MediaGalleries::OnGalleryChanged::Create(details).Pass());
+}
+
+void MediaGalleriesEventRouter::OnGalleryWatchDropped(
+    const std::string& extension_id, MediaGalleryPrefId gallery_id) {
+  MediaGalleries::GalleryChangeDetails details;
+  details.type = MediaGalleries::GALLERY_CHANGE_TYPE_WATCH_DROPPED;
+  details.gallery_id = gallery_id;
+  DispatchEventToExtension(
+      extension_id,
+      MediaGalleries::OnGalleryChanged::kEventName,
+      MediaGalleries::OnGalleryChanged::Create(details).Pass());
+}
+
+void MediaGalleriesEventRouter::OnListenerRemoved(
+    const EventListenerInfo& details) {
+  if (details.event_name == MediaGalleries::OnGalleryChanged::kEventName &&
+      !ExtensionHasGalleryChangeListener(details.extension_id)) {
+    gallery_watch_manager()->RemoveAllWatches(profile_, details.extension_id);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//               MediaGalleriesGetMediaFileSystemsFunction                   //
+///////////////////////////////////////////////////////////////////////////////
 MediaGalleriesGetMediaFileSystemsFunction::
     ~MediaGalleriesGetMediaFileSystemsFunction() {}
 
-bool MediaGalleriesGetMediaFileSystemsFunction::RunImpl() {
+bool MediaGalleriesGetMediaFileSystemsFunction::RunAsync() {
   media_galleries::UsageCount(media_galleries::GET_MEDIA_FILE_SYSTEMS);
   scoped_ptr<GetMediaFileSystems::Params> params(
       GetMediaFileSystems::Params::Create(*args_));
@@ -399,7 +523,7 @@ void MediaGalleriesGetMediaFileSystemsFunction::GetAndReturnGalleries() {
 void MediaGalleriesGetMediaFileSystemsFunction::ReturnGalleries(
     const std::vector<MediaFileSystemInfo>& filesystems) {
   scoped_ptr<base::ListValue> list(
-      ConstructFileSystemList(render_view_host(), GetExtension(), filesystems));
+      ConstructFileSystemList(render_view_host(), extension(), filesystems));
   if (!list.get()) {
     SendResponse(false);
     return;
@@ -412,9 +536,8 @@ void MediaGalleriesGetMediaFileSystemsFunction::ReturnGalleries(
 
 void MediaGalleriesGetMediaFileSystemsFunction::ShowDialog() {
   media_galleries::UsageCount(media_galleries::SHOW_DIALOG);
-  const Extension* extension = GetExtension();
   WebContents* contents =
-      GetWebContents(render_view_host(), GetProfile(), extension->id());
+      GetWebContents(render_view_host(), GetProfile(), extension()->id());
   if (!contents) {
     SendResponse(false);
     return;
@@ -423,7 +546,7 @@ void MediaGalleriesGetMediaFileSystemsFunction::ShowDialog() {
   // Controller will delete itself.
   base::Closure cb = base::Bind(
       &MediaGalleriesGetMediaFileSystemsFunction::GetAndReturnGalleries, this);
-  new MediaGalleriesDialogController(contents, *extension, cb);
+  new MediaGalleriesPermissionController(contents, *extension(), cb);
 }
 
 void MediaGalleriesGetMediaFileSystemsFunction::GetMediaFileSystemsForExtension(
@@ -435,13 +558,17 @@ void MediaGalleriesGetMediaFileSystemsFunction::GetMediaFileSystemsForExtension(
   MediaFileSystemRegistry* registry = media_file_system_registry();
   DCHECK(registry->GetPreferences(GetProfile())->IsInitialized());
   registry->GetMediaFileSystemsForExtension(
-      render_view_host(), GetExtension(), cb);
+      render_view_host(), extension(), cb);
 }
 
+
+///////////////////////////////////////////////////////////////////////////////
+//          MediaGalleriesGetAllMediaFileSystemMetadataFunction              //
+///////////////////////////////////////////////////////////////////////////////
 MediaGalleriesGetAllMediaFileSystemMetadataFunction::
     ~MediaGalleriesGetAllMediaFileSystemMetadataFunction() {}
 
-bool MediaGalleriesGetAllMediaFileSystemMetadataFunction::RunImpl() {
+bool MediaGalleriesGetAllMediaFileSystemMetadataFunction::RunAsync() {
   media_galleries::UsageCount(
       media_galleries::GET_ALL_MEDIA_FILE_SYSTEM_METADATA);
   return Setup(GetProfile(), &error_, base::Bind(
@@ -454,7 +581,7 @@ void MediaGalleriesGetAllMediaFileSystemMetadataFunction::OnPreferencesInit() {
   MediaGalleriesPreferences* prefs = registry->GetPreferences(GetProfile());
   DCHECK(prefs->IsInitialized());
   MediaGalleryPrefIdSet permitted_gallery_ids =
-      prefs->GalleriesForExtension(*GetExtension());
+      prefs->GalleriesForExtension(*extension());
 
   MediaStorageUtil::DeviceIdSet* device_ids = new MediaStorageUtil::DeviceIdSet;
   const MediaGalleriesPrefInfoMap& galleries = prefs->known_galleries();
@@ -500,10 +627,13 @@ void MediaGalleriesGetAllMediaFileSystemMetadataFunction::OnGetGalleries(
   SendResponse(true);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//               MediaGalleriesAddUserSelectedFolderFunction                 //
+///////////////////////////////////////////////////////////////////////////////
 MediaGalleriesAddUserSelectedFolderFunction::
     ~MediaGalleriesAddUserSelectedFolderFunction() {}
 
-bool MediaGalleriesAddUserSelectedFolderFunction::RunImpl() {
+bool MediaGalleriesAddUserSelectedFolderFunction::RunAsync() {
   media_galleries::UsageCount(media_galleries::ADD_USER_SELECTED_FOLDER);
   return Setup(GetProfile(), &error_, base::Bind(
       &MediaGalleriesAddUserSelectedFolderFunction::OnPreferencesInit, this));
@@ -511,11 +641,19 @@ bool MediaGalleriesAddUserSelectedFolderFunction::RunImpl() {
 
 void MediaGalleriesAddUserSelectedFolderFunction::OnPreferencesInit() {
   Profile* profile = GetProfile();
-  const std::string& app_id = GetExtension()->id();
+  const std::string& app_id = extension()->id();
   WebContents* contents = GetWebContents(render_view_host(), profile, app_id);
   if (!contents) {
-    SendResponse(false);
-    return;
+    // When the request originated from a background page, but there is no app
+    // window open, check to see if it originated from a tab and display the
+    // dialog in that tab.
+    bool found_tab = extensions::ExtensionTabUtil::GetTabById(
+        source_tab_id(), profile, profile->IsOffTheRecord(),
+        NULL, NULL, &contents, NULL);
+    if (!found_tab || !contents) {
+      SendResponse(false);
+      return;
+    }
   }
 
   if (!user_gesture()) {
@@ -546,7 +684,7 @@ void MediaGalleriesAddUserSelectedFolderFunction::OnDirectorySelected(
 
   extensions::file_system_api::SetLastChooseEntryDirectory(
       extensions::ExtensionPrefs::Get(GetProfile()),
-      GetExtension()->id(),
+      extension()->id(),
       selected_directory);
 
   MediaGalleriesPreferences* preferences =
@@ -554,7 +692,7 @@ void MediaGalleriesAddUserSelectedFolderFunction::OnDirectorySelected(
   MediaGalleryPrefId pref_id =
       preferences->AddGalleryByPath(selected_directory,
                                     MediaGalleryPrefInfo::kUserAdded);
-  preferences->SetGalleryPermissionForExtension(*GetExtension(), pref_id, true);
+  preferences->SetGalleryPermissionForExtension(*extension(), pref_id, true);
 
   GetMediaFileSystemsForExtension(base::Bind(
       &MediaGalleriesAddUserSelectedFolderFunction::ReturnGalleriesAndId,
@@ -566,7 +704,7 @@ void MediaGalleriesAddUserSelectedFolderFunction::ReturnGalleriesAndId(
     MediaGalleryPrefId pref_id,
     const std::vector<MediaFileSystemInfo>& filesystems) {
   scoped_ptr<base::ListValue> list(
-      ConstructFileSystemList(render_view_host(), GetExtension(), filesystems));
+      ConstructFileSystemList(render_view_host(), extension(), filesystems));
   if (!list.get()) {
     SendResponse(false);
     return;
@@ -598,68 +736,156 @@ MediaGalleriesAddUserSelectedFolderFunction::GetMediaFileSystemsForExtension(
   MediaFileSystemRegistry* registry = media_file_system_registry();
   DCHECK(registry->GetPreferences(GetProfile())->IsInitialized());
   registry->GetMediaFileSystemsForExtension(
-      render_view_host(), GetExtension(), cb);
+      render_view_host(), extension(), cb);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//         MediaGalleriesDropPermissionForMediaFileSystemFunction            //
+///////////////////////////////////////////////////////////////////////////////
+MediaGalleriesDropPermissionForMediaFileSystemFunction::
+    ~MediaGalleriesDropPermissionForMediaFileSystemFunction() {}
+
+bool MediaGalleriesDropPermissionForMediaFileSystemFunction::RunAsync() {
+  media_galleries::UsageCount(
+      media_galleries::DROP_PERMISSION_FOR_MEDIA_FILE_SYSTEM);
+
+  scoped_ptr<DropPermissionForMediaFileSystem::Params> params(
+      DropPermissionForMediaFileSystem::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+  MediaGalleryPrefId pref_id;
+  if (!base::StringToUint64(params->gallery_id, &pref_id)) {
+    error_ = kInvalidGalleryIdMsg;
+    return false;
+  }
+
+  base::Closure callback = base::Bind(
+      &MediaGalleriesDropPermissionForMediaFileSystemFunction::
+          OnPreferencesInit,
+      this,
+      pref_id);
+  return Setup(GetProfile(), &error_, callback);
 }
 
+void MediaGalleriesDropPermissionForMediaFileSystemFunction::OnPreferencesInit(
+    MediaGalleryPrefId pref_id) {
+  MediaGalleriesPreferences* preferences =
+      media_file_system_registry()->GetPreferences(GetProfile());
+  if (!ContainsKey(preferences->known_galleries(), pref_id)) {
+    error_ = kNonExistentGalleryId;
+    SendResponse(false);
+    return;
+  }
+
+  bool dropped = preferences->SetGalleryPermissionForExtension(
+      *extension(), pref_id, false);
+  if (dropped)
+    SetResult(new base::StringValue(base::Uint64ToString(pref_id)));
+  else
+    error_ = kFailedToSetGalleryPermission;
+  SendResponse(dropped);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                 MediaGalleriesStartMediaScanFunction                      //
+///////////////////////////////////////////////////////////////////////////////
 MediaGalleriesStartMediaScanFunction::~MediaGalleriesStartMediaScanFunction() {}
 
-bool MediaGalleriesStartMediaScanFunction::RunImpl() {
+bool MediaGalleriesStartMediaScanFunction::RunAsync() {
   media_galleries::UsageCount(media_galleries::START_MEDIA_SCAN);
+  if (!CheckScanPermission(extension(), &error_)) {
+    MediaGalleriesEventRouter::Get(GetProfile())
+        ->OnScanError(extension()->id());
+    return false;
+  }
   return Setup(GetProfile(), &error_, base::Bind(
       &MediaGalleriesStartMediaScanFunction::OnPreferencesInit, this));
 }
 
 void MediaGalleriesStartMediaScanFunction::OnPreferencesInit() {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   MediaGalleriesEventRouter* api = MediaGalleriesEventRouter::Get(GetProfile());
-  if (!api->ExtensionHasScanProgressListener(GetExtension()->id())) {
+  if (!api->ExtensionHasScanProgressListener(extension()->id())) {
     error_ = kMissingEventListener;
     SendResponse(false);
     return;
   }
 
-  media_scan_manager()->StartScan(GetProfile(), GetExtension()->id());
+  media_scan_manager()->StartScan(GetProfile(), extension(), user_gesture());
   SendResponse(true);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                MediaGalleriesCancelMediaScanFunction                      //
+///////////////////////////////////////////////////////////////////////////////
 MediaGalleriesCancelMediaScanFunction::
     ~MediaGalleriesCancelMediaScanFunction() {
 }
 
-bool MediaGalleriesCancelMediaScanFunction::RunImpl() {
+bool MediaGalleriesCancelMediaScanFunction::RunAsync() {
   media_galleries::UsageCount(media_galleries::CANCEL_MEDIA_SCAN);
+  if (!CheckScanPermission(extension(), &error_)) {
+    MediaGalleriesEventRouter::Get(GetProfile())
+        ->OnScanError(extension()->id());
+    return false;
+  }
   return Setup(GetProfile(), &error_, base::Bind(
       &MediaGalleriesCancelMediaScanFunction::OnPreferencesInit, this));
 }
 
 void MediaGalleriesCancelMediaScanFunction::OnPreferencesInit() {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  media_scan_manager()->CancelScan(GetProfile(), GetExtension()->id());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  media_scan_manager()->CancelScan(GetProfile(), extension());
   SendResponse(true);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                MediaGalleriesAddScanResultsFunction                       //
+///////////////////////////////////////////////////////////////////////////////
 MediaGalleriesAddScanResultsFunction::~MediaGalleriesAddScanResultsFunction() {}
 
-bool MediaGalleriesAddScanResultsFunction::RunImpl() {
+bool MediaGalleriesAddScanResultsFunction::RunAsync() {
   media_galleries::UsageCount(media_galleries::ADD_SCAN_RESULTS);
+  if (!CheckScanPermission(extension(), &error_)) {
+    // We don't fire a scan progress error here, as it would be unintuitive.
+    return false;
+  }
+  if (!user_gesture())
+    return false;
+
   return Setup(GetProfile(), &error_, base::Bind(
       &MediaGalleriesAddScanResultsFunction::OnPreferencesInit, this));
 }
 
+MediaGalleriesScanResultController*
+MediaGalleriesAddScanResultsFunction::MakeDialog(
+    content::WebContents* web_contents,
+    const extensions::Extension& extension,
+    const base::Closure& on_finish) {
+  // Controller will delete itself.
+  return new MediaGalleriesScanResultController(web_contents, extension,
+                                                on_finish);
+}
+
 void MediaGalleriesAddScanResultsFunction::OnPreferencesInit() {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  const Extension* extension = GetExtension();
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  MediaGalleriesPreferences* preferences =
+      media_file_system_registry()->GetPreferences(GetProfile());
+  if (MediaGalleriesScanResultController::ScanResultCountForExtension(
+          preferences, extension()) == 0) {
+    GetAndReturnGalleries();
+    return;
+  }
+
   WebContents* contents =
-      GetWebContents(render_view_host(), GetProfile(), extension->id());
+      GetWebContents(render_view_host(), GetProfile(), extension()->id());
   if (!contents) {
     SendResponse(false);
     return;
   }
 
-  // Controller will delete itself.
   base::Closure cb = base::Bind(
       &MediaGalleriesAddScanResultsFunction::GetAndReturnGalleries, this);
-  new MediaGalleriesScanResultDialogController(contents, *extension, cb);
+  MakeDialog(contents, *extension(), cb);
 }
 
 void MediaGalleriesAddScanResultsFunction::GetAndReturnGalleries() {
@@ -670,15 +896,15 @@ void MediaGalleriesAddScanResultsFunction::GetAndReturnGalleries() {
   MediaFileSystemRegistry* registry = media_file_system_registry();
   DCHECK(registry->GetPreferences(GetProfile())->IsInitialized());
   registry->GetMediaFileSystemsForExtension(
-      render_view_host(), GetExtension(),
-      base::Bind(&MediaGalleriesAddScanResultsFunction::ReturnGalleries,
-                 this));
+      render_view_host(),
+      extension(),
+      base::Bind(&MediaGalleriesAddScanResultsFunction::ReturnGalleries, this));
 }
 
 void MediaGalleriesAddScanResultsFunction::ReturnGalleries(
     const std::vector<MediaFileSystemInfo>& filesystems) {
   scoped_ptr<base::ListValue> list(
-      ConstructFileSystemList(render_view_host(), GetExtension(), filesystems));
+      ConstructFileSystemList(render_view_host(), extension(), filesystems));
   if (!list.get()) {
     SendResponse(false);
     return;
@@ -689,9 +915,12 @@ void MediaGalleriesAddScanResultsFunction::ReturnGalleries(
   SendResponse(true);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+//                 MediaGalleriesGetMetadataFunction                         //
+///////////////////////////////////////////////////////////////////////////////
 MediaGalleriesGetMetadataFunction::~MediaGalleriesGetMetadataFunction() {}
 
-bool MediaGalleriesGetMetadataFunction::RunImpl() {
+bool MediaGalleriesGetMetadataFunction::RunAsync() {
   std::string blob_uuid;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &blob_uuid));
 
@@ -703,44 +932,346 @@ bool MediaGalleriesGetMetadataFunction::RunImpl() {
   if (!options)
     return false;
 
-  bool mime_type_only = options->metadata_type ==
-      MediaGalleries::GET_METADATA_TYPE_MIMETYPEONLY;
-
   return Setup(GetProfile(), &error_, base::Bind(
       &MediaGalleriesGetMetadataFunction::OnPreferencesInit, this,
-      mime_type_only, blob_uuid));
+      options->metadata_type, blob_uuid));
 }
 
 void MediaGalleriesGetMetadataFunction::OnPreferencesInit(
-    bool mime_type_only, const std::string& blob_uuid) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+    MediaGalleries::GetMetadataType metadata_type,
+    const std::string& blob_uuid) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // BlobReader is self-deleting.
   BlobReader* reader = new BlobReader(
       GetProfile(),
       blob_uuid,
-      base::Bind(&MediaGalleriesGetMetadataFunction::SniffMimeType, this,
-                 mime_type_only));
+      base::Bind(&MediaGalleriesGetMetadataFunction::GetMetadata, this,
+                 metadata_type, blob_uuid));
   reader->SetByteRange(0, net::kMaxBytesToSniff);
   reader->Start();
 }
 
-void MediaGalleriesGetMetadataFunction::SniffMimeType(
-    bool mime_type_only, scoped_ptr<std::string> blob_header,
-    int64 /* total_blob_length */) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-
-  MediaGalleries::MediaMetadata metadata;
+void MediaGalleriesGetMetadataFunction::GetMetadata(
+    MediaGalleries::GetMetadataType metadata_type, const std::string& blob_uuid,
+    scoped_ptr<std::string> blob_header, int64 total_blob_length) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   std::string mime_type;
   bool mime_type_sniffed = net::SniffMimeTypeFromLocalData(
       blob_header->c_str(), blob_header->size(), &mime_type);
-  if (mime_type_sniffed)
+
+  if (!mime_type_sniffed) {
+    SendResponse(false);
+    return;
+  }
+
+  if (metadata_type == MediaGalleries::GET_METADATA_TYPE_MIMETYPEONLY) {
+    MediaGalleries::MediaMetadata metadata;
     metadata.mime_type = mime_type;
 
-  // TODO(tommycli): Kick off SafeMediaMetadataParser if |mime_type_only| false.
+    base::DictionaryValue* result_dictionary = new base::DictionaryValue;
+    result_dictionary->Set(kMetadataKey, metadata.ToValue().release());
+    SetResult(result_dictionary);
+    SendResponse(true);
+    return;
+  }
+
+  // We get attached images by default. GET_METADATA_TYPE_NONE is the default
+  // value if the caller doesn't specify the metadata type.
+  bool get_attached_images =
+      metadata_type == MediaGalleries::GET_METADATA_TYPE_ALL ||
+      metadata_type == MediaGalleries::GET_METADATA_TYPE_NONE;
+
+  scoped_refptr<metadata::SafeMediaMetadataParser> parser(
+      new metadata::SafeMediaMetadataParser(GetProfile(), blob_uuid,
+                                            total_blob_length, mime_type,
+                                            get_attached_images));
+  parser->Start(base::Bind(
+      &MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone, this));
+}
+
+void MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone(
+    bool parse_success, scoped_ptr<base::DictionaryValue> metadata_dictionary,
+    scoped_ptr<std::vector<metadata::AttachedImage> > attached_images) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (!parse_success) {
+    SendResponse(false);
+    return;
+  }
+
+  DCHECK(metadata_dictionary.get());
+  DCHECK(attached_images.get());
+
+  scoped_ptr<base::DictionaryValue> result_dictionary(
+      new base::DictionaryValue);
+  result_dictionary->Set(kMetadataKey, metadata_dictionary.release());
+
+  if (attached_images->empty()) {
+    SetResult(result_dictionary.release());
+    SendResponse(true);
+    return;
+  }
+
+  result_dictionary->Set(kAttachedImagesBlobInfoKey, new base::ListValue);
+  metadata::AttachedImage* first_image = &attached_images->front();
+  content::BrowserContext::CreateMemoryBackedBlob(
+      GetProfile(),
+      first_image->data.c_str(),
+      first_image->data.size(),
+      base::Bind(&MediaGalleriesGetMetadataFunction::ConstructNextBlob,
+                 this, base::Passed(&result_dictionary),
+                 base::Passed(&attached_images),
+                 base::Passed(make_scoped_ptr(new std::vector<std::string>))));
+}
+
+void MediaGalleriesGetMetadataFunction::ConstructNextBlob(
+    scoped_ptr<base::DictionaryValue> result_dictionary,
+    scoped_ptr<std::vector<metadata::AttachedImage> > attached_images,
+    scoped_ptr<std::vector<std::string> > blob_uuids,
+    scoped_ptr<content::BlobHandle> current_blob) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  DCHECK(result_dictionary.get());
+  DCHECK(attached_images.get());
+  DCHECK(blob_uuids.get());
+  DCHECK(current_blob.get());
+
+  DCHECK(!attached_images->empty());
+  DCHECK_LT(blob_uuids->size(), attached_images->size());
+
+  // For the newly constructed Blob, store its image's metadata and Blob UUID.
+  base::ListValue* attached_images_list = NULL;
+  result_dictionary->GetList(kAttachedImagesBlobInfoKey, &attached_images_list);
+  DCHECK(attached_images_list);
+  DCHECK_LT(attached_images_list->GetSize(), attached_images->size());
+
+  metadata::AttachedImage* current_image =
+      &(*attached_images)[blob_uuids->size()];
+  base::DictionaryValue* attached_image = new base::DictionaryValue;
+  attached_image->Set(kBlobUUIDKey, new base::StringValue(
+      current_blob->GetUUID()));
+  attached_image->Set(kTypeKey, new base::StringValue(
+      current_image->type));
+  attached_image->Set(kSizeKey, new base::FundamentalValue(
+      base::checked_cast<int>(current_image->data.size())));
+  attached_images_list->Append(attached_image);
+
+  blob_uuids->push_back(current_blob->GetUUID());
+  WebContents* contents = WebContents::FromRenderViewHost(render_view_host());
+  extensions::BlobHolder* holder =
+      extensions::BlobHolder::FromRenderProcessHost(
+          contents->GetRenderProcessHost());
+  holder->HoldBlobReference(current_blob.Pass());
+
+  // Construct the next Blob if necessary.
+  if (blob_uuids->size() < attached_images->size()) {
+    metadata::AttachedImage* next_image =
+        &(*attached_images)[blob_uuids->size()];
+    content::BrowserContext::CreateMemoryBackedBlob(
+        GetProfile(),
+        next_image->data.c_str(),
+        next_image->data.size(),
+        base::Bind(&MediaGalleriesGetMetadataFunction::ConstructNextBlob,
+                   this, base::Passed(&result_dictionary),
+                   base::Passed(&attached_images), base::Passed(&blob_uuids)));
+    return;
+  }
+
+  // All Blobs have been constructed. The renderer will take ownership.
+  SetResult(result_dictionary.release());
+  SetTransferredBlobUUIDs(*blob_uuids);
+  SendResponse(true);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//              MediaGalleriesAddGalleryWatchFunction                        //
+///////////////////////////////////////////////////////////////////////////////
+MediaGalleriesAddGalleryWatchFunction::
+    ~MediaGalleriesAddGalleryWatchFunction() {
+}
+
+bool MediaGalleriesAddGalleryWatchFunction::RunAsync() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(GetProfile());
+  if (!render_view_host() || !render_view_host()->GetProcess())
+    return false;
+
+  scoped_ptr<AddGalleryWatch::Params> params(
+      AddGalleryWatch::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+
+  MediaGalleriesPreferences* preferences =
+      g_browser_process->media_file_system_registry()->GetPreferences(
+          GetProfile());
+  preferences->EnsureInitialized(
+      base::Bind(&MediaGalleriesAddGalleryWatchFunction::OnPreferencesInit,
+                 this,
+                 params->gallery_id));
+
+  return true;
+}
+
+void MediaGalleriesAddGalleryWatchFunction::OnPreferencesInit(
+    const std::string& pref_id) {
+  base::FilePath gallery_file_path;
+  MediaGalleryPrefId gallery_pref_id = kInvalidMediaGalleryPrefId;
+  if (!GetGalleryFilePathAndId(pref_id,
+                               GetProfile(),
+                               extension(),
+                               &gallery_file_path,
+                               &gallery_pref_id)) {
+    api::media_galleries::AddGalleryWatchResult result;
+    error_ = kInvalidGalleryIdMsg;
+    result.gallery_id = kInvalidGalleryId;
+    result.success = false;
+    SetResult(result.ToValue().release());
+    SendResponse(false);
+    return;
+  }
+
+  gallery_watch_manager()->AddWatch(
+      GetProfile(),
+      extension(),
+      gallery_pref_id,
+      base::Bind(&MediaGalleriesAddGalleryWatchFunction::HandleResponse,
+                 this,
+                 gallery_pref_id));
+}
+
+void MediaGalleriesAddGalleryWatchFunction::HandleResponse(
+    MediaGalleryPrefId gallery_id,
+    const std::string& error) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  // If an app added a file watch without any event listeners on the
+  // onGalleryChanged event, that's an error.
+  MediaGalleriesEventRouter* api = MediaGalleriesEventRouter::Get(GetProfile());
+  api::media_galleries::AddGalleryWatchResult result;
+  result.gallery_id = base::Uint64ToString(gallery_id);
+
+  if (!api->ExtensionHasGalleryChangeListener(extension()->id())) {
+    result.success = false;
+    SetResult(result.ToValue().release());
+    error_ = kMissingEventListener;
+    SendResponse(false);
+    return;
+  }
+
+  result.success = error.empty();
+  SetResult(result.ToValue().release());
+  if (error.empty()) {
+    SendResponse(true);
+  } else {
+    error_ = error.c_str();
+    SendResponse(false);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//              MediaGalleriesRemoveGalleryWatchFunction                     //
+///////////////////////////////////////////////////////////////////////////////
+
+MediaGalleriesRemoveGalleryWatchFunction::
+    ~MediaGalleriesRemoveGalleryWatchFunction() {
+}
+
+bool MediaGalleriesRemoveGalleryWatchFunction::RunAsync() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!render_view_host() || !render_view_host()->GetProcess())
+    return false;
+
+  scoped_ptr<RemoveGalleryWatch::Params> params(
+      RemoveGalleryWatch::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+
+  MediaGalleriesPreferences* preferences =
+      g_browser_process->media_file_system_registry()->GetPreferences(
+          GetProfile());
+  preferences->EnsureInitialized(
+      base::Bind(&MediaGalleriesRemoveGalleryWatchFunction::OnPreferencesInit,
+                 this,
+                 params->gallery_id));
+  return true;
+}
+
+void MediaGalleriesRemoveGalleryWatchFunction::OnPreferencesInit(
+    const std::string& pref_id) {
+  base::FilePath gallery_file_path;
+  MediaGalleryPrefId gallery_pref_id = 0;
+  if (!GetGalleryFilePathAndId(pref_id,
+                               GetProfile(),
+                               extension(),
+                               &gallery_file_path,
+                               &gallery_pref_id)) {
+    error_ = kInvalidGalleryIdMsg;
+    SendResponse(false);
+    return;
+  }
+
+  gallery_watch_manager()->RemoveWatch(
+      GetProfile(), extension_id(), gallery_pref_id);
+  SendResponse(true);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//              MediaGalleriesGetAllGalleryWatchFunction                     //
+///////////////////////////////////////////////////////////////////////////////
+
+MediaGalleriesGetAllGalleryWatchFunction::
+    ~MediaGalleriesGetAllGalleryWatchFunction() {
+}
+
+bool MediaGalleriesGetAllGalleryWatchFunction::RunAsync() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!render_view_host() || !render_view_host()->GetProcess())
+    return false;
+
+  MediaGalleriesPreferences* preferences =
+      g_browser_process->media_file_system_registry()->GetPreferences(
+          GetProfile());
+  preferences->EnsureInitialized(base::Bind(
+      &MediaGalleriesGetAllGalleryWatchFunction::OnPreferencesInit, this));
+  return true;
+}
+
+void MediaGalleriesGetAllGalleryWatchFunction::OnPreferencesInit() {
+  std::vector<std::string> result;
+  MediaGalleryPrefIdSet gallery_ids =
+      gallery_watch_manager()->GetWatchSet(GetProfile(), extension_id());
+  for (MediaGalleryPrefIdSet::const_iterator iter = gallery_ids.begin();
+       iter != gallery_ids.end();
+       ++iter) {
+    result.push_back(base::Uint64ToString(*iter));
+  }
+  results_ = GetAllGalleryWatch::Results::Create(result);
+  SendResponse(true);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//              MediaGalleriesRemoveAllGalleryWatchFunction                  //
+///////////////////////////////////////////////////////////////////////////////
+
+MediaGalleriesRemoveAllGalleryWatchFunction::
+    ~MediaGalleriesRemoveAllGalleryWatchFunction() {
+}
+
+bool MediaGalleriesRemoveAllGalleryWatchFunction::RunAsync() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!render_view_host() || !render_view_host()->GetProcess())
+    return false;
+
+  MediaGalleriesPreferences* preferences =
+      g_browser_process->media_file_system_registry()->GetPreferences(
+          GetProfile());
+  preferences->EnsureInitialized(base::Bind(
+      &MediaGalleriesRemoveAllGalleryWatchFunction::OnPreferencesInit, this));
+  return true;
+}
 
-  SetResult(metadata.ToValue().release());
+void MediaGalleriesRemoveAllGalleryWatchFunction::OnPreferencesInit() {
+  gallery_watch_manager()->RemoveAllWatches(GetProfile(), extension_id());
   SendResponse(true);
 }