Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: chrome/browser/chromeos/extensions/file_browser_private_api.cc

Issue 10834383: Chrome OS "open with" picker allowing Web Intents (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Fixed mime matching code, asserts that the mime-pattern "*" matches a blank mime-type (i.e. "*" mat… Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/extensions/file_browser_private_api.h" 5 #include "chrome/browser/chromeos/extensions/file_browser_private_api.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/base64.h" 9 #include "base/base64.h"
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/file_path.h"
12 #include "base/file_util.h"
13 #include "base/i18n/case_conversion.h"
11 #include "base/logging.h" 14 #include "base/logging.h"
12 #include "base/memory/scoped_vector.h" 15 #include "base/memory/scoped_vector.h"
13 #include "base/memory/singleton.h" 16 #include "base/memory/singleton.h"
14 #include "base/string_split.h" 17 #include "base/string_split.h"
15 #include "base/stringprintf.h" 18 #include "base/stringprintf.h"
16 #include "base/time.h" 19 #include "base/time.h"
17 #include "base/values.h" 20 #include "base/values.h"
21 #include "base/utf_string_conversions.h"
18 #include "chrome/browser/chromeos/cros/cros_library.h" 22 #include "chrome/browser/chromeos/cros/cros_library.h"
19 #include "chrome/browser/chromeos/cros/network_library.h" 23 #include "chrome/browser/chromeos/cros/network_library.h"
20 #include "chrome/browser/chromeos/disks/disk_mount_manager.h" 24 #include "chrome/browser/chromeos/disks/disk_mount_manager.h"
21 #include "chrome/browser/chromeos/extensions/file_handler_util.h" 25 #include "chrome/browser/chromeos/extensions/file_handler_util.h"
22 #include "chrome/browser/chromeos/extensions/file_manager_util.h" 26 #include "chrome/browser/chromeos/extensions/file_manager_util.h"
23 #include "chrome/browser/chromeos/gdata/drive_webapps_registry.h" 27 #include "chrome/browser/chromeos/gdata/drive_webapps_registry.h"
24 #include "chrome/browser/chromeos/gdata/gdata.pb.h" 28 #include "chrome/browser/chromeos/gdata/gdata.pb.h"
25 #include "chrome/browser/chromeos/gdata/gdata_documents_service.h" 29 #include "chrome/browser/chromeos/gdata/gdata_documents_service.h"
26 #include "chrome/browser/chromeos/gdata/gdata_operation_registry.h" 30 #include "chrome/browser/chromeos/gdata/gdata_operation_registry.h"
27 #include "chrome/browser/chromeos/gdata/gdata_system_service.h" 31 #include "chrome/browser/chromeos/gdata/gdata_system_service.h"
(...skipping 15 matching lines...) Expand all
43 #include "chrome/common/extensions/extension_icon_set.h" 47 #include "chrome/common/extensions/extension_icon_set.h"
44 #include "chrome/common/extensions/file_browser_handler.h" 48 #include "chrome/common/extensions/file_browser_handler.h"
45 #include "chrome/common/pref_names.h" 49 #include "chrome/common/pref_names.h"
46 #include "content/public/browser/child_process_security_policy.h" 50 #include "content/public/browser/child_process_security_policy.h"
47 #include "content/public/browser/render_process_host.h" 51 #include "content/public/browser/render_process_host.h"
48 #include "content/public/browser/render_view_host.h" 52 #include "content/public/browser/render_view_host.h"
49 #include "googleurl/src/gurl.h" 53 #include "googleurl/src/gurl.h"
50 #include "grit/generated_resources.h" 54 #include "grit/generated_resources.h"
51 #include "grit/platform_locale_settings.h" 55 #include "grit/platform_locale_settings.h"
52 #include "net/base/escape.h" 56 #include "net/base/escape.h"
57 #include "net/base/mime_util.h"
53 #include "ui/base/dialogs/selected_file_info.h" 58 #include "ui/base/dialogs/selected_file_info.h"
54 #include "ui/base/l10n/l10n_util.h" 59 #include "ui/base/l10n/l10n_util.h"
55 #include "webkit/fileapi/file_system_context.h" 60 #include "webkit/fileapi/file_system_context.h"
56 #include "webkit/fileapi/file_system_file_util.h" 61 #include "webkit/fileapi/file_system_file_util.h"
57 #include "webkit/fileapi/file_system_mount_point_provider.h" 62 #include "webkit/fileapi/file_system_mount_point_provider.h"
58 #include "webkit/fileapi/file_system_operation_context.h" 63 #include "webkit/fileapi/file_system_operation_context.h"
59 #include "webkit/fileapi/file_system_types.h" 64 #include "webkit/fileapi/file_system_types.h"
60 #include "webkit/fileapi/file_system_util.h" 65 #include "webkit/fileapi/file_system_util.h"
66 #include "webkit/glue/web_intent_service_data.h"
61 67
62 using chromeos::disks::DiskMountManager; 68 using chromeos::disks::DiskMountManager;
63 using content::BrowserContext; 69 using content::BrowserContext;
64 using content::BrowserThread; 70 using content::BrowserThread;
65 using content::ChildProcessSecurityPolicy; 71 using content::ChildProcessSecurityPolicy;
66 using content::SiteInstance; 72 using content::SiteInstance;
67 using content::WebContents; 73 using content::WebContents;
68 using extensions::Extension; 74 using extensions::Extension;
69 using file_handler_util::FileTaskExecutor; 75 using file_handler_util::FileTaskExecutor;
70 using gdata::GDataOperationRegistry; 76 using gdata::GDataOperationRegistry;
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 GURL best_icon = FindPreferredIcon(info->app_icons, 344 GURL best_icon = FindPreferredIcon(info->app_icons,
339 kPreferredIconSize); 345 kPreferredIconSize);
340 if (!best_icon.is_empty()) { 346 if (!best_icon.is_empty()) {
341 task->SetString("iconUrl", best_icon.spec()); 347 task->SetString("iconUrl", best_icon.spec());
342 } 348 }
343 task->SetBoolean("driveApp", true); 349 task->SetBoolean("driveApp", true);
344 result_list->Append(task); 350 result_list->Append(task);
345 } 351 }
346 } 352 }
347 353
354 typedef std::vector<webkit_glue::WebIntentServiceData> ServiceList;
355
356 // Returns the set Web Intent actions for which the given |mime_type| is
357 // allowed.
358 std::set<std::string> ActionsForType(const std::string& mime_type,
359 const ServiceList& services) {
360 std::set<std::string> actions;
361 for (ServiceList::const_iterator i = services.begin();
362 i != services.end(); ++i) {
363 if (net::MatchesMimeType(UTF16ToUTF8(i->type), mime_type))
364 actions.insert(UTF16ToUTF8(i->action));
365 }
366 return actions;
367 }
368
369 // Given an extension and a set of |mime_types|, return the set of Web Intent
370 // actions that are supported on every type within the set. This set may be
371 // empty, in which case no actions are supported.
372 std::set<std::string> ActionsForExtension(const Extension* extension,
373 const std::set<std::string>& mime_types) {
374 std::set<std::string> actions;
375
376 // TODO(thorogood): Test this!
377
378 for (std::set<std::string>::const_iterator i = mime_types.begin();
379 i != mime_types.end(); ++i) {
380 std::set<std::string> inner =
381 ActionsForType(*i, extension->intents_services());
382
383 if (i == mime_types.begin()) {
384 actions = inner;
385 } else {
386 std::set<std::string> tmp;
387 std::set_intersection(actions.begin(),
388 actions.end(),
389 inner.begin(),
390 inner.end(),
391 std::inserter(tmp, tmp.begin()));
392 actions = tmp;
393 }
394
395 if (actions.empty())
396 break; // fall-out early, this set will never grow
397 }
398
399 return actions;
400 }
401
402 // Retrieves the title for the given Extension and action pair, returning true
403 // if it could be found.
404 bool TitleForExtensionAction(const Extension* extension,
405 const std::string& action, std::string* title) {
406 for (ServiceList::const_iterator i = extension->intents_services().begin();
407 i != extension->intents_services().end(); ++i) {
408 if (action == UTF16ToUTF8(i->action)) {
409 *title = UTF16ToUTF8(i->title);
410 return true;
411 }
412 }
413 return false;
414 }
415
348 } // namespace 416 } // namespace
349 417
350 class RequestLocalFileSystemFunction::LocalFileSystemCallbackDispatcher { 418 class RequestLocalFileSystemFunction::LocalFileSystemCallbackDispatcher {
351 public: 419 public:
352 static fileapi::FileSystemContext::OpenFileSystemCallback CreateCallback( 420 static fileapi::FileSystemContext::OpenFileSystemCallback CreateCallback(
353 RequestLocalFileSystemFunction* function, 421 RequestLocalFileSystemFunction* function,
354 scoped_refptr<fileapi::FileSystemContext> file_system_context, 422 scoped_refptr<fileapi::FileSystemContext> file_system_context,
355 int child_id, 423 int child_id,
356 scoped_refptr<const Extension> extension) { 424 scoped_refptr<const Extension> extension) {
357 return base::Bind( 425 return base::Bind(
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after
628 } 696 }
629 697
630 gdata::GDataSystemService* system_service = 698 gdata::GDataSystemService* system_service =
631 gdata::GDataSystemServiceFactory::GetForProfile(profile_); 699 gdata::GDataSystemServiceFactory::GetForProfile(profile_);
632 // |system_service| is NULL if incognito window / guest login. We return true 700 // |system_service| is NULL if incognito window / guest login. We return true
633 // in this case because there might be other extension tasks, even if we don't 701 // in this case because there might be other extension tasks, even if we don't
634 // have any to add. 702 // have any to add.
635 if (!system_service || !system_service->webapps_registry()) 703 if (!system_service || !system_service->webapps_registry())
636 return true; 704 return true;
637 705
638
639 gdata::DriveWebAppsRegistry* registry = system_service->webapps_registry(); 706 gdata::DriveWebAppsRegistry* registry = system_service->webapps_registry();
640 707
641 // Map of app_id to DriveWebAppInfo so we can look up the apps we've found 708 // Map of app_id to DriveWebAppInfo so we can look up the apps we've found
642 // after taking the intersection of available apps. 709 // after taking the intersection of available apps.
643 std::map<std::string, gdata::DriveWebAppInfo*> app_info; 710 std::map<std::string, gdata::DriveWebAppInfo*> app_info;
644 // Set of application IDs. This will end up with the intersection of the 711 // Set of application IDs. This will end up with the intersection of the
645 // application IDs that apply to the paths in |file_paths|. 712 // application IDs that apply to the paths in |file_paths|.
646 std::set<std::string> available_apps; 713 std::set<std::string> available_apps;
647 714
648 IntersectAvailableDriveTasks(registry, file_paths, 715 IntersectAvailableDriveTasks(registry, file_paths,
649 &app_info, &available_apps); 716 &app_info, &available_apps);
650 CreateDriveTasks(registry, app_info, available_apps, result_list); 717 CreateDriveTasks(registry, app_info, available_apps, result_list);
651 718
652 // We own the pointers in |app_info|, so we need to delete them. 719 // We own the pointers in |app_info|, so we need to delete them.
653 STLDeleteContainerPairSecondPointers(app_info.begin(), app_info.end()); 720 STLDeleteContainerPairSecondPointers(app_info.begin(), app_info.end());
654 return true; 721 return true;
655 } 722 }
656 723
724 // Find special tasks here for Web Intent platform apps. Iterate through
725 // matching apps and add them. These tasks will be identified by the "http"
726 // prefix found on the task action.
727 bool GetFileTasksFileBrowserFunction::FindWebIntentTasks(
728 const std::vector<GURL>& file_urls,
729 ListValue* result_list) {
730 DCHECK(!file_urls.empty());
731 ExtensionService* service = profile_->GetExtensionService();
732 if (!service)
733 return false;
734
735 std::set<std::string> mime_types;
736 for (std::vector<GURL>::const_iterator iter = file_urls.begin();
737 iter != file_urls.end(); ++iter) {
738 const FilePath file = FilePath(GURL(iter->spec()).ExtractFileName());
739 const FilePath::StringType file_extension =
740 StringToLowerASCII(file.Extension());
741
742 // TODO(thorogood): Rearchitect this call so it can run on the File thread;
743 // GetMimeTypeFromFile requires this on Linux. Right now, we use
744 // Chrome-level knowledge only.
745 std::string mime_type;
746 if (!file_extension.empty() && !net::GetWellKnownMimeTypeFromExtension(
747 file_extension.substr(1), &mime_type))
748 mime_type = std::string(); // There was no mime-type available from
749 // this file, but we'll still match "*".
750 mime_types.insert(mime_type);
751 }
752
753 for (ExtensionSet::const_iterator iter = service->extensions()->begin();
754 iter != service->extensions()->end();
755 ++iter) {
756 const Extension* extension = *iter;
757
758 // We can't use hosted apps to open files.
759 if (!extension->is_platform_app() || !extension->has_background_page())
760 continue;
761
762 if (profile_->IsOffTheRecord() &&
763 !service->IsIncognitoEnabled(extension->id()))
764 continue;
765
766 const std::set<std::string> actions =
767 ActionsForExtension(extension, mime_types);
768 for (std::set<std::string>::iterator ai = actions.begin();
769 ai != actions.end(); ++ai) {
770 std::string title;
771 DCHECK(TitleForExtensionAction(extension, *ai, &title));
772
773 DictionaryValue* task = new DictionaryValue;
774 std::string task_id =
775 file_handler_util::MakeTaskID(extension->id(), *ai);
776 task->SetString("taskId", task_id);
777 task->SetString("title", title);
778
779 // TODO(thorogood): Expand mime-types. Is this even important? We're
780 // already only serving this task if it satisfies the pattern list.
781 ListValue* pattern_list = new ListValue;
782 pattern_list->Append(new StringValue("filesystem:*"));
783 task->Set("patterns", pattern_list);
784
785 GURL best_icon = extension->GetIconURL(kPreferredIconSize,
786 ExtensionIconSet::MATCH_BIGGER);
787 task->SetString("iconUrl", best_icon.spec());
788
789 task->SetBoolean("driveApp", false);
790 result_list->Append(task);
791 }
792 }
793
794 return true;
795 }
657 796
658 bool GetFileTasksFileBrowserFunction::RunImpl() { 797 bool GetFileTasksFileBrowserFunction::RunImpl() {
659 ListValue* files_list = NULL; 798 ListValue* files_list = NULL;
660 if (!args_->GetList(0, &files_list)) 799 if (!args_->GetList(0, &files_list))
661 return false; 800 return false;
662 801
663 std::vector<GURL> file_urls; 802 std::vector<GURL> file_urls;
664 for (size_t i = 0; i < files_list->GetSize(); ++i) { 803 for (size_t i = 0; i < files_list->GetSize(); ++i) {
665 std::string file_url; 804 std::string file_url;
666 if (!files_list->GetString(i, &file_url)) 805 if (!files_list->GetString(i, &file_url))
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
703 842
704 // Take the union of Drive and extension tasks: Because any extension tasks we 843 // Take the union of Drive and extension tasks: Because any extension tasks we
705 // found must apply to all of the files (intersection), and because the same 844 // found must apply to all of the files (intersection), and because the same
706 // is true of the drive apps, we simply take the union of two lists by adding 845 // is true of the drive apps, we simply take the union of two lists by adding
707 // the drive tasks to the extension task list. We know there aren't duplicates 846 // the drive tasks to the extension task list. We know there aren't duplicates
708 // because they're entirely different kinds of tasks, but there could be both 847 // because they're entirely different kinds of tasks, but there could be both
709 // kinds of tasks for a file type (an image file, for instance). 848 // kinds of tasks for a file type (an image file, for instance).
710 if (!FindDriveAppTasks(file_urls, result_list)) 849 if (!FindDriveAppTasks(file_urls, result_list))
711 return false; 850 return false;
712 851
713 // TODO(zelidrag, serya): Add intent content tasks to result_list once we 852 // Take the union of Web Intents (that platform apps may accept) and all
714 // implement that API. 853 // previous Drive and extension tasks. As above, we know there aren't
854 // duplicates because they're entirely different kinds of tasks.
855 if (!FindWebIntentTasks(file_urls, result_list))
856 return false;
857
715 SendResponse(true); 858 SendResponse(true);
716 return true; 859 return true;
717 } 860 }
718 861
719 ExecuteTasksFileBrowserFunction::ExecuteTasksFileBrowserFunction() {} 862 ExecuteTasksFileBrowserFunction::ExecuteTasksFileBrowserFunction() {}
720 863
721 void ExecuteTasksFileBrowserFunction::OnTaskExecuted(bool success) { 864 void ExecuteTasksFileBrowserFunction::OnTaskExecuted(bool success) {
722 SendResponse(success); 865 SendResponse(success);
723 } 866 }
724 867
(...skipping 1706 matching lines...) Expand 10 before | Expand all | Expand 10 after
2431 gdata::GDataSystemService* system_service = 2574 gdata::GDataSystemService* system_service =
2432 gdata::GDataSystemServiceFactory::GetForProfile(profile_); 2575 gdata::GDataSystemServiceFactory::GetForProfile(profile_);
2433 if (!system_service || !system_service->file_system()) 2576 if (!system_service || !system_service->file_system())
2434 return false; 2577 return false;
2435 2578
2436 FilePath directory_path = GetVirtualPathFromURL(GURL(file_url_as_string)); 2579 FilePath directory_path = GetVirtualPathFromURL(GURL(file_url_as_string));
2437 system_service->file_system()->RequestDirectoryRefresh(directory_path); 2580 system_service->file_system()->RequestDirectoryRefresh(directory_path);
2438 2581
2439 return true; 2582 return true;
2440 } 2583 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698