#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"
#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";
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;
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);
}
}
}
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:
NULL,
0,
base::FilePath::StringType(),
- platform_util::GetTopLevel(web_contents_->GetView()->GetNativeView()),
+ platform_util::GetTopLevel(web_contents_->GetNativeView()),
NULL);
}
} // 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);
}
}
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) {
}
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,
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;
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_));
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(
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));
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()) {
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;
return;
}
- media_scan_manager()->StartScan(GetProfile(), GetExtension()->id());
+ media_scan_manager()->StartScan(GetProfile(), GetExtension(), user_gesture());
SendResponse(true);
}
~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) {
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() {
MediaGalleriesGetMetadataFunction::~MediaGalleriesGetMetadataFunction() {}
-bool MediaGalleriesGetMetadataFunction::RunImpl() {
+bool MediaGalleriesGetMetadataFunction::RunAsync() {
std::string blob_uuid;
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &blob_uuid));
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);
}