094e5ffc174fec991befa5ded82050686f424e69
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / extensions / file_manager / private_api_misc.cc
1 // Copyright 2013 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 #include "chrome/browser/chromeos/extensions/file_manager/private_api_misc.h"
6
7 #include "apps/app_window.h"
8 #include "apps/app_window_registry.h"
9 #include "ash/frame/frame_util.h"
10 #include "base/files/file_path.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/chromeos/drive/file_system_util.h"
16 #include "chrome/browser/chromeos/extensions/file_manager/event_router.h"
17 #include "chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h"
18 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
19 #include "chrome/browser/chromeos/file_manager/app_installer.h"
20 #include "chrome/browser/chromeos/file_manager/zip_file_creator.h"
21 #include "chrome/browser/chromeos/profiles/profile_helper.h"
22 #include "chrome/browser/chromeos/settings/cros_settings.h"
23 #include "chrome/browser/devtools/devtools_window.h"
24 #include "chrome/browser/drive/event_logger.h"
25 #include "chrome/browser/extensions/devtools_util.h"
26 #include "chrome/browser/lifetime/application_lifetime.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/profiles/profile_manager.h"
29 #include "chrome/browser/profiles/profiles_state.h"
30 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
31 #include "chrome/browser/signin/signin_manager_factory.h"
32 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
33 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
34 #include "chrome/common/extensions/api/file_browser_private.h"
35 #include "chrome/common/pref_names.h"
36 #include "components/signin/core/browser/profile_oauth2_token_service.h"
37 #include "components/signin/core/browser/signin_manager.h"
38 #include "components/user_manager/user_manager.h"
39 #include "content/public/browser/render_view_host.h"
40 #include "content/public/browser/web_contents.h"
41 #include "content/public/common/page_zoom.h"
42 #include "google_apis/drive/auth_service.h"
43 #include "ui/base/webui/web_ui_util.h"
44 #include "url/gurl.h"
45
46 namespace extensions {
47
48 namespace {
49 const char kCWSScope[] = "https://www.googleapis.com/auth/chromewebstore";
50 const char kGoogleCastApiExtensionId[] = "mafeflapfdfljijmlienjedomfjfmhpd";
51
52 // Obtains the current app window.
53 apps::AppWindow* GetCurrentAppWindow(ChromeSyncExtensionFunction* function) {
54   apps::AppWindowRegistry* const app_window_registry =
55       apps::AppWindowRegistry::Get(function->GetProfile());
56   content::WebContents* const contents = function->GetAssociatedWebContents();
57   content::RenderViewHost* const render_view_host =
58       contents ? contents->GetRenderViewHost() : NULL;
59   return render_view_host ? app_window_registry->GetAppWindowForRenderViewHost(
60                                 render_view_host)
61                           : NULL;
62 }
63
64 std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >
65 GetLoggedInProfileInfoList(content::WebContents* contents) {
66   DCHECK(user_manager::UserManager::IsInitialized());
67   const std::vector<Profile*>& profiles =
68       g_browser_process->profile_manager()->GetLoadedProfiles();
69   std::set<Profile*> original_profiles;
70   std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >
71       result_profiles;
72
73   for (size_t i = 0; i < profiles.size(); ++i) {
74     // Filter the profile.
75     Profile* const profile = profiles[i]->GetOriginalProfile();
76     if (original_profiles.count(profile))
77       continue;
78     original_profiles.insert(profile);
79     const user_manager::User* const user =
80         chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
81     if (!user || !user->is_logged_in())
82       continue;
83
84     // Make a ProfileInfo.
85     linked_ptr<api::file_browser_private::ProfileInfo> profile_info(
86         new api::file_browser_private::ProfileInfo());
87     profile_info->profile_id = multi_user_util::GetUserIDFromProfile(profile);
88     profile_info->display_name = UTF16ToUTF8(user->GetDisplayName());
89     // TODO(hirono): Remove the property from the profile_info.
90     profile_info->is_current_profile = true;
91
92     // Make an icon URL of the profile.
93     if (contents) {
94       const gfx::Image& image =
95           ash::GetAvatarImageForContext(contents->GetBrowserContext());
96       const gfx::ImageSkia& skia = image.AsImageSkia();
97       profile_info->profile_image.reset(
98           new api::file_browser_private::ImageSet);
99       profile_info->profile_image->scale1x_url =
100           webui::GetBitmapDataUrl(skia.GetRepresentation(1.0f).sk_bitmap());
101       profile_info->profile_image->scale2x_url =
102           webui::GetBitmapDataUrl(skia.GetRepresentation(2.0f).sk_bitmap());
103     }
104     result_profiles.push_back(profile_info);
105   }
106
107   return result_profiles;
108 }
109 } // namespace
110
111 bool FileBrowserPrivateLogoutUserForReauthenticationFunction::RunSync() {
112   user_manager::User* user =
113       chromeos::ProfileHelper::Get()->GetUserByProfile(GetProfile());
114   if (user) {
115     user_manager::UserManager::Get()->SaveUserOAuthStatus(
116         user->email(), user_manager::User::OAUTH2_TOKEN_STATUS_INVALID);
117   }
118
119   chrome::AttemptUserExit();
120   return true;
121 }
122
123 bool FileBrowserPrivateGetPreferencesFunction::RunSync() {
124   api::file_browser_private::Preferences result;
125   const PrefService* const service = GetProfile()->GetPrefs();
126
127   result.drive_enabled = drive::util::IsDriveEnabledForProfile(GetProfile());
128   result.cellular_disabled =
129       service->GetBoolean(prefs::kDisableDriveOverCellular);
130   result.hosted_files_disabled =
131       service->GetBoolean(prefs::kDisableDriveHostedFiles);
132   result.use24hour_clock = service->GetBoolean(prefs::kUse24HourClock);
133   result.allow_redeem_offers = true;
134   if (!chromeos::CrosSettings::Get()->GetBoolean(
135           chromeos::kAllowRedeemChromeOsRegistrationOffers,
136           &result.allow_redeem_offers)) {
137     result.allow_redeem_offers = true;
138   }
139
140   SetResult(result.ToValue().release());
141
142   drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
143   if (logger)
144     logger->Log(logging::LOG_INFO, "%s succeeded.", name().c_str());
145   return true;
146 }
147
148 bool FileBrowserPrivateSetPreferencesFunction::RunSync() {
149   using extensions::api::file_browser_private::SetPreferences::Params;
150   const scoped_ptr<Params> params(Params::Create(*args_));
151   EXTENSION_FUNCTION_VALIDATE(params);
152
153   PrefService* const service = GetProfile()->GetPrefs();
154
155   if (params->change_info.cellular_disabled)
156     service->SetBoolean(prefs::kDisableDriveOverCellular,
157                         *params->change_info.cellular_disabled);
158
159   if (params->change_info.hosted_files_disabled)
160     service->SetBoolean(prefs::kDisableDriveHostedFiles,
161                         *params->change_info.hosted_files_disabled);
162
163   drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
164   if (logger)
165     logger->Log(logging::LOG_INFO, "%s succeeded.", name().c_str());
166   return true;
167 }
168
169 FileBrowserPrivateZipSelectionFunction::
170     FileBrowserPrivateZipSelectionFunction() {}
171
172 FileBrowserPrivateZipSelectionFunction::
173     ~FileBrowserPrivateZipSelectionFunction() {}
174
175 bool FileBrowserPrivateZipSelectionFunction::RunAsync() {
176   using extensions::api::file_browser_private::ZipSelection::Params;
177   const scoped_ptr<Params> params(Params::Create(*args_));
178   EXTENSION_FUNCTION_VALIDATE(params);
179
180   // First param is the source directory URL.
181   if (params->dir_url.empty())
182     return false;
183
184   base::FilePath src_dir = file_manager::util::GetLocalPathFromURL(
185       render_view_host(), GetProfile(), GURL(params->dir_url));
186   if (src_dir.empty())
187     return false;
188
189   // Second param is the list of selected file URLs.
190   if (params->selection_urls.empty())
191     return false;
192
193   std::vector<base::FilePath> files;
194   for (size_t i = 0; i < params->selection_urls.size(); ++i) {
195     base::FilePath path = file_manager::util::GetLocalPathFromURL(
196         render_view_host(), GetProfile(), GURL(params->selection_urls[i]));
197     if (path.empty())
198       return false;
199     files.push_back(path);
200   }
201
202   // Third param is the name of the output zip file.
203   if (params->dest_name.empty())
204     return false;
205
206   // Check if the dir path is under Drive mount point.
207   // TODO(hshi): support create zip file on Drive (crbug.com/158690).
208   if (drive::util::IsUnderDriveMountPoint(src_dir))
209     return false;
210
211   base::FilePath dest_file = src_dir.Append(params->dest_name);
212   std::vector<base::FilePath> src_relative_paths;
213   for (size_t i = 0; i != files.size(); ++i) {
214     const base::FilePath& file_path = files[i];
215
216     // Obtain the relative path of |file_path| under |src_dir|.
217     base::FilePath relative_path;
218     if (!src_dir.AppendRelativePath(file_path, &relative_path))
219       return false;
220     src_relative_paths.push_back(relative_path);
221   }
222
223   (new file_manager::ZipFileCreator(
224        base::Bind(&FileBrowserPrivateZipSelectionFunction::OnZipDone, this),
225        src_dir,
226        src_relative_paths,
227        dest_file))->Start();
228   return true;
229 }
230
231 void FileBrowserPrivateZipSelectionFunction::OnZipDone(bool success) {
232   SetResult(new base::FundamentalValue(success));
233   SendResponse(true);
234 }
235
236 bool FileBrowserPrivateZoomFunction::RunSync() {
237   using extensions::api::file_browser_private::Zoom::Params;
238   const scoped_ptr<Params> params(Params::Create(*args_));
239   EXTENSION_FUNCTION_VALIDATE(params);
240
241   content::PageZoom zoom_type;
242   switch (params->operation) {
243     case api::file_browser_private::ZOOM_OPERATION_TYPE_IN:
244       zoom_type = content::PAGE_ZOOM_IN;
245       break;
246     case api::file_browser_private::ZOOM_OPERATION_TYPE_OUT:
247       zoom_type = content::PAGE_ZOOM_OUT;
248       break;
249     case api::file_browser_private::ZOOM_OPERATION_TYPE_RESET:
250       zoom_type = content::PAGE_ZOOM_RESET;
251       break;
252     default:
253       NOTREACHED();
254       return false;
255   }
256   render_view_host()->Zoom(zoom_type);
257   return true;
258 }
259
260 bool FileBrowserPrivateInstallWebstoreItemFunction::RunAsync() {
261   using extensions::api::file_browser_private::InstallWebstoreItem::Params;
262   const scoped_ptr<Params> params(Params::Create(*args_));
263   EXTENSION_FUNCTION_VALIDATE(params);
264
265   if (params->item_id.empty())
266     return false;
267
268   const extensions::WebstoreStandaloneInstaller::Callback callback =
269       base::Bind(
270           &FileBrowserPrivateInstallWebstoreItemFunction::OnInstallComplete,
271           this);
272
273   // Only GoogleCastAPI extension can use silent installation.
274   if (params->silent_installation &&
275       params->item_id != kGoogleCastApiExtensionId) {
276     SetError("Only whitelisted items can do silent installation.");
277     return false;
278   }
279
280   scoped_refptr<file_manager::AppInstaller> installer(
281       new file_manager::AppInstaller(GetAssociatedWebContents(),
282                                      params->item_id,
283                                      GetProfile(),
284                                      params->silent_installation,
285                                      callback));
286   // installer will be AddRef()'d in BeginInstall().
287   installer->BeginInstall();
288   return true;
289 }
290
291 void FileBrowserPrivateInstallWebstoreItemFunction::OnInstallComplete(
292     bool success,
293     const std::string& error,
294     extensions::webstore_install::Result result) {
295   drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
296   if (success) {
297     if (logger) {
298       logger->Log(logging::LOG_INFO,
299                   "App install succeeded. (item id: %s)",
300                   webstore_item_id_.c_str());
301     }
302   } else {
303     if (logger) {
304       logger->Log(logging::LOG_ERROR,
305                   "App install failed. (item id: %s, reason: %s)",
306                   webstore_item_id_.c_str(),
307                   error.c_str());
308     }
309     SetError(error);
310   }
311
312   SendResponse(success);
313 }
314
315 FileBrowserPrivateRequestWebStoreAccessTokenFunction::
316     FileBrowserPrivateRequestWebStoreAccessTokenFunction() {
317 }
318
319 FileBrowserPrivateRequestWebStoreAccessTokenFunction::
320     ~FileBrowserPrivateRequestWebStoreAccessTokenFunction() {
321 }
322
323 bool FileBrowserPrivateRequestWebStoreAccessTokenFunction::RunAsync() {
324   std::vector<std::string> scopes;
325   scopes.push_back(kCWSScope);
326
327   ProfileOAuth2TokenService* oauth_service =
328       ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
329   net::URLRequestContextGetter* url_request_context_getter =
330       g_browser_process->system_request_context();
331
332   if (!oauth_service) {
333     drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
334     if (logger) {
335       logger->Log(logging::LOG_ERROR,
336                   "CWS OAuth token fetch failed. OAuth2TokenService can't "
337                   "be retrieved.");
338     }
339     SetResult(base::Value::CreateNullValue());
340     return false;
341   }
342
343   SigninManagerBase* signin_manager =
344       SigninManagerFactory::GetForProfile(GetProfile());
345   auth_service_.reset(new google_apis::AuthService(
346       oauth_service,
347       signin_manager->GetAuthenticatedAccountId(),
348       url_request_context_getter,
349       scopes));
350   auth_service_->StartAuthentication(base::Bind(
351       &FileBrowserPrivateRequestWebStoreAccessTokenFunction::
352           OnAccessTokenFetched,
353       this));
354
355   return true;
356 }
357
358 void FileBrowserPrivateRequestWebStoreAccessTokenFunction::OnAccessTokenFetched(
359     google_apis::GDataErrorCode code,
360     const std::string& access_token) {
361   drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
362
363   if (code == google_apis::HTTP_SUCCESS) {
364     DCHECK(auth_service_->HasAccessToken());
365     DCHECK(access_token == auth_service_->access_token());
366     if (logger)
367       logger->Log(logging::LOG_INFO, "CWS OAuth token fetch succeeded.");
368     SetResult(new base::StringValue(access_token));
369     SendResponse(true);
370   } else {
371     if (logger) {
372       logger->Log(logging::LOG_ERROR,
373                   "CWS OAuth token fetch failed. (GDataErrorCode: %s)",
374                   google_apis::GDataErrorCodeToString(code).c_str());
375     }
376     SetResult(base::Value::CreateNullValue());
377     SendResponse(false);
378   }
379 }
380
381 bool FileBrowserPrivateGetProfilesFunction::RunSync() {
382   const std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >&
383       profiles = GetLoggedInProfileInfoList(GetAssociatedWebContents());
384
385   // Obtains the display profile ID.
386   apps::AppWindow* const app_window = GetCurrentAppWindow(this);
387   chrome::MultiUserWindowManager* const window_manager =
388       chrome::MultiUserWindowManager::GetInstance();
389   const std::string current_profile_id =
390       multi_user_util::GetUserIDFromProfile(GetProfile());
391   const std::string display_profile_id =
392       window_manager && app_window ? window_manager->GetUserPresentingWindow(
393                                          app_window->GetNativeWindow())
394                                    : "";
395
396   results_ = api::file_browser_private::GetProfiles::Results::Create(
397       profiles,
398       current_profile_id,
399       display_profile_id.empty() ? current_profile_id : display_profile_id);
400   return true;
401 }
402
403 bool FileBrowserPrivateVisitDesktopFunction::RunSync() {
404   using api::file_browser_private::VisitDesktop::Params;
405   const scoped_ptr<Params> params(Params::Create(*args_));
406   const std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >&
407       profiles = GetLoggedInProfileInfoList(GetAssociatedWebContents());
408
409   chrome::MultiUserWindowManager* const window_manager =
410       chrome::MultiUserWindowManager::GetInstance();
411   DCHECK(window_manager);
412
413   // Check if the target user is logged-in or not.
414   bool logged_in = false;
415   for (size_t i = 0; i < profiles.size(); ++i) {
416     if (profiles[i]->profile_id == params->profile_id) {
417       logged_in = true;
418       break;
419     }
420   }
421   if (!logged_in) {
422     SetError("The user is not logged-in now.");
423     return false;
424   }
425
426   // Look for the current app window.
427   apps::AppWindow* const app_window = GetCurrentAppWindow(this);
428   if (!app_window) {
429     SetError("Target window is not found.");
430     return false;
431   }
432
433   // Observe owner changes of windows.
434   file_manager::EventRouter* const event_router =
435       file_manager::FileBrowserPrivateAPI::Get(GetProfile())->event_router();
436   event_router->RegisterMultiUserWindowManagerObserver();
437
438   // Move the window to the user's desktop.
439   window_manager->ShowWindowForUser(app_window->GetNativeWindow(),
440                                     params->profile_id);
441
442   // Check the result.
443   if (!window_manager->IsWindowOnDesktopOfUser(app_window->GetNativeWindow(),
444                                                params->profile_id)) {
445     SetError("The window cannot visit the desktop.");
446     return false;
447   }
448
449   return true;
450 }
451
452 bool FileBrowserPrivateOpenInspectorFunction::RunSync() {
453   using extensions::api::file_browser_private::OpenInspector::Params;
454   const scoped_ptr<Params> params(Params::Create(*args_));
455   EXTENSION_FUNCTION_VALIDATE(params);
456
457   switch (params->type) {
458     case extensions::api::file_browser_private::INSPECTION_TYPE_NORMAL:
459       // Open inspector for foreground page.
460       DevToolsWindow::OpenDevToolsWindow(
461           content::WebContents::FromRenderViewHost(render_view_host()));
462       break;
463     case extensions::api::file_browser_private::INSPECTION_TYPE_CONSOLE:
464       // Open inspector for foreground page and bring focus to the console.
465       DevToolsWindow::OpenDevToolsWindow(
466           content::WebContents::FromRenderViewHost(render_view_host()),
467           DevToolsToggleAction::ShowConsole());
468       break;
469     case extensions::api::file_browser_private::INSPECTION_TYPE_ELEMENT:
470       // Open inspector for foreground page in inspect element mode.
471       DevToolsWindow::OpenDevToolsWindow(
472           content::WebContents::FromRenderViewHost(render_view_host()),
473           DevToolsToggleAction::Inspect());
474       break;
475     case extensions::api::file_browser_private::INSPECTION_TYPE_BACKGROUND:
476       // Open inspector for background page.
477       extensions::devtools_util::InspectBackgroundPage(extension(),
478                                                        GetProfile());
479       break;
480     default:
481       NOTREACHED();
482       SetError(
483           base::StringPrintf("Unexpected inspection type(%d) is specified.",
484                              static_cast<int>(params->type)));
485       return false;
486   }
487   return true;
488 }
489
490 }  // namespace extensions