#include <string>
#include <vector>
-#include "apps/shell_window.h"
-#include "apps/shell_window_registry.h"
-#include "base/memory/scoped_ptr.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"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/values.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/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_preferences.h"
+#include "chrome/browser/media_galleries/media_galleries_scan_result_dialog_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/ui/chrome_select_file_policy.h"
#include "chrome/common/extensions/api/media_galleries.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/permissions/media_galleries_permission.h"
-#include "chrome/common/extensions/permissions/permissions_data.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 "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"
-#if defined(OS_WIN)
-#include "base/strings/sys_string_conversions.h"
-#endif
-
-using apps::ShellWindow;
-using content::ChildProcessSecurityPolicy;
using content::WebContents;
+using storage_monitor::MediaStorageUtil;
+using storage_monitor::StorageInfo;
using web_modal::WebContentsModalDialogManager;
-namespace MediaGalleries = extensions::api::media_galleries;
-namespace GetMediaFileSystems = MediaGalleries::GetMediaFileSystems;
-
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 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";
+const char kIsAvailableKey[] = "isAvailable";
const char kIsMediaDeviceKey[] = "isMediaDevice";
const char kIsRemovableKey[] = "isRemovable";
const char kNameKey[] = "name";
+MediaFileSystemRegistry* media_file_system_registry() {
+ return g_browser_process->media_file_system_registry();
+}
+
+MediaScanManager* media_scan_manager() {
+ return media_file_system_registry()->media_scan_manager();
+}
+
// Checks whether the MediaGalleries API is currently accessible (it may be
-// disallowed even if an extension has the requisite permission).
-bool ApiIsAccessible(std::string* error) {
+// disallowed even if an extension has the requisite permission). Then
+// initializes the MediaGalleriesPreferences
+bool Setup(Profile* profile, std::string* error, base::Closure callback) {
if (!ChromeSelectFilePolicy::FileSelectDialogsAllowed()) {
*error = std::string(kDisallowedByPolicy) +
prefs::kAllowFileSelectionDialogs;
return false;
}
+ MediaGalleriesPreferences* preferences =
+ media_file_system_registry()->GetPreferences(profile);
+ preferences->EnsureInitialized(callback);
return true;
}
+WebContents* GetWebContents(content::RenderViewHost* rvh,
+ Profile* profile,
+ const std::string& app_id) {
+ WebContents* contents = WebContents::FromRenderViewHost(rvh);
+ WebContentsModalDialogManager* web_contents_modal_dialog_manager =
+ 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 app window to
+ // host the dialog.
+ apps::AppWindow* window = apps::AppWindowRegistry::Get(profile)
+ ->GetCurrentAppWindowForApp(app_id);
+ contents = window ? window->web_contents() : NULL;
+ }
+ return contents;
+}
+
+base::ListValue* ConstructFileSystemList(
+ content::RenderViewHost* rvh,
+ const Extension* extension,
+ const std::vector<MediaFileSystemInfo>& filesystems) {
+ if (!rvh)
+ return NULL;
+
+ MediaGalleriesPermission::CheckParam read_param(
+ MediaGalleriesPermission::kReadPermission);
+ bool has_read_permission = PermissionsData::CheckAPIPermissionWithParam(
+ extension, APIPermission::kMediaGalleries, &read_param);
+ MediaGalleriesPermission::CheckParam copy_to_param(
+ MediaGalleriesPermission::kCopyToPermission);
+ bool has_copy_to_permission = PermissionsData::CheckAPIPermissionWithParam(
+ extension, APIPermission::kMediaGalleries, ©_to_param);
+ MediaGalleriesPermission::CheckParam delete_param(
+ MediaGalleriesPermission::kDeletePermission);
+ bool has_delete_permission = PermissionsData::CheckAPIPermissionWithParam(
+ extension, APIPermission::kMediaGalleries, &delete_param);
+
+ const int child_id = rvh->GetProcess()->GetID();
+ scoped_ptr<base::ListValue> list(new base::ListValue());
+ for (size_t i = 0; i < filesystems.size(); ++i) {
+ scoped_ptr<base::DictionaryValue> file_system_dict_value(
+ new base::DictionaryValue());
+
+ // Send the file system id so the renderer can create a valid FileSystem
+ // object.
+ file_system_dict_value->SetStringWithoutPathExpansion(
+ "fsid", filesystems[i].fsid);
+
+ file_system_dict_value->SetStringWithoutPathExpansion(
+ kNameKey, filesystems[i].name);
+ file_system_dict_value->SetStringWithoutPathExpansion(
+ kGalleryIdKey,
+ base::Uint64ToString(filesystems[i].pref_id));
+ if (!filesystems[i].transient_device_id.empty()) {
+ file_system_dict_value->SetStringWithoutPathExpansion(
+ kDeviceIdKey, filesystems[i].transient_device_id);
+ }
+ file_system_dict_value->SetBooleanWithoutPathExpansion(
+ kIsRemovableKey, filesystems[i].removable);
+ file_system_dict_value->SetBooleanWithoutPathExpansion(
+ kIsMediaDeviceKey, filesystems[i].media_device);
+ file_system_dict_value->SetBooleanWithoutPathExpansion(
+ kIsAvailableKey, true);
+
+ list->Append(file_system_dict_value.release());
+
+ if (filesystems[i].path.empty())
+ continue;
+
+ if (has_read_permission) {
+ content::ChildProcessSecurityPolicy* policy =
+ content::ChildProcessSecurityPolicy::GetInstance();
+ policy->GrantReadFile(child_id, filesystems[i].path);
+ if (has_delete_permission) {
+ policy->GrantDeleteFrom(child_id, filesystems[i].path);
+ if (has_copy_to_permission) {
+ policy->GrantCopyInto(child_id, filesystems[i].path);
+ }
+ }
+ }
+ }
+
+ 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:
+ // Selected file path, or an empty path if the user canceled.
+ typedef base::Callback<void(const base::FilePath&)> Callback;
+
+ SelectDirectoryDialog(WebContents* web_contents, const Callback& callback)
+ : web_contents_(web_contents),
+ callback_(callback) {
+ select_file_dialog_ = ui::SelectFileDialog::Create(
+ this, new ChromeSelectFilePolicy(web_contents));
+ }
+
+ void Show(const base::FilePath& default_path) {
+ AddRef(); // Balanced in the two reachable listener outcomes.
+ select_file_dialog_->SelectFile(
+ ui::SelectFileDialog::SELECT_FOLDER,
+ l10n_util::GetStringUTF16(IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY_TITLE),
+ default_path,
+ NULL,
+ 0,
+ base::FilePath::StringType(),
+ platform_util::GetTopLevel(web_contents_->GetNativeView()),
+ NULL);
+ }
+
+ // ui::SelectFileDialog::Listener implementation.
+ virtual 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 {
+ NOTREACHED() << "Should not be able to select multiple files";
+ }
+
+ virtual void FileSelectionCanceled(void* params) OVERRIDE {
+ callback_.Run(base::FilePath());
+ Release(); // Balanced in Show().
+ }
+
+ private:
+ friend class base::RefCounted<SelectDirectoryDialog>;
+ virtual ~SelectDirectoryDialog() {}
+
+ scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
+ WebContents* web_contents_;
+ Callback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(SelectDirectoryDialog);
+};
+
} // namespace
+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);
+}
+
+MediaGalleriesEventRouter::~MediaGalleriesEventRouter() {
+}
+
+void MediaGalleriesEventRouter::Shutdown() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ media_scan_manager()->RemoveObserver(profile_);
+ media_scan_manager()->CancelScansForProfile(profile_);
+}
+
+static base::LazyInstance<
+ BrowserContextKeyedAPIFactory<MediaGalleriesEventRouter> > g_factory =
+ LAZY_INSTANCE_INITIALIZER;
+
+// static
+BrowserContextKeyedAPIFactory<MediaGalleriesEventRouter>*
+MediaGalleriesEventRouter::GetFactoryInstance() {
+ return g_factory.Pointer();
+}
+
+// static
+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 {
+ return EventRouter::Get(profile_)->ExtensionHasEventListener(
+ extension_id, MediaGalleries::OnScanProgress::kEventName);
+}
+
+void MediaGalleriesEventRouter::OnScanStarted(const std::string& extension_id) {
+ MediaGalleries::ScanProgressDetails details;
+ details.type = MediaGalleries::SCAN_PROGRESS_TYPE_START;
+ DispatchEventToExtension(
+ extension_id,
+ MediaGalleries::OnScanProgress::kEventName,
+ MediaGalleries::OnScanProgress::Create(details).Pass());
+}
+
+void MediaGalleriesEventRouter::OnScanCancelled(
+ const std::string& extension_id) {
+ MediaGalleries::ScanProgressDetails details;
+ details.type = MediaGalleries::SCAN_PROGRESS_TYPE_CANCEL;
+ DispatchEventToExtension(
+ extension_id,
+ MediaGalleries::OnScanProgress::kEventName,
+ MediaGalleries::OnScanProgress::Create(details).Pass());
+}
+
+void MediaGalleriesEventRouter::OnScanFinished(
+ 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.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,
+ MediaGalleries::OnScanProgress::Create(details).Pass());
+}
+
+void MediaGalleriesEventRouter::DispatchEventToExtension(
+ const std::string& extension_id,
+ const std::string& event_name,
+ scoped_ptr<base::ListValue> event_args) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ EventRouter* router = EventRouter::Get(profile_);
+ if (!router->ExtensionHasEventListener(extension_id, event_name))
+ return;
+
+ scoped_ptr<extensions::Event> event(
+ new extensions::Event(event_name, event_args.Pass()));
+ router->DispatchEventToExtension(extension_id, event.Pass());
+}
+
MediaGalleriesGetMediaFileSystemsFunction::
~MediaGalleriesGetMediaFileSystemsFunction() {}
-bool MediaGalleriesGetMediaFileSystemsFunction::RunImpl() {
- if (!ApiIsAccessible(&error_))
- return false;
-
+bool MediaGalleriesGetMediaFileSystemsFunction::RunAsync() {
media_galleries::UsageCount(media_galleries::GET_MEDIA_FILE_SYSTEMS);
scoped_ptr<GetMediaFileSystems::Params> params(
GetMediaFileSystems::Params::Create(*args_));
interactive = params->details->interactive;
}
- Profile* profile = Profile::FromBrowserContext(
- render_view_host()->GetProcess()->GetBrowserContext());
- MediaGalleriesPreferences* preferences =
- g_browser_process->media_file_system_registry()->GetPreferences(profile);
- preferences->EnsureInitialized(base::Bind(
- &MediaGalleriesGetMediaFileSystemsFunction::OnPreferencesInit,
- this,
+ return Setup(GetProfile(), &error_, base::Bind(
+ &MediaGalleriesGetMediaFileSystemsFunction::OnPreferencesInit, this,
interactive));
- return true;
}
void MediaGalleriesGetMediaFileSystemsFunction::OnPreferencesInit(
void MediaGalleriesGetMediaFileSystemsFunction::ReturnGalleries(
const std::vector<MediaFileSystemInfo>& filesystems) {
- content::RenderViewHost* rvh = render_view_host();
- if (!rvh) {
+ scoped_ptr<base::ListValue> list(
+ ConstructFileSystemList(render_view_host(), GetExtension(), filesystems));
+ if (!list.get()) {
SendResponse(false);
return;
}
- MediaGalleriesPermission::CheckParam read_param(
- MediaGalleriesPermission::kReadPermission);
- bool has_read_permission = PermissionsData::CheckAPIPermissionWithParam(
- GetExtension(), APIPermission::kMediaGalleries, &read_param);
- MediaGalleriesPermission::CheckParam copy_to_param(
- MediaGalleriesPermission::kCopyToPermission);
- bool has_copy_to_permission = PermissionsData::CheckAPIPermissionWithParam(
- GetExtension(), APIPermission::kMediaGalleries, ©_to_param);
- const int child_id = rvh->GetProcess()->GetID();
- base::ListValue* list = new base::ListValue();
- for (size_t i = 0; i < filesystems.size(); i++) {
- scoped_ptr<base::DictionaryValue> file_system_dict_value(
- new base::DictionaryValue());
+ // The custom JS binding will use this list to create DOMFileSystem objects.
+ SetResult(list.release());
+ SendResponse(true);
+}
- // Send the file system id so the renderer can create a valid FileSystem
- // object.
- file_system_dict_value->SetStringWithoutPathExpansion(
- "fsid", filesystems[i].fsid);
+void MediaGalleriesGetMediaFileSystemsFunction::ShowDialog() {
+ media_galleries::UsageCount(media_galleries::SHOW_DIALOG);
+ const Extension* extension = GetExtension();
+ WebContents* contents =
+ GetWebContents(render_view_host(), GetProfile(), extension->id());
+ if (!contents) {
+ SendResponse(false);
+ return;
+ }
- file_system_dict_value->SetStringWithoutPathExpansion(
- kNameKey, filesystems[i].name);
- file_system_dict_value->SetStringWithoutPathExpansion(
- kGalleryIdKey,
- base::Uint64ToString(filesystems[i].pref_id));
- if (!filesystems[i].transient_device_id.empty()) {
- file_system_dict_value->SetStringWithoutPathExpansion(
- kDeviceIdKey, filesystems[i].transient_device_id);
- }
- file_system_dict_value->SetBooleanWithoutPathExpansion(
- kIsRemovableKey, filesystems[i].removable);
- file_system_dict_value->SetBooleanWithoutPathExpansion(
- kIsMediaDeviceKey, filesystems[i].media_device);
+ // Controller will delete itself.
+ base::Closure cb = base::Bind(
+ &MediaGalleriesGetMediaFileSystemsFunction::GetAndReturnGalleries, this);
+ new MediaGalleriesDialogController(contents, *extension, cb);
+}
- list->Append(file_system_dict_value.release());
+void MediaGalleriesGetMediaFileSystemsFunction::GetMediaFileSystemsForExtension(
+ const MediaFileSystemsCallback& cb) {
+ if (!render_view_host()) {
+ cb.Run(std::vector<MediaFileSystemInfo>());
+ return;
+ }
+ MediaFileSystemRegistry* registry = media_file_system_registry();
+ DCHECK(registry->GetPreferences(GetProfile())->IsInitialized());
+ registry->GetMediaFileSystemsForExtension(
+ render_view_host(), GetExtension(), cb);
+}
- if (filesystems[i].path.empty())
- continue;
+MediaGalleriesGetAllMediaFileSystemMetadataFunction::
+ ~MediaGalleriesGetAllMediaFileSystemMetadataFunction() {}
- if (has_read_permission) {
- content::ChildProcessSecurityPolicy* policy =
- ChildProcessSecurityPolicy::GetInstance();
- policy->GrantReadFileSystem(child_id, filesystems[i].fsid);
- if (has_copy_to_permission)
- policy->GrantCopyIntoFileSystem(child_id, filesystems[i].fsid);
- }
+bool MediaGalleriesGetAllMediaFileSystemMetadataFunction::RunAsync() {
+ media_galleries::UsageCount(
+ media_galleries::GET_ALL_MEDIA_FILE_SYSTEM_METADATA);
+ return Setup(GetProfile(), &error_, base::Bind(
+ &MediaGalleriesGetAllMediaFileSystemMetadataFunction::OnPreferencesInit,
+ this));
+}
+
+void MediaGalleriesGetAllMediaFileSystemMetadataFunction::OnPreferencesInit() {
+ MediaFileSystemRegistry* registry = media_file_system_registry();
+ MediaGalleriesPreferences* prefs = registry->GetPreferences(GetProfile());
+ DCHECK(prefs->IsInitialized());
+ MediaGalleryPrefIdSet permitted_gallery_ids =
+ prefs->GalleriesForExtension(*GetExtension());
+
+ MediaStorageUtil::DeviceIdSet* device_ids = new MediaStorageUtil::DeviceIdSet;
+ const MediaGalleriesPrefInfoMap& galleries = prefs->known_galleries();
+ for (MediaGalleryPrefIdSet::const_iterator it = permitted_gallery_ids.begin();
+ it != permitted_gallery_ids.end(); ++it) {
+ MediaGalleriesPrefInfoMap::const_iterator gallery_it = galleries.find(*it);
+ DCHECK(gallery_it != galleries.end());
+ device_ids->insert(gallery_it->second.device_id);
+ }
+
+ MediaStorageUtil::FilterAttachedDevices(
+ device_ids,
+ base::Bind(
+ &MediaGalleriesGetAllMediaFileSystemMetadataFunction::OnGetGalleries,
+ this,
+ permitted_gallery_ids,
+ base::Owned(device_ids)));
+}
+
+void MediaGalleriesGetAllMediaFileSystemMetadataFunction::OnGetGalleries(
+ const MediaGalleryPrefIdSet& permitted_gallery_ids,
+ const MediaStorageUtil::DeviceIdSet* available_devices) {
+ MediaFileSystemRegistry* registry = media_file_system_registry();
+ MediaGalleriesPreferences* prefs = registry->GetPreferences(GetProfile());
+
+ base::ListValue* list = new base::ListValue();
+ const MediaGalleriesPrefInfoMap& galleries = prefs->known_galleries();
+ for (MediaGalleryPrefIdSet::const_iterator it = permitted_gallery_ids.begin();
+ it != permitted_gallery_ids.end(); ++it) {
+ MediaGalleriesPrefInfoMap::const_iterator gallery_it = galleries.find(*it);
+ DCHECK(gallery_it != galleries.end());
+ const MediaGalleryPrefInfo& gallery = gallery_it->second;
+ MediaGalleries::MediaFileSystemMetadata metadata;
+ metadata.name = base::UTF16ToUTF8(gallery.GetGalleryDisplayName());
+ metadata.gallery_id = base::Uint64ToString(gallery.pref_id);
+ metadata.is_removable = StorageInfo::IsRemovableDevice(gallery.device_id);
+ metadata.is_media_device = StorageInfo::IsMediaDevice(gallery.device_id);
+ metadata.is_available = ContainsKey(*available_devices, gallery.device_id);
+ list->Append(metadata.ToValue().release());
}
SetResult(list);
SendResponse(true);
}
-void MediaGalleriesGetMediaFileSystemsFunction::ShowDialog() {
- media_galleries::UsageCount(media_galleries::SHOW_DIALOG);
- WebContents* contents = WebContents::FromRenderViewHost(render_view_host());
- WebContentsModalDialogManager* web_contents_modal_dialog_manager =
- 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
- // host the dialog.
- ShellWindow* window = apps::ShellWindowRegistry::Get(
- GetProfile())->GetCurrentShellWindowForApp(GetExtension()->id());
- if (window) {
- contents = window->web_contents();
- } else {
- // Abort showing the dialog. TODO(estade) Perhaps return an error instead.
- GetAndReturnGalleries();
+MediaGalleriesAddUserSelectedFolderFunction::
+ ~MediaGalleriesAddUserSelectedFolderFunction() {}
+
+bool MediaGalleriesAddUserSelectedFolderFunction::RunAsync() {
+ media_galleries::UsageCount(media_galleries::ADD_USER_SELECTED_FOLDER);
+ return Setup(GetProfile(), &error_, base::Bind(
+ &MediaGalleriesAddUserSelectedFolderFunction::OnPreferencesInit, this));
+}
+
+void MediaGalleriesAddUserSelectedFolderFunction::OnPreferencesInit() {
+ Profile* profile = GetProfile();
+ const std::string& app_id = GetExtension()->id();
+ WebContents* contents = GetWebContents(render_view_host(), profile, app_id);
+ if (!contents) {
+ // 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;
}
}
- // Controller will delete itself.
- base::Closure cb = base::Bind(
- &MediaGalleriesGetMediaFileSystemsFunction::GetAndReturnGalleries, this);
- new MediaGalleriesDialogController(contents, *GetExtension(), cb);
+ if (!user_gesture()) {
+ OnDirectorySelected(base::FilePath());
+ return;
+ }
+
+ base::FilePath last_used_path =
+ extensions::file_system_api::GetLastChooseEntryDirectory(
+ extensions::ExtensionPrefs::Get(profile), app_id);
+ SelectDirectoryDialog::Callback callback = base::Bind(
+ &MediaGalleriesAddUserSelectedFolderFunction::OnDirectorySelected, this);
+ scoped_refptr<SelectDirectoryDialog> select_directory_dialog =
+ new SelectDirectoryDialog(contents, callback);
+ select_directory_dialog->Show(last_used_path);
}
-void MediaGalleriesGetMediaFileSystemsFunction::GetMediaFileSystemsForExtension(
+void MediaGalleriesAddUserSelectedFolderFunction::OnDirectorySelected(
+ const base::FilePath& selected_directory) {
+ if (selected_directory.empty()) {
+ // User cancelled case.
+ GetMediaFileSystemsForExtension(base::Bind(
+ &MediaGalleriesAddUserSelectedFolderFunction::ReturnGalleriesAndId,
+ this,
+ kInvalidMediaGalleryPrefId));
+ return;
+ }
+
+ extensions::file_system_api::SetLastChooseEntryDirectory(
+ extensions::ExtensionPrefs::Get(GetProfile()),
+ GetExtension()->id(),
+ selected_directory);
+
+ MediaGalleriesPreferences* preferences =
+ media_file_system_registry()->GetPreferences(GetProfile());
+ MediaGalleryPrefId pref_id =
+ preferences->AddGalleryByPath(selected_directory,
+ MediaGalleryPrefInfo::kUserAdded);
+ preferences->SetGalleryPermissionForExtension(*GetExtension(), pref_id, true);
+
+ GetMediaFileSystemsForExtension(base::Bind(
+ &MediaGalleriesAddUserSelectedFolderFunction::ReturnGalleriesAndId,
+ this,
+ pref_id));
+}
+
+void MediaGalleriesAddUserSelectedFolderFunction::ReturnGalleriesAndId(
+ MediaGalleryPrefId pref_id,
+ const std::vector<MediaFileSystemInfo>& filesystems) {
+ scoped_ptr<base::ListValue> list(
+ ConstructFileSystemList(render_view_host(), GetExtension(), filesystems));
+ if (!list.get()) {
+ SendResponse(false);
+ return;
+ }
+
+ int index = -1;
+ if (pref_id != kInvalidMediaGalleryPrefId) {
+ for (size_t i = 0; i < filesystems.size(); ++i) {
+ if (filesystems[i].pref_id == pref_id) {
+ index = i;
+ break;
+ }
+ }
+ }
+ base::DictionaryValue* results = new base::DictionaryValue;
+ results->SetWithoutPathExpansion("mediaFileSystems", list.release());
+ results->SetIntegerWithoutPathExpansion("selectedFileSystemIndex", index);
+ SetResult(results);
+ SendResponse(true);
+}
+
+void
+MediaGalleriesAddUserSelectedFolderFunction::GetMediaFileSystemsForExtension(
const MediaFileSystemsCallback& cb) {
if (!render_view_host()) {
cb.Run(std::vector<MediaFileSystemInfo>());
return;
}
- DCHECK(g_browser_process->media_file_system_registry()
- ->GetPreferences(GetProfile())
- ->IsInitialized());
- MediaFileSystemRegistry* registry =
- g_browser_process->media_file_system_registry();
+ MediaFileSystemRegistry* registry = media_file_system_registry();
+ DCHECK(registry->GetPreferences(GetProfile())->IsInitialized());
registry->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::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_CURRENTLY_ON(content::BrowserThread::UI);
+ MediaGalleriesEventRouter* api = MediaGalleriesEventRouter::Get(GetProfile());
+ if (!api->ExtensionHasScanProgressListener(GetExtension()->id())) {
+ error_ = kMissingEventListener;
+ SendResponse(false);
+ return;
+ }
+
+ media_scan_manager()->StartScan(GetProfile(), GetExtension(), user_gesture());
+ SendResponse(true);
+}
+
+MediaGalleriesCancelMediaScanFunction::
+ ~MediaGalleriesCancelMediaScanFunction() {
+}
+
+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_CURRENTLY_ON(content::BrowserThread::UI);
+ media_scan_manager()->CancelScan(GetProfile(), GetExtension());
+ SendResponse(true);
+}
+
+MediaGalleriesAddScanResultsFunction::~MediaGalleriesAddScanResultsFunction() {}
+
+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_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) {
+ SendResponse(false);
+ return;
+ }
+
+ base::Closure cb = base::Bind(
+ &MediaGalleriesAddScanResultsFunction::GetAndReturnGalleries, this);
+ MakeDialog(contents, *extension, cb);
+}
+
+void MediaGalleriesAddScanResultsFunction::GetAndReturnGalleries() {
+ if (!render_view_host()) {
+ ReturnGalleries(std::vector<MediaFileSystemInfo>());
+ return;
+ }
+ MediaFileSystemRegistry* registry = media_file_system_registry();
+ DCHECK(registry->GetPreferences(GetProfile())->IsInitialized());
+ registry->GetMediaFileSystemsForExtension(
+ render_view_host(), GetExtension(),
+ base::Bind(&MediaGalleriesAddScanResultsFunction::ReturnGalleries,
+ this));
+}
+
+void MediaGalleriesAddScanResultsFunction::ReturnGalleries(
+ const std::vector<MediaFileSystemInfo>& filesystems) {
+ scoped_ptr<base::ListValue> list(
+ ConstructFileSystemList(render_view_host(), GetExtension(), filesystems));
+ if (!list.get()) {
+ SendResponse(false);
+ return;
+ }
+
+ // The custom JS binding will use this list to create DOMFileSystem objects.
+ SetResult(list.release());
+ SendResponse(true);
+}
+
+MediaGalleriesGetMetadataFunction::~MediaGalleriesGetMetadataFunction() {}
+
+bool MediaGalleriesGetMetadataFunction::RunAsync() {
+ std::string blob_uuid;
+ EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &blob_uuid));
+
+ const base::Value* options_value = NULL;
+ if (!args_->Get(1, &options_value))
+ return false;
+ scoped_ptr<MediaGalleries::MediaMetadataOptions> options =
+ MediaGalleries::MediaMetadataOptions::FromValue(*options_value);
+ 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));
+}
+
+void MediaGalleriesGetMetadataFunction::OnPreferencesInit(
+ bool mime_type_only, 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, blob_uuid));
+ reader->SetByteRange(0, net::kMaxBytesToSniff);
+ reader->Start();
+}
+
+void MediaGalleriesGetMetadataFunction::SniffMimeType(
+ 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) {
+ 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));
+}
+
+void MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone(
+ bool parse_success, base::DictionaryValue* metadata_dictionary) {
+ if (!parse_success) {
+ SendResponse(false);
+ return;
+ }
+
+ SetResult(metadata_dictionary->DeepCopy());
+ SendResponse(true);
+}
+
} // namespace extensions