Chromium Code Reviews| Index: chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc |
| diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc |
| index 24e708bf2272ac976103ebb670b056c449df410c..72c172d26d4a75d78ee336b464d613b36fa837d2 100644 |
| --- a/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc |
| +++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc |
| @@ -20,6 +20,7 @@ |
| #include "chrome/browser/chromeos/extensions/file_manager/file_browser_handler.h" |
| #include "chrome/browser/chromeos/extensions/file_manager/file_handler_util.h" |
| #include "chrome/browser/chromeos/media/media_player.h" |
| +#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h" |
| #include "chrome/browser/extensions/crx_installer.h" |
| #include "chrome/browser/extensions/extension_install_prompt.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| @@ -49,6 +50,7 @@ |
| #include "content/public/common/pepper_plugin_info.h" |
| #include "grit/generated_resources.h" |
| #include "net/base/escape.h" |
| +#include "net/base/mime_util.h" |
| #include "net/base/net_util.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/gfx/screen.h" |
| @@ -65,6 +67,8 @@ using content::BrowserContext; |
| using content::BrowserThread; |
| using content::PluginService; |
| using content::UserMetricsAction; |
| +using extensions::app_file_handler_util::FindFileHandlersForFiles; |
| +using extensions::app_file_handler_util::PathAndMimeTypeSet; |
| using extensions::Extension; |
| using file_handler_util::FileTaskExecutor; |
| using fileapi::FileSystemURL; |
| @@ -314,7 +318,8 @@ bool GrantFileSystemAccessToFileBrowser(Profile* profile) { |
| void ExecuteHandler(Profile* profile, |
| std::string extension_id, |
| std::string action_id, |
| - const GURL& url) { |
| + const GURL& url, |
| + const std::string& task_type) { |
| // If File Browser has not been open yet then it did not request access |
| // to the file system. Do it now. |
| if (!GrantFileSystemAccessToFileBrowser(profile)) |
| @@ -332,7 +337,7 @@ void ExecuteHandler(Profile* profile, |
| urls.push_back(file_system_context->CrackURL(url)); |
| scoped_refptr<FileTaskExecutor> executor = FileTaskExecutor::Create(profile, |
| source_url, kFileBrowserDomain, 0 /* no tab id */, extension_id, |
| - file_handler_util::kTaskFile, action_id); |
| + task_type, action_id); |
| executor->Execute(urls); |
| } |
| @@ -351,7 +356,8 @@ void OpenFileBrowserImpl(const base::FilePath& path, |
| // Some values of |action_id| are not listed in the manifest and are used |
| // to parametrize the behavior when opening the Files app window. |
| - ExecuteHandler(profile, kFileBrowserDomain, action_id, url); |
| + ExecuteHandler(profile, kFileBrowserDomain, action_id, url, |
| + file_handler_util::kTaskFile); |
| return; |
| } |
| @@ -409,17 +415,70 @@ Browser* GetBrowserForUrl(GURL target_url) { |
| return NULL; |
| } |
| -bool ExecuteDefaultHandler(Profile* profile, const base::FilePath& path) { |
| - GURL url; |
| - if (!ConvertFileToFileSystemUrl(profile, path, kFileBrowserDomain, &url)) |
| +bool ExecuteDefaultAppHandler(Profile* profile, |
| + const base::FilePath& path, |
| + const GURL& url, |
| + const std::string& mime_type, |
| + const std::string& default_task_id) { |
| + ExtensionService* service = profile->GetExtensionService(); |
| + if (!service) |
| return false; |
| - const FileBrowserHandler* handler; |
| - if (!file_handler_util::GetTaskForURLAndPath(profile, url, path, &handler)) |
| - return false; |
| + PathAndMimeTypeSet files; |
| + files.insert(std::make_pair(path, mime_type)); |
| + const extensions::FileHandlerInfo* first_handler = NULL; |
| + const extensions::Extension* extension_for_first_handler = NULL; |
| + |
| + // If we find the default handler, we execute it immediately, but otherwise, |
| + // we remember the first handler, and if there was no default handler, simply |
| + // execute the first one. |
| + for (ExtensionSet::const_iterator iter = service->extensions()->begin(); |
| + iter != service->extensions()->end(); |
| + ++iter) { |
| + const Extension* extension = *iter; |
| + |
| + // We don't support using hosted apps to open files. |
|
mtomasz
2013/06/07 02:36:00
This comment is misleading. is_platform_app disall
Sam McNally
2013/06/07 05:29:13
This is copied from the check in file_manager_priv
|
| + if (!extension->is_platform_app()) |
| + continue; |
| + |
| + // We only support apps that specify "incognito: split" if in incognito |
|
mtomasz
2013/06/07 02:36:00
I'm wondering if this behavior is documented somew
Sam McNally
2013/06/07 05:29:13
Same as above. This check may be unnecessary thoug
|
| + // mode. |
| + if (profile->IsOffTheRecord() && |
| + !service->IsIncognitoEnabled(extension->id())) |
| + continue; |
| + |
| + typedef std::vector<const extensions::FileHandlerInfo*> FileHandlerList; |
| + FileHandlerList file_handlers = FindFileHandlersForFiles(*extension, files); |
| + for (FileHandlerList::iterator i = file_handlers.begin(); |
| + i != file_handlers.end(); ++i) { |
| + const extensions::FileHandlerInfo* handler = *i; |
| + std::string task_id = file_handler_util::MakeTaskID(extension->id(), |
| + file_handler_util::kTaskApp, handler->id); |
| + if (task_id == default_task_id) { |
| + ExecuteHandler(profile, extension->id(), handler->id, url, |
| + file_handler_util::kTaskApp); |
| + return true; |
| + |
| + } else if (!first_handler) { |
| + first_handler = handler; |
| + extension_for_first_handler = extension; |
| + } |
| + } |
| + } |
| + if (first_handler) { |
| + ExecuteHandler(profile, extension_for_first_handler->id(), |
| + first_handler->id, url, file_handler_util::kTaskApp); |
| + return true; |
| + } |
| + return false; |
| +} |
| - std::string extension_id = handler->extension_id(); |
| - std::string action_id = handler->id(); |
| +bool ExecuteExtensionHandler(Profile* profile, |
| + const base::FilePath& path, |
| + const FileBrowserHandler& handler, |
| + const GURL& url) { |
| + std::string extension_id = handler.extension_id(); |
| + std::string action_id = handler.id(); |
| Browser* browser = chrome::FindLastActiveWithProfile(profile, |
| chrome::HOST_DESKTOP_TYPE_ASH); |
| @@ -434,7 +493,8 @@ bool ExecuteDefaultHandler(Profile* profile, const base::FilePath& path) { |
| action_id == kFileBrowserMountArchiveTaskId || |
| action_id == kFileBrowserPlayTaskId || |
| action_id == kFileBrowserWatchTaskId) { |
| - ExecuteHandler(profile, extension_id, action_id, url); |
| + ExecuteHandler(profile, extension_id, action_id, url, |
| + file_handler_util::kTaskFile); |
| return true; |
| } |
| return ExecuteBuiltinHandler(browser, path, action_id); |
| @@ -454,10 +514,45 @@ bool ExecuteDefaultHandler(Profile* profile, const base::FilePath& path) { |
| return ExecuteBuiltinHandler(browser, path, action_id); |
| } |
| - ExecuteHandler(profile, extension_id, action_id, url); |
| + ExecuteHandler(profile, extension_id, action_id, url, |
| + file_handler_util::kTaskFile); |
| return true; |
| } |
| +bool ExecuteDefaultHandler(Profile* profile, const base::FilePath& path) { |
| + GURL url; |
| + if (!ConvertFileToFileSystemUrl(profile, path, kFileBrowserDomain, &url)) |
| + return false; |
| + |
| + std::string mime_type = GetMimeTypeForPath(path); |
| + std::string default_task_id = file_handler_util::GetDefaultTaskIdFromPrefs( |
| + profile, mime_type, path.Extension()); |
| + const FileBrowserHandler* handler; |
| + |
| + // We choose the file handler from the following in decreasing priority or |
| + // fail if none support the file type: |
| + // 1. default extension |
|
mtomasz
2013/06/07 02:36:00
default extensions before apps, but non-default ap
Sam McNally
2013/06/07 05:29:13
Yes, but there can be at most one default handler.
|
| + // 2. default app |
| + // 3. a fallback handler (e.g. opening in the browser) |
| + // 4. non-default app |
| + // 5. non-default extension |
| + // Note that there can be at most one of default extension and default app. |
| + if (!file_handler_util::GetTaskForURLAndPath(profile, url, path, &handler)) { |
| + return ExecuteDefaultAppHandler( |
| + profile, path, url, mime_type, default_task_id); |
| + } |
| + |
| + std::string handler_task_id = file_handler_util::MakeTaskID( |
| + handler->extension_id(), file_handler_util::kTaskFile, handler->id()); |
| + if (handler_task_id != default_task_id && |
| + !file_handler_util::IsFallbackTask(handler) && |
| + ExecuteDefaultAppHandler( |
| + profile, path, url, mime_type, default_task_id)) { |
| + return true; |
| + } |
| + return ExecuteExtensionHandler(profile, path, *handler, url); |
| +} |
| + |
| // Reads the alternate URL from a GDoc file. When it fails, returns a file URL |
| // for |file_path| as fallback. |
| // Note that an alternate url is a URL to open a hosted document. |
| @@ -889,4 +984,24 @@ bool ShouldBeOpenedWithPlugin(Profile* profile, const char* file_extension) { |
| return false; |
| } |
| +std::string GetMimeTypeForPath(const base::FilePath& file_path) { |
| + const base::FilePath::StringType file_extension = |
| + StringToLowerASCII(file_path.Extension()); |
| + |
| + // TODO(thorogood): Rearchitect this call so it can run on the File thread; |
| + // GetMimeTypeFromFile requires this on Linux. Right now, we use |
| + // Chrome-level knowledge only. |
| + std::string mime_type; |
| + if (file_extension.empty() || |
| + !net::GetWellKnownMimeTypeFromExtension(file_extension.substr(1), |
| + &mime_type)) { |
| + // If the file doesn't have an extension or its mime-type cannot be |
| + // determined, then indicate that it has the empty mime-type. This will |
| + // only be matched if the Web Intents accepts "*" or "*/*". |
| + return ""; |
| + } else { |
| + return mime_type; |
| + } |
| +} |
| + |
| } // namespace file_manager_util |