1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Implements the Chrome Extensions Media Galleries API.
7 #include "chrome/browser/extensions/api/media_galleries/media_galleries_api.h"
13 #include "apps/shell_window.h"
14 #include "apps/shell_window_registry.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/platform_file.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/values.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/media_galleries/media_file_system_registry.h"
22 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h"
23 #include "chrome/browser/media_galleries/media_galleries_histograms.h"
24 #include "chrome/browser/media_galleries/media_galleries_preferences.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/browser/ui/chrome_select_file_policy.h"
27 #include "chrome/common/extensions/api/media_galleries.h"
28 #include "chrome/common/extensions/extension.h"
29 #include "chrome/common/extensions/permissions/media_galleries_permission.h"
30 #include "chrome/common/extensions/permissions/permissions_data.h"
31 #include "chrome/common/pref_names.h"
32 #include "components/web_modal/web_contents_modal_dialog_manager.h"
33 #include "content/public/browser/child_process_security_policy.h"
34 #include "content/public/browser/render_process_host.h"
35 #include "content/public/browser/render_view_host.h"
36 #include "content/public/browser/web_contents.h"
37 #include "extensions/common/permissions/api_permission.h"
40 #include "base/strings/sys_string_conversions.h"
43 using apps::ShellWindow;
44 using content::ChildProcessSecurityPolicy;
45 using content::WebContents;
46 using web_modal::WebContentsModalDialogManager;
48 namespace MediaGalleries = extensions::api::media_galleries;
49 namespace GetMediaFileSystems = MediaGalleries::GetMediaFileSystems;
51 namespace extensions {
55 const char kDisallowedByPolicy[] =
56 "Media Galleries API is disallowed by policy: ";
58 const char kDeviceIdKey[] = "deviceId";
59 const char kGalleryIdKey[] = "galleryId";
60 const char kIsMediaDeviceKey[] = "isMediaDevice";
61 const char kIsRemovableKey[] = "isRemovable";
62 const char kNameKey[] = "name";
64 // Checks whether the MediaGalleries API is currently accessible (it may be
65 // disallowed even if an extension has the requisite permission).
66 bool ApiIsAccessible(std::string* error) {
67 if (!ChromeSelectFilePolicy::FileSelectDialogsAllowed()) {
68 *error = std::string(kDisallowedByPolicy) +
69 prefs::kAllowFileSelectionDialogs;
78 MediaGalleriesGetMediaFileSystemsFunction::
79 ~MediaGalleriesGetMediaFileSystemsFunction() {}
81 bool MediaGalleriesGetMediaFileSystemsFunction::RunImpl() {
82 if (!ApiIsAccessible(&error_))
85 media_galleries::UsageCount(media_galleries::GET_MEDIA_FILE_SYSTEMS);
86 scoped_ptr<GetMediaFileSystems::Params> params(
87 GetMediaFileSystems::Params::Create(*args_));
88 EXTENSION_FUNCTION_VALIDATE(params.get());
89 MediaGalleries::GetMediaFileSystemsInteractivity interactive =
90 MediaGalleries::GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_NO;
91 if (params->details.get() && params->details->interactive != MediaGalleries::
92 GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_NONE) {
93 interactive = params->details->interactive;
96 Profile* profile = Profile::FromBrowserContext(
97 render_view_host()->GetProcess()->GetBrowserContext());
98 MediaGalleriesPreferences* preferences =
99 g_browser_process->media_file_system_registry()->GetPreferences(profile);
100 preferences->EnsureInitialized(base::Bind(
101 &MediaGalleriesGetMediaFileSystemsFunction::OnPreferencesInit,
107 void MediaGalleriesGetMediaFileSystemsFunction::OnPreferencesInit(
108 MediaGalleries::GetMediaFileSystemsInteractivity interactive) {
109 switch (interactive) {
110 case MediaGalleries::GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_YES: {
111 // The MediaFileSystemRegistry only updates preferences for extensions
112 // that it knows are in use. Since this may be the first call to
113 // chrome.getMediaFileSystems for this extension, call
114 // GetMediaFileSystemsForExtension() here solely so that
115 // MediaFileSystemRegistry will send preference changes.
116 GetMediaFileSystemsForExtension(base::Bind(
117 &MediaGalleriesGetMediaFileSystemsFunction::AlwaysShowDialog, this));
120 case MediaGalleries::GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_IF_NEEDED: {
121 GetMediaFileSystemsForExtension(base::Bind(
122 &MediaGalleriesGetMediaFileSystemsFunction::ShowDialogIfNoGalleries,
126 case MediaGalleries::GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_NO:
127 GetAndReturnGalleries();
129 case MediaGalleries::GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_NONE:
135 void MediaGalleriesGetMediaFileSystemsFunction::AlwaysShowDialog(
136 const std::vector<MediaFileSystemInfo>& /*filesystems*/) {
140 void MediaGalleriesGetMediaFileSystemsFunction::ShowDialogIfNoGalleries(
141 const std::vector<MediaFileSystemInfo>& filesystems) {
142 if (filesystems.empty())
145 ReturnGalleries(filesystems);
148 void MediaGalleriesGetMediaFileSystemsFunction::GetAndReturnGalleries() {
149 GetMediaFileSystemsForExtension(base::Bind(
150 &MediaGalleriesGetMediaFileSystemsFunction::ReturnGalleries, this));
153 void MediaGalleriesGetMediaFileSystemsFunction::ReturnGalleries(
154 const std::vector<MediaFileSystemInfo>& filesystems) {
155 content::RenderViewHost* rvh = render_view_host();
160 MediaGalleriesPermission::CheckParam read_param(
161 MediaGalleriesPermission::kReadPermission);
162 bool has_read_permission = PermissionsData::CheckAPIPermissionWithParam(
163 GetExtension(), APIPermission::kMediaGalleries, &read_param);
164 MediaGalleriesPermission::CheckParam copy_to_param(
165 MediaGalleriesPermission::kCopyToPermission);
166 bool has_copy_to_permission = PermissionsData::CheckAPIPermissionWithParam(
167 GetExtension(), APIPermission::kMediaGalleries, ©_to_param);
169 const int child_id = rvh->GetProcess()->GetID();
170 base::ListValue* list = new base::ListValue();
171 for (size_t i = 0; i < filesystems.size(); i++) {
172 scoped_ptr<base::DictionaryValue> file_system_dict_value(
173 new base::DictionaryValue());
175 // Send the file system id so the renderer can create a valid FileSystem
177 file_system_dict_value->SetStringWithoutPathExpansion(
178 "fsid", filesystems[i].fsid);
180 file_system_dict_value->SetStringWithoutPathExpansion(
181 kNameKey, filesystems[i].name);
182 file_system_dict_value->SetStringWithoutPathExpansion(
184 base::Uint64ToString(filesystems[i].pref_id));
185 if (!filesystems[i].transient_device_id.empty()) {
186 file_system_dict_value->SetStringWithoutPathExpansion(
187 kDeviceIdKey, filesystems[i].transient_device_id);
189 file_system_dict_value->SetBooleanWithoutPathExpansion(
190 kIsRemovableKey, filesystems[i].removable);
191 file_system_dict_value->SetBooleanWithoutPathExpansion(
192 kIsMediaDeviceKey, filesystems[i].media_device);
194 list->Append(file_system_dict_value.release());
196 if (filesystems[i].path.empty())
199 if (has_read_permission) {
200 content::ChildProcessSecurityPolicy* policy =
201 ChildProcessSecurityPolicy::GetInstance();
202 policy->GrantReadFileSystem(child_id, filesystems[i].fsid);
203 if (has_copy_to_permission)
204 policy->GrantCopyIntoFileSystem(child_id, filesystems[i].fsid);
212 void MediaGalleriesGetMediaFileSystemsFunction::ShowDialog() {
213 media_galleries::UsageCount(media_galleries::SHOW_DIALOG);
214 WebContents* contents = WebContents::FromRenderViewHost(render_view_host());
215 WebContentsModalDialogManager* web_contents_modal_dialog_manager =
216 WebContentsModalDialogManager::FromWebContents(contents);
217 if (!web_contents_modal_dialog_manager) {
218 // If there is no WebContentsModalDialogManager, then this contents is
219 // probably the background page for an app. Try to find a shell window to
221 ShellWindow* window = apps::ShellWindowRegistry::Get(
222 GetProfile())->GetCurrentShellWindowForApp(GetExtension()->id());
224 contents = window->web_contents();
226 // Abort showing the dialog. TODO(estade) Perhaps return an error instead.
227 GetAndReturnGalleries();
232 // Controller will delete itself.
233 base::Closure cb = base::Bind(
234 &MediaGalleriesGetMediaFileSystemsFunction::GetAndReturnGalleries, this);
235 new MediaGalleriesDialogController(contents, *GetExtension(), cb);
238 void MediaGalleriesGetMediaFileSystemsFunction::GetMediaFileSystemsForExtension(
239 const MediaFileSystemsCallback& cb) {
240 if (!render_view_host()) {
241 cb.Run(std::vector<MediaFileSystemInfo>());
244 DCHECK(g_browser_process->media_file_system_registry()
245 ->GetPreferences(GetProfile())
247 MediaFileSystemRegistry* registry =
248 g_browser_process->media_file_system_registry();
249 registry->GetMediaFileSystemsForExtension(
250 render_view_host(), GetExtension(), cb);
253 } // namespace extensions