Index: chrome/browser/chromeos/extensions/file_manager/file_tasks.cc |
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_tasks.cc b/chrome/browser/chromeos/extensions/file_manager/file_tasks.cc |
index 435257025278888adf461bdf2189098361a682ac..262705bce261e3021e6d3932b7097ff0b77a2964 100644 |
--- a/chrome/browser/chromeos/extensions/file_manager/file_tasks.cc |
+++ b/chrome/browser/chromeos/extensions/file_manager/file_tasks.cc |
@@ -8,6 +8,8 @@ |
#include "base/bind.h" |
#include "base/prefs/pref_service.h" |
#include "base/strings/stringprintf.h" |
+#include "chrome/browser/chromeos/drive/drive_app_registry.h" |
+#include "chrome/browser/chromeos/drive/drive_integration_service.h" |
#include "chrome/browser/chromeos/drive/file_task_executor.h" |
#include "chrome/browser/chromeos/extensions/file_manager/file_browser_handlers.h" |
#include "chrome/browser/chromeos/extensions/file_manager/fileapi_util.h" |
@@ -15,14 +17,19 @@ |
#include "chrome/browser/chromeos/fileapi/file_system_backend.h" |
#include "chrome/browser/extensions/extension_host.h" |
#include "chrome/browser/extensions/extension_service.h" |
+#include "chrome/browser/extensions/extension_service.h" |
+#include "chrome/browser/extensions/extension_system.h" |
#include "chrome/browser/extensions/extension_system.h" |
#include "chrome/browser/extensions/extension_tab_util.h" |
#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/ui/webui/extensions/extension_icon_source.h" |
+#include "chrome/common/extensions/api/file_browser_handlers/file_browser_handler.h" |
#include "chrome/common/pref_names.h" |
#include "webkit/browser/fileapi/file_system_context.h" |
#include "webkit/browser/fileapi/file_system_url.h" |
using extensions::Extension; |
+using extensions::app_file_handler_util::FindFileHandlersForFiles; |
using fileapi::FileSystemURL; |
namespace file_manager { |
@@ -40,6 +47,9 @@ const char kFileBrowserHandlerTaskType[] = "file"; |
const char kFileHandlerTaskType[] = "app"; |
const char kDriveAppTaskType[] = "drive"; |
+// Default icon path for drive docs. |
+const char kDefaultIcon[] = "images/filetype_generic.png"; |
+ |
// Converts a TaskType to a string. |
std::string TaskTypeToString(TaskType task_type) { |
switch (task_type) { |
@@ -262,5 +272,321 @@ bool ExecuteFileTask(Profile* profile, |
return false; |
} |
+struct TaskInfo { |
+ TaskInfo(const std::string& app_name, const GURL& icon_url) |
+ : app_name(app_name), icon_url(icon_url) { |
+ } |
+ |
+ std::string app_name; |
+ GURL icon_url; |
+}; |
+ |
+void GetAvailableDriveTasks( |
+ const drive::DriveAppRegistry& drive_app_registry, |
+ const PathAndMimeTypeSet& path_mime_set, |
+ TaskInfoMap* task_info_map) { |
+ DCHECK(task_info_map); |
+ DCHECK(task_info_map->empty()); |
+ |
+ bool is_first = true; |
+ for (PathAndMimeTypeSet::const_iterator it = path_mime_set.begin(); |
+ it != path_mime_set.end(); ++it) { |
+ const base::FilePath& file_path = it->first; |
+ const std::string& mime_type = it->second; |
+ if (file_path.empty()) |
+ continue; |
+ |
+ ScopedVector<drive::DriveAppInfo> app_info_list; |
+ drive_app_registry.GetAppsForFile(file_path, mime_type, &app_info_list); |
+ |
+ if (is_first) { |
+ // For the first file, we store all the info. |
+ for (size_t j = 0; j < app_info_list.size(); ++j) { |
+ const drive::DriveAppInfo& app_info = *app_info_list[j]; |
+ GURL icon_url = drive::util::FindPreferredIcon( |
+ app_info.app_icons, |
+ drive::util::kPreferredIconSize); |
+ task_info_map->insert(std::pair<std::string, TaskInfo>( |
+ file_tasks::MakeDriveAppTaskId(app_info.app_id), |
+ TaskInfo(app_info.app_name, icon_url))); |
+ } |
+ } else { |
+ // For remaining files, take the intersection with the current result, |
+ // based on the task id. |
+ std::set<std::string> task_id_set; |
+ for (size_t j = 0; j < app_info_list.size(); ++j) { |
+ task_id_set.insert( |
+ file_tasks::MakeDriveAppTaskId(app_info_list[j]->app_id)); |
+ } |
+ for (TaskInfoMap::iterator iter = task_info_map->begin(); |
+ iter != task_info_map->end(); ) { |
+ if (task_id_set.find(iter->first) == task_id_set.end()) { |
+ task_info_map->erase(iter++); |
+ } else { |
+ ++iter; |
+ } |
+ } |
+ } |
+ |
+ is_first = false; |
+ } |
+} |
+ |
+void FindDefaultDriveTasks( |
+ const PrefService& pref_service, |
+ const PathAndMimeTypeSet& path_mime_set, |
+ const TaskInfoMap& task_info_map, |
+ std::set<std::string>* default_tasks) { |
+ DCHECK(default_tasks); |
+ |
+ for (PathAndMimeTypeSet::const_iterator it = path_mime_set.begin(); |
+ it != path_mime_set.end(); ++it) { |
+ const base::FilePath& file_path = it->first; |
+ const std::string& mime_type = it->second; |
+ std::string task_id = file_tasks::GetDefaultTaskIdFromPrefs( |
+ pref_service, mime_type, file_path.Extension()); |
+ if (task_info_map.find(task_id) != task_info_map.end()) |
+ default_tasks->insert(task_id); |
+ } |
+} |
+ |
+void CreateDriveTasks( |
+ const TaskInfoMap& task_info_map, |
+ const std::set<std::string>& default_tasks, |
+ ListValue* result_list, |
+ bool* default_already_set) { |
+ DCHECK(result_list); |
+ DCHECK(default_already_set); |
+ |
+ for (TaskInfoMap::const_iterator iter = task_info_map.begin(); |
+ iter != task_info_map.end(); ++iter) { |
+ DictionaryValue* task = new DictionaryValue; |
+ task->SetString("taskId", iter->first); |
+ task->SetString("title", iter->second.app_name); |
+ |
+ const GURL& icon_url = iter->second.icon_url; |
+ if (!icon_url.is_empty()) |
+ task->SetString("iconUrl", icon_url.spec()); |
+ |
+ task->SetBoolean("driveApp", true); |
+ |
+ // Once we set a default app, we don't want to set any more. |
+ if (!(*default_already_set) && |
+ default_tasks.find(iter->first) != default_tasks.end()) { |
+ task->SetBoolean("isDefault", true); |
+ *default_already_set = true; |
+ } else { |
+ task->SetBoolean("isDefault", false); |
+ } |
+ result_list->Append(task); |
+ } |
+} |
+ |
+void FindDriveAppTasks( |
+ Profile* profile, |
+ const PathAndMimeTypeSet& path_mime_set, |
+ ListValue* result_list, |
+ bool* default_already_set) { |
+ DCHECK(!path_mime_set.empty()); |
+ DCHECK(result_list); |
+ DCHECK(default_already_set); |
+ |
+ drive::DriveIntegrationService* integration_service = |
+ drive::DriveIntegrationServiceFactory::GetForProfile(profile); |
+ // |integration_service| is NULL if Drive is disabled. |
+ if (!integration_service || !integration_service->drive_app_registry()) |
+ return; |
+ |
+ // Map of task_id to TaskInfo of available tasks. |
+ TaskInfoMap task_info_map; |
+ GetAvailableDriveTasks(*integration_service->drive_app_registry(), |
+ path_mime_set, |
+ &task_info_map); |
+ |
+ std::set<std::string> default_tasks; |
+ FindDefaultDriveTasks(*profile->GetPrefs(), |
+ path_mime_set, |
+ task_info_map, |
+ &default_tasks); |
+ CreateDriveTasks( |
+ task_info_map, default_tasks, result_list, default_already_set); |
+} |
+ |
+void FindFileHandlerTasks( |
+ Profile* profile, |
+ const PathAndMimeTypeSet& path_mime_set, |
+ ListValue* result_list, |
+ bool* default_already_set) { |
+ DCHECK(!path_mime_set.empty()); |
+ DCHECK(result_list); |
+ DCHECK(default_already_set); |
+ |
+ ExtensionService* service = profile->GetExtensionService(); |
+ if (!service) |
+ return; |
+ |
+ std::set<std::string> default_tasks; |
+ for (PathAndMimeTypeSet::iterator it = path_mime_set.begin(); |
+ it != path_mime_set.end(); ++it) { |
+ default_tasks.insert(file_tasks::GetDefaultTaskIdFromPrefs( |
+ *profile->GetPrefs(), it->second, it->first.Extension())); |
+ } |
+ |
+ for (ExtensionSet::const_iterator iter = service->extensions()->begin(); |
+ iter != service->extensions()->end(); |
+ ++iter) { |
+ const Extension* extension = iter->get(); |
+ |
+ // We don't support using hosted apps to open files. |
+ if (!extension->is_platform_app()) |
+ continue; |
+ |
+ if (profile->IsOffTheRecord() && |
+ !service->IsIncognitoEnabled(extension->id())) |
+ continue; |
+ |
+ typedef std::vector<const extensions::FileHandlerInfo*> FileHandlerList; |
+ FileHandlerList file_handlers = |
+ FindFileHandlersForFiles(*extension, path_mime_set); |
+ if (file_handlers.empty()) |
+ continue; |
+ |
+ for (FileHandlerList::iterator i = file_handlers.begin(); |
+ i != file_handlers.end(); ++i) { |
+ DictionaryValue* task = new DictionaryValue; |
+ std::string task_id = file_tasks::MakeTaskID( |
+ extension->id(), file_tasks::TASK_TYPE_FILE_HANDLER, (*i)->id); |
+ task->SetString("taskId", task_id); |
+ task->SetString("title", (*i)->title); |
+ if (!(*default_already_set) && ContainsKey(default_tasks, task_id)) { |
+ task->SetBoolean("isDefault", true); |
+ *default_already_set = true; |
+ } else { |
+ task->SetBoolean("isDefault", false); |
+ } |
+ |
+ GURL best_icon = extensions::ExtensionIconSource::GetIconURL( |
+ extension, |
+ drive::util::kPreferredIconSize, |
+ ExtensionIconSet::MATCH_BIGGER, |
+ false, // grayscale |
+ NULL); // exists |
+ if (!best_icon.is_empty()) |
+ task->SetString("iconUrl", best_icon.spec()); |
+ else |
+ task->SetString("iconUrl", kDefaultIcon); |
+ |
+ task->SetBoolean("driveApp", false); |
+ result_list->Append(task); |
+ } |
+ } |
+} |
+ |
+void FindFileBrowserHandlerTasks( |
+ Profile* profile, |
+ const std::vector<GURL>& file_urls, |
+ const std::vector<base::FilePath>& file_paths, |
+ ListValue* result_list, |
+ bool* default_already_set) { |
+ DCHECK(!file_paths.empty()); |
+ DCHECK(!file_urls.empty()); |
+ DCHECK(result_list); |
+ DCHECK(default_already_set); |
+ |
+ file_browser_handlers::FileBrowserHandlerList common_tasks = |
+ file_browser_handlers::FindCommonFileBrowserHandlers(profile, file_urls); |
+ if (common_tasks.empty()) |
+ return; |
+ file_browser_handlers::FileBrowserHandlerList default_tasks = |
+ file_browser_handlers::FindDefaultFileBrowserHandlers( |
+ *profile->GetPrefs(), file_paths, common_tasks); |
+ |
+ ExtensionService* service = |
+ extensions::ExtensionSystem::Get(profile)->extension_service(); |
+ for (file_browser_handlers::FileBrowserHandlerList::const_iterator iter = |
+ common_tasks.begin(); |
+ iter != common_tasks.end(); |
+ ++iter) { |
+ const FileBrowserHandler* handler = *iter; |
+ const std::string extension_id = handler->extension_id(); |
+ const Extension* extension = service->GetExtensionById(extension_id, false); |
+ CHECK(extension); |
+ DictionaryValue* task = new DictionaryValue; |
+ task->SetString("taskId", file_tasks::MakeTaskID( |
+ extension_id, |
+ file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER, |
+ handler->id())); |
+ task->SetString("title", handler->title()); |
+ // TODO(zelidrag): Figure out how to expose icon URL that task defined in |
+ // manifest instead of the default extension icon. |
+ GURL icon = extensions::ExtensionIconSource::GetIconURL( |
+ extension, |
+ extension_misc::EXTENSION_ICON_BITTY, |
+ ExtensionIconSet::MATCH_BIGGER, |
+ false, // grayscale |
+ NULL); // exists |
+ task->SetString("iconUrl", icon.spec()); |
+ task->SetBoolean("driveApp", false); |
+ |
+ // Only set the default if there isn't already a default set. |
+ if (!*default_already_set && |
+ std::find(default_tasks.begin(), default_tasks.end(), *iter) != |
+ default_tasks.end()) { |
+ task->SetBoolean("isDefault", true); |
+ *default_already_set = true; |
+ } else { |
+ task->SetBoolean("isDefault", false); |
+ } |
+ |
+ result_list->Append(task); |
+ } |
+} |
+ |
+void FindAllTypesOfTasks( |
+ Profile* profile, |
+ const PathAndMimeTypeSet& path_mime_set, |
+ const std::vector<GURL>& file_urls, |
+ const std::vector<base::FilePath>& file_paths, |
+ ListValue* result_list) { |
+ // Check if file_paths contain a google document. |
+ bool has_google_document = false; |
+ for (size_t i = 0; i < file_paths.size(); ++i) { |
+ if (google_apis::ResourceEntry::ClassifyEntryKindByFileExtension( |
+ file_paths[i]) & |
+ google_apis::ResourceEntry::KIND_OF_GOOGLE_DOCUMENT) { |
+ has_google_document = true; |
+ break; |
+ } |
+ } |
+ |
+ // Find the Drive app tasks first, because we want them to take precedence |
+ // when setting the default app. |
+ bool default_already_set = false; |
+ // Google document are not opened by drive apps but file manager. |
+ if (!has_google_document) { |
+ FindDriveAppTasks(profile, |
+ path_mime_set, |
+ result_list, |
+ &default_already_set); |
+ } |
+ |
+ // Find and append file handler tasks. We know there aren't duplicates |
+ // because Drive apps and platform apps are entirely different kinds of |
+ // tasks. |
+ FindFileHandlerTasks(profile, |
+ path_mime_set, |
+ result_list, |
+ &default_already_set); |
+ |
+ // Find and append file browser handler tasks. We know there aren't |
+ // duplicates because "file_browser_handlers" and "file_handlers" shouldn't |
+ // be used in the same manifest.json. |
+ FindFileBrowserHandlerTasks(profile, |
+ file_urls, |
+ file_paths, |
+ result_list, |
+ &default_already_set); |
+} |
+ |
} // namespace file_tasks |
} // namespace file_manager |