Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / media_galleries / media_galleries_api.cc
index 8f1c48d..024efde 100644 (file)
@@ -10,8 +10,9 @@
 #include <string>
 #include <vector>
 
-#include "apps/shell_window.h"
-#include "apps/shell_window_registry.h"
+#include "apps/app_window.h"
+#include "apps/app_window_registry.h"
+#include "base/callback.h"
 #include "base/lazy_instance.h"
 #include "base/platform_file.h"
 #include "base/stl_util.h"
@@ -21,6 +22,8 @@
 #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/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_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 "components/storage_monitor/storage_info.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.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/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 "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 {
 
 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 kInvalidGalleryId[] = "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";
@@ -104,10 +115,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);
+    apps::AppWindow* window = apps::AppWindowRegistry::Get(profile)
+                                  ->GetCurrentAppWindowForApp(app_id);
     contents = window ? window->web_contents() : NULL;
   }
   return contents;
@@ -168,11 +179,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 +192,19 @@ 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 = PermissionsData::CheckAPIPermissionWithParam(
+      extension, 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,7 +227,7 @@ 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);
   }
 
@@ -238,10 +262,10 @@ 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_);
   media_scan_manager()->AddObserver(profile_, this);
 }
@@ -250,35 +274,35 @@ MediaGalleriesEventRouter::~MediaGalleriesEventRouter() {
 }
 
 void MediaGalleriesEventRouter::Shutdown() {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   weak_ptr_factory_.InvalidateWeakPtrs();
   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::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 +325,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 +354,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;
 
@@ -333,7 +367,7 @@ void MediaGalleriesEventRouter::DispatchEventToExtension(
 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_));
@@ -441,7 +475,7 @@ void MediaGalleriesGetMediaFileSystemsFunction::GetMediaFileSystemsForExtension(
 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(
@@ -503,7 +537,7 @@ void MediaGalleriesGetAllMediaFileSystemMetadataFunction::OnGetGalleries(
 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));
@@ -514,8 +548,16 @@ void MediaGalleriesAddUserSelectedFolderFunction::OnPreferencesInit() {
   const std::string& app_id = GetExtension()->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()) {
@@ -601,16 +643,64 @@ MediaGalleriesAddUserSelectedFolderFunction::GetMediaFileSystemsForExtension(
       render_view_host(), GetExtension(), cb);
 }
 
+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_ = kInvalidGalleryId;
+    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(
+      *GetExtension(), pref_id, false);
+  if (dropped)
+    SetResult(new base::StringValue(base::Uint64ToString(pref_id)));
+  else
+    error_ = kFailedToSetGalleryPermission;
+  SendResponse(dropped);
+}
+
 MediaGalleriesStartMediaScanFunction::~MediaGalleriesStartMediaScanFunction() {}
 
-bool MediaGalleriesStartMediaScanFunction::RunImpl() {
+bool MediaGalleriesStartMediaScanFunction::RunAsync() {
   media_galleries::UsageCount(media_galleries::START_MEDIA_SCAN);
+  if (!CheckScanPermission(GetExtension(), &error_)) {
+    MediaGalleriesEventRouter::Get(GetProfile())->OnScanError(
+        GetExtension()->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())) {
     error_ = kMissingEventListener;
@@ -618,7 +708,7 @@ void MediaGalleriesStartMediaScanFunction::OnPreferencesInit() {
     return;
   }
 
-  media_scan_manager()->StartScan(GetProfile(), GetExtension()->id());
+  media_scan_manager()->StartScan(GetProfile(), GetExtension(), user_gesture());
   SendResponse(true);
 }
 
@@ -626,29 +716,59 @@ MediaGalleriesCancelMediaScanFunction::
     ~MediaGalleriesCancelMediaScanFunction() {
 }
 
-bool MediaGalleriesCancelMediaScanFunction::RunImpl() {
+bool MediaGalleriesCancelMediaScanFunction::RunAsync() {
   media_galleries::UsageCount(media_galleries::CANCEL_MEDIA_SCAN);
+  if (!CheckScanPermission(GetExtension(), &error_)) {
+    MediaGalleriesEventRouter::Get(GetProfile())->OnScanError(
+        GetExtension()->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(), GetExtension());
   SendResponse(true);
 }
 
 MediaGalleriesAddScanResultsFunction::~MediaGalleriesAddScanResultsFunction() {}
 
-bool MediaGalleriesAddScanResultsFunction::RunImpl() {
+bool MediaGalleriesAddScanResultsFunction::RunAsync() {
   media_galleries::UsageCount(media_galleries::ADD_SCAN_RESULTS);
+  if (!CheckScanPermission(GetExtension(), &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));
 }
 
+MediaGalleriesScanResultDialogController*
+MediaGalleriesAddScanResultsFunction::MakeDialog(
+    content::WebContents* web_contents,
+    const extensions::Extension& extension,
+    const base::Closure& on_finish) {
+  // Controller will delete itself.
+  return new MediaGalleriesScanResultDialogController(web_contents, extension,
+                                                      on_finish);
+}
+
 void MediaGalleriesAddScanResultsFunction::OnPreferencesInit() {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   const Extension* extension = GetExtension();
+  MediaGalleriesPreferences* preferences =
+      media_file_system_registry()->GetPreferences(GetProfile());
+  if (MediaGalleriesScanResultDialogController::ScanResultCountForExtension(
+          preferences, extension) == 0) {
+    GetAndReturnGalleries();
+    return;
+  }
+
   WebContents* contents =
       GetWebContents(render_view_host(), GetProfile(), extension->id());
   if (!contents) {
@@ -656,10 +776,9 @@ void MediaGalleriesAddScanResultsFunction::OnPreferencesInit() {
     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() {
@@ -691,7 +810,7 @@ void MediaGalleriesAddScanResultsFunction::ReturnGalleries(
 
 MediaGalleriesGetMetadataFunction::~MediaGalleriesGetMetadataFunction() {}
 
-bool MediaGalleriesGetMetadataFunction::RunImpl() {
+bool MediaGalleriesGetMetadataFunction::RunAsync() {
   std::string blob_uuid;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &blob_uuid));
 
@@ -713,34 +832,55 @@ bool MediaGalleriesGetMetadataFunction::RunImpl() {
 
 void MediaGalleriesGetMetadataFunction::OnPreferencesInit(
     bool mime_type_only, const std::string& blob_uuid) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  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));
+                 mime_type_only, 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;
+    bool mime_type_only, 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 (mime_type_only) {
+    MediaGalleries::MediaMetadata metadata;
     metadata.mime_type = mime_type;
+    SetResult(metadata.ToValue().release());
+    SendResponse(true);
+    return;
+  }
+
+  scoped_refptr<metadata::SafeMediaMetadataParser> parser(
+      new metadata::SafeMediaMetadataParser(GetProfile(), blob_uuid,
+                                            total_blob_length, mime_type));
+  parser->Start(base::Bind(
+      &MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone, this));
+}
 
-  // TODO(tommycli): Kick off SafeMediaMetadataParser if |mime_type_only| false.
+void MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone(
+    bool parse_success, base::DictionaryValue* metadata_dictionary) {
+  if (!parse_success) {
+    SendResponse(false);
+    return;
+  }
 
-  SetResult(metadata.ToValue().release());
+  SetResult(metadata_dictionary->DeepCopy());
   SendResponse(true);
 }