- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / media_galleries / media_galleries_api.cc
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.
4
5 // Implements the Chrome Extensions Media Galleries API.
6
7 #include "chrome/browser/extensions/api/media_galleries/media_galleries_api.h"
8
9 #include <set>
10 #include <string>
11 #include <vector>
12
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"
38
39 #if defined(OS_WIN)
40 #include "base/strings/sys_string_conversions.h"
41 #endif
42
43 using apps::ShellWindow;
44 using content::ChildProcessSecurityPolicy;
45 using content::WebContents;
46 using web_modal::WebContentsModalDialogManager;
47
48 namespace MediaGalleries = extensions::api::media_galleries;
49 namespace GetMediaFileSystems = MediaGalleries::GetMediaFileSystems;
50
51 namespace extensions {
52
53 namespace {
54
55 const char kDisallowedByPolicy[] =
56     "Media Galleries API is disallowed by policy: ";
57
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";
63
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;
70     return false;
71   }
72
73   return true;
74 }
75
76 }  // namespace
77
78 MediaGalleriesGetMediaFileSystemsFunction::
79     ~MediaGalleriesGetMediaFileSystemsFunction() {}
80
81 bool MediaGalleriesGetMediaFileSystemsFunction::RunImpl() {
82   if (!ApiIsAccessible(&error_))
83     return false;
84
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;
94   }
95
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,
102       this,
103       interactive));
104   return true;
105 }
106
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));
118       return;
119     }
120     case MediaGalleries::GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_IF_NEEDED: {
121       GetMediaFileSystemsForExtension(base::Bind(
122           &MediaGalleriesGetMediaFileSystemsFunction::ShowDialogIfNoGalleries,
123           this));
124       return;
125     }
126     case MediaGalleries::GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_NO:
127       GetAndReturnGalleries();
128       return;
129     case MediaGalleries::GET_MEDIA_FILE_SYSTEMS_INTERACTIVITY_NONE:
130       NOTREACHED();
131   }
132   SendResponse(false);
133 }
134
135 void MediaGalleriesGetMediaFileSystemsFunction::AlwaysShowDialog(
136     const std::vector<MediaFileSystemInfo>& /*filesystems*/) {
137   ShowDialog();
138 }
139
140 void MediaGalleriesGetMediaFileSystemsFunction::ShowDialogIfNoGalleries(
141     const std::vector<MediaFileSystemInfo>& filesystems) {
142   if (filesystems.empty())
143     ShowDialog();
144   else
145     ReturnGalleries(filesystems);
146 }
147
148 void MediaGalleriesGetMediaFileSystemsFunction::GetAndReturnGalleries() {
149   GetMediaFileSystemsForExtension(base::Bind(
150       &MediaGalleriesGetMediaFileSystemsFunction::ReturnGalleries, this));
151 }
152
153 void MediaGalleriesGetMediaFileSystemsFunction::ReturnGalleries(
154     const std::vector<MediaFileSystemInfo>& filesystems) {
155   content::RenderViewHost* rvh = render_view_host();
156   if (!rvh) {
157     SendResponse(false);
158     return;
159   }
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, &copy_to_param);
168
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());
174
175     // Send the file system id so the renderer can create a valid FileSystem
176     // object.
177     file_system_dict_value->SetStringWithoutPathExpansion(
178         "fsid", filesystems[i].fsid);
179
180     file_system_dict_value->SetStringWithoutPathExpansion(
181         kNameKey, filesystems[i].name);
182     file_system_dict_value->SetStringWithoutPathExpansion(
183         kGalleryIdKey,
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);
188     }
189     file_system_dict_value->SetBooleanWithoutPathExpansion(
190         kIsRemovableKey, filesystems[i].removable);
191     file_system_dict_value->SetBooleanWithoutPathExpansion(
192         kIsMediaDeviceKey, filesystems[i].media_device);
193
194     list->Append(file_system_dict_value.release());
195
196     if (filesystems[i].path.empty())
197       continue;
198
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);
205     }
206   }
207
208   SetResult(list);
209   SendResponse(true);
210 }
211
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
220     // host the dialog.
221     ShellWindow* window = apps::ShellWindowRegistry::Get(
222         GetProfile())->GetCurrentShellWindowForApp(GetExtension()->id());
223     if (window) {
224       contents = window->web_contents();
225     } else {
226       // Abort showing the dialog. TODO(estade) Perhaps return an error instead.
227       GetAndReturnGalleries();
228       return;
229     }
230   }
231
232   // Controller will delete itself.
233   base::Closure cb = base::Bind(
234       &MediaGalleriesGetMediaFileSystemsFunction::GetAndReturnGalleries, this);
235   new MediaGalleriesDialogController(contents, *GetExtension(), cb);
236 }
237
238 void MediaGalleriesGetMediaFileSystemsFunction::GetMediaFileSystemsForExtension(
239     const MediaFileSystemsCallback& cb) {
240   if (!render_view_host()) {
241     cb.Run(std::vector<MediaFileSystemInfo>());
242     return;
243   }
244   DCHECK(g_browser_process->media_file_system_registry()
245              ->GetPreferences(GetProfile())
246              ->IsInitialized());
247   MediaFileSystemRegistry* registry =
248       g_browser_process->media_file_system_registry();
249   registry->GetMediaFileSystemsForExtension(
250       render_view_host(), GetExtension(), cb);
251 }
252
253 }  // namespace extensions