summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/chromeos/extensions/external_filesystem_apitest.cc31
-rw-r--r--chrome/browser/chromeos/extensions/file_browser_private_api.cc153
-rw-r--r--chrome/browser/chromeos/extensions/file_browser_private_api.h4
-rw-r--r--chrome/browser/chromeos/extensions/file_handler_util.cc254
-rw-r--r--chrome/browser/chromeos/extensions/file_handler_util.h46
-rw-r--r--chrome/browser/chromeos/extensions/file_manager_util.cc4
-rw-r--r--chrome/browser/chromeos/gdata/drive_task_executor.cc13
-rw-r--r--chrome/browser/chromeos/gdata/drive_task_executor.h1
-rw-r--r--chrome/browser/extensions/extension_special_storage_policy.cc41
-rw-r--r--chrome/browser/extensions/extension_special_storage_policy.h1
-rw-r--r--chrome/browser/extensions/extension_special_storage_policy_unittest.cc43
-rw-r--r--chrome/browser/resources/file_manager/js/file_tasks.js32
-rw-r--r--chrome/test/data/extensions/api_test/filebrowser_component/intent.html10
-rw-r--r--chrome/test/data/extensions/api_test/filebrowser_component/intent.js31
-rw-r--r--chrome/test/data/extensions/api_test/webintent_handler/background.js25
-rw-r--r--chrome/test/data/extensions/api_test/webintent_handler/manifest.json23
16 files changed, 569 insertions, 143 deletions
diff --git a/chrome/browser/chromeos/extensions/external_filesystem_apitest.cc b/chrome/browser/chromeos/extensions/external_filesystem_apitest.cc
index ba3add1..0d2f091 100644
--- a/chrome/browser/chromeos/extensions/external_filesystem_apitest.cc
+++ b/chrome/browser/chromeos/extensions/external_filesystem_apitest.cc
@@ -15,6 +15,7 @@
#include "chrome/browser/chromeos/gdata/drive_file_system.h"
#include "chrome/browser/chromeos/gdata/drive_system_service.h"
#include "chrome/browser/chromeos/gdata/mock_drive_service.h"
+#include "chrome/browser/extensions/event_router.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/google_apis/gdata_util.h"
@@ -24,6 +25,7 @@
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
@@ -245,6 +247,35 @@ IN_PROC_BROWSER_TEST_F(FileSystemExtensionApiTest, FileBrowserTestLazy) {
"filebrowser_component", "read.html", kComponentFlags)) << message_;
}
+IN_PROC_BROWSER_TEST_F(FileSystemExtensionApiTest, FileBrowserWebIntentTest) {
+ AddTmpMountPoint();
+
+ ResultCatcher catcher;
+ ScopedTempDir tmp_dir;
+ ASSERT_TRUE(tmp_dir.CreateUniqueTempDir());
+
+ // Create a test file inside the ScopedTempDir.
+ FilePath test_file = tmp_dir.path().AppendASCII("text_file.xul");
+ CreateDownloadFile(test_file);
+
+ ASSERT_TRUE(LoadExtension(
+ test_data_dir_.AppendASCII("webintent_handler"))) << message_;
+
+ // Load the source component, with the fileUrl within the virtual mount
+ // point.
+ const extensions::Extension* extension = LoadExtensionAsComponent(
+ test_data_dir_.AppendASCII("filebrowser_component"));
+ ASSERT_TRUE(extension) << message_;
+ std::string path = "filesystem:chrome-extension://" + extension->id() +
+ "/external" + test_file.value();
+ GURL url = extension->GetResourceURL("intent.html#" + path);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // The webintent_handler sends chrome.test.succeed() on successful receipt
+ // of the incoming Web Intent.
+ ASSERT_TRUE(catcher.GetNextResult()) << message_;
+}
+
IN_PROC_BROWSER_TEST_F(FileSystemExtensionApiTest, FileBrowserTestWrite) {
AddTmpMountPoint();
ASSERT_TRUE(RunExtensionTest("filesystem_handler_write")) << message_;
diff --git a/chrome/browser/chromeos/extensions/file_browser_private_api.cc b/chrome/browser/chromeos/extensions/file_browser_private_api.cc
index 22e88ee..c7dd48c 100644
--- a/chrome/browser/chromeos/extensions/file_browser_private_api.cc
+++ b/chrome/browser/chromeos/extensions/file_browser_private_api.cc
@@ -9,6 +9,9 @@
#include "base/base64.h"
#include "base/bind.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/i18n/case_conversion.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/memory/scoped_vector.h"
@@ -16,6 +19,7 @@
#include "base/string_split.h"
#include "base/stringprintf.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/network_library.h"
@@ -32,8 +36,10 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/extensions/process_map.h"
+#include "chrome/browser/google_apis/operation_registry.h"
#include "chrome/browser/google_apis/gdata_util.h"
#include "chrome/browser/google_apis/gdata_wapi_parser.h"
+#include "chrome/browser/intents/web_intents_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
@@ -53,6 +59,7 @@
#include "grit/generated_resources.h"
#include "grit/platform_locale_settings.h"
#include "net/base/escape.h"
+#include "net/base/mime_util.h"
#include "ui/base/dialogs/selected_file_info.h"
#include "ui/base/l10n/l10n_util.h"
#include "webkit/chromeos/fileapi/cros_mount_point_provider.h"
@@ -62,6 +69,7 @@
#include "webkit/fileapi/file_system_types.h"
#include "webkit/fileapi/file_system_url.h"
#include "webkit/fileapi/file_system_util.h"
+#include "webkit/glue/web_intent_service_data.h"
using chromeos::disks::DiskMountManager;
using content::BrowserContext;
@@ -76,7 +84,7 @@ using gdata::InstalledApp;
namespace {
// Default icon path for drive docs.
-const char kDefaultDriveIcon[] = "images/filetype_generic.png";
+const char kDefaultIcon[] = "images/filetype_generic.png";
const int kPreferredIconSize = 16;
// Error messages.
@@ -234,6 +242,45 @@ GURL FindPreferredIcon(const InstalledApp::IconList& icons,
return result;
}
+// Finds the title of the given Web Intents |action|, if the passed extension
+// supports this action for all specified |mime_types|. Returns true and
+// provides the |title| as output on success.
+bool FindTitleForActionWithTypes(
+ const Extension* extension,
+ const std::string& action,
+ const std::set<std::string>& mime_types,
+ std::string* title) {
+ DCHECK(!mime_types.empty());
+ std::set<std::string> pending(mime_types.begin(), mime_types.end());
+ std::string found_title;
+
+ for (std::vector<webkit_glue::WebIntentServiceData>::const_iterator data =
+ extension->intents_services().begin();
+ data != extension->intents_services().end(); ++data) {
+ if (pending.empty())
+ break;
+
+ if (UTF16ToUTF8(data->action) != action)
+ continue;
+
+ std::set<std::string>::iterator pending_iter = pending.begin();
+ while (pending_iter != pending.end()) {
+ std::set<std::string>::iterator current = pending_iter++;
+ if (net::MatchesMimeType(UTF16ToUTF8(data->type), *current))
+ pending.erase(current);
+ }
+ if (found_title.empty())
+ found_title = UTF16ToUTF8(data->title);
+ }
+
+ // Not all mime-types have been found.
+ if (!pending.empty())
+ return false;
+
+ *title = found_title;
+ return true;
+}
+
// Retrieves total and remaining available size on |mount_path|.
void GetSizeStatsOnFileThread(const std::string& mount_path,
size_t* total_size_kb,
@@ -602,8 +649,8 @@ void GetFileTasksFileBrowserFunction::IntersectAvailableDriveTasks(
app_info->insert(std::make_pair((*apps)->app_id, *apps));
// TODO(gspencer): For now, the action id is always "open-with", but we
// could add any actions that the drive app supports.
- std::string task_id =
- file_handler_util::MakeDriveTaskID((*apps)->app_id, "open-with");
+ std::string task_id = file_handler_util::MakeTaskID(
+ (*apps)->app_id, file_handler_util::kTaskDrive, "open-with");
tasks_for_this_file.insert(task_id);
// If we failed to insert a task_id because there was a duplicate, then we
// must delete it (since we own it).
@@ -656,10 +703,12 @@ void GetFileTasksFileBrowserFunction::CreateDriveTasks(
for (std::set<std::string>::const_iterator app_iter = available_tasks.begin();
app_iter != available_tasks.end(); ++app_iter) {
std::string app_id;
- bool result = file_handler_util::CrackDriveTaskID(*app_iter, &app_id, NULL);
+ std::string task_type;
+ bool result = file_handler_util::CrackTaskID(
+ *app_iter, &app_id, &task_type, NULL);
DCHECK(result) << "Unable to parse Drive task id: " << *app_iter;
- if (!result)
- continue;
+ DCHECK_EQ(task_type, file_handler_util::kTaskDrive);
+
WebAppInfoMap::const_iterator info_iter = app_info.find(app_id);
DCHECK(info_iter != app_info.end());
gdata::DriveWebAppInfo* info = info_iter->second;
@@ -707,7 +756,6 @@ bool GetFileTasksFileBrowserFunction::FindDriveAppTasks(
if (!system_service || !system_service->webapps_registry())
return true;
-
gdata::DriveWebAppsRegistry* registry = system_service->webapps_registry();
// Map of app_id to DriveWebAppInfo so we can look up the apps we've found
@@ -729,6 +777,77 @@ bool GetFileTasksFileBrowserFunction::FindDriveAppTasks(
return true;
}
+// Find Web Intent platform apps that support the View task, and add them to
+// the |result_list|. These will be marked as kTaskWebIntent.
+bool GetFileTasksFileBrowserFunction::FindWebIntentTasks(
+ const std::vector<GURL>& file_urls,
+ ListValue* result_list) {
+ DCHECK(!file_urls.empty());
+ ExtensionService* service = profile_->GetExtensionService();
+ if (!service)
+ return false;
+
+ std::set<std::string> mime_types;
+ for (std::vector<GURL>::const_iterator iter = file_urls.begin();
+ iter != file_urls.end(); ++iter) {
+ const FilePath file = FilePath(GURL(iter->spec()).ExtractFileName());
+ const FilePath::StringType file_extension =
+ StringToLowerASCII(file.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 "*/*".
+ mime_types.insert("");
+ } else {
+ mime_types.insert(mime_type);
+ }
+ }
+
+ 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.
+ if (!extension->is_platform_app())
+ continue;
+
+ if (profile_->IsOffTheRecord() &&
+ !service->IsIncognitoEnabled(extension->id()))
+ continue;
+
+ std::string title;
+ if (!FindTitleForActionWithTypes(
+ extension, web_intents::kActionView, mime_types, &title))
+ continue;
+
+ DictionaryValue* task = new DictionaryValue;
+ std::string task_id = file_handler_util::MakeTaskID(extension->id(),
+ file_handler_util::kTaskWebIntent, web_intents::kActionView);
+ task->SetString("taskId", task_id);
+ task->SetString("title", title);
+ task->SetBoolean("isDefault", false);
+
+ GURL best_icon = extension->GetIconURL(kPreferredIconSize,
+ ExtensionIconSet::MATCH_BIGGER);
+ if (!best_icon.is_empty())
+ task->SetString("iconUrl", best_icon.spec());
+ else
+ task->SetString("iconUrl", kDefaultIcon);
+
+ task->SetBoolean("driveApp", false);
+ result_list->Append(task);
+ }
+
+ return true;
+}
+
bool GetFileTasksFileBrowserFunction::RunImpl() {
// First argument is the list of files to get tasks for.
ListValue* files_list = NULL;
@@ -798,8 +917,8 @@ bool GetFileTasksFileBrowserFunction::RunImpl() {
const Extension* extension = service->GetExtensionById(extension_id, false);
CHECK(extension);
DictionaryValue* task = new DictionaryValue;
- task->SetString("taskId",
- file_handler_util::MakeTaskID(extension_id, handler->id()));
+ task->SetString("taskId", file_handler_util::MakeTaskID(
+ extension_id, file_handler_util::kTaskFile, 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.
@@ -823,6 +942,12 @@ bool GetFileTasksFileBrowserFunction::RunImpl() {
result_list->Append(task);
}
+ // Take the union of Web Intents (that platform apps may accept) and all
+ // previous Drive and extension tasks. As above, we know there aren't
+ // duplicates because they're entirely different kinds of tasks.
+ if (!FindWebIntentTasks(file_urls, result_list))
+ return false;
+
if (VLOG_IS_ON(1)) {
std::string result_json;
base::JSONWriter::WriteWithOptions(
@@ -833,8 +958,6 @@ bool GetFileTasksFileBrowserFunction::RunImpl() {
VLOG(1) << "GetFileTasks result:\n" << result_json;
}
- // TODO(zelidrag, serya): Add intent content tasks to result_list once we
- // implement that API.
SendResponse(true);
return true;
}
@@ -863,8 +986,10 @@ bool ExecuteTasksFileBrowserFunction::RunImpl() {
return false;
std::string extension_id;
+ std::string task_type;
std::string action_id;
- if (!file_handler_util::CrackTaskID(task_id, &extension_id, &action_id)) {
+ if (!file_handler_util::CrackTaskID(
+ task_id, &extension_id, &task_type, &action_id)) {
LOG(WARNING) << "Invalid task " << task_id;
return false;
}
@@ -886,6 +1011,7 @@ bool ExecuteTasksFileBrowserFunction::RunImpl() {
FileTaskExecutor::Create(profile(),
source_url(),
extension_id,
+ task_type,
action_id));
if (!executor->ExecuteAndNotify(
@@ -2035,7 +2161,8 @@ void GetDriveFilePropertiesFunction::OnOperationComplete(
file_specific_info.content_mime_type(),
file_path.Extension());
std::string default_app_id;
- file_handler_util::CrackDriveTaskID(default_task_id, &default_app_id, NULL);
+ file_handler_util::CrackTaskID(
+ default_task_id, &default_app_id, NULL, NULL);
ListValue* apps = new ListValue();
property_dict->Set("driveApps", apps);
diff --git a/chrome/browser/chromeos/extensions/file_browser_private_api.h b/chrome/browser/chromeos/extensions/file_browser_private_api.h
index 81e5fe1..d08326e 100644
--- a/chrome/browser/chromeos/extensions/file_browser_private_api.h
+++ b/chrome/browser/chromeos/extensions/file_browser_private_api.h
@@ -170,6 +170,10 @@ class GetFileTasksFileBrowserFunction : public AsyncExtensionFunction {
ListValue* result_list,
bool* default_already_set);
+ // Find the list of Web Intent tasks that can be used with the given file
+ // types, appending them to the |result_list|.
+ bool FindWebIntentTasks(const std::vector<GURL>& file_urls,
+ ListValue* result_list);
};
// Implements the chrome.fileBrowserPrivate.executeTask method.
diff --git a/chrome/browser/chromeos/extensions/file_handler_util.cc b/chrome/browser/chromeos/extensions/file_handler_util.cc
index afe5614..18058dc 100644
--- a/chrome/browser/chromeos/extensions/file_handler_util.cc
+++ b/chrome/browser/chromeos/extensions/file_handler_util.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/extensions/lazy_background_task_queue.h"
+#include "chrome/browser/extensions/platform_app_launcher.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
@@ -39,6 +40,7 @@
#include "webkit/fileapi/file_system_context.h"
#include "webkit/fileapi/file_system_url.h"
#include "webkit/fileapi/file_system_util.h"
+#include "webkit/fileapi/isolated_context.h"
using content::BrowserContext;
using content::BrowserThread;
@@ -49,12 +51,17 @@ using extensions::Extension;
namespace file_handler_util {
-// The prefix used to differentiate drive extensions from Chrome extensions.
-const char FileTaskExecutor::kDriveTaskExtensionPrefix[] = "drive-app:";
-const size_t FileTaskExecutor::kDriveTaskExtensionPrefixLength =
- arraysize(FileTaskExecutor::kDriveTaskExtensionPrefix) - 1;
+const char kTaskFile[] = "file";
+const char kTaskDrive[] = "drive";
+const char kTaskWebIntent[] = "web-intent";
namespace {
+
+// Legacy Drive task extension prefix, used by CrackTaskID.
+const char kDriveTaskExtensionPrefix[] = "drive-app:";
+const size_t kDriveTaskExtensionPrefixLength =
+ arraysize(kDriveTaskExtensionPrefix) - 1;
+
typedef std::set<const FileBrowserHandler*> FileBrowserHandlerSet;
const int kReadWriteFilePermissions = base::PLATFORM_FILE_OPEN |
@@ -113,8 +120,9 @@ const FileBrowserHandler* FindFileBrowserHandler(const Extension* extension,
return NULL;
}
-unsigned int GetAccessPermissionsForHandler(const Extension* extension,
- const std::string& action_id) {
+unsigned int GetAccessPermissionsForFileBrowserHandler(
+ const Extension* extension,
+ const std::string& action_id) {
const FileBrowserHandler* action =
FindFileBrowserHandler(extension, action_id);
if (!action)
@@ -128,7 +136,6 @@ unsigned int GetAccessPermissionsForHandler(const Extension* extension,
return result;
}
-
std::string EscapedUtf8ToLower(const std::string& str) {
string16 utf16 = UTF8ToUTF16(
net::UnescapeURLComponent(str, net::UnescapeRule::NORMAL));
@@ -246,52 +253,66 @@ int GetReadOnlyPermissions() {
}
std::string MakeTaskID(const std::string& extension_id,
+ const std::string& task_type,
const std::string& action_id) {
- return base::StringPrintf("%s|%s", extension_id.c_str(), action_id.c_str());
-}
-
-std::string MakeDriveTaskID(const std::string& app_id,
- const std::string& action_id) {
- return MakeTaskID(FileTaskExecutor::kDriveTaskExtensionPrefix + app_id,
- action_id);
-}
-
-bool CrackDriveTaskID(const std::string& task_id,
- std::string* app_id,
- std::string* action_id) {
- std::string app_id_tmp;
- std::string action_id_tmp;
- if (!CrackTaskID(task_id, &app_id_tmp, &action_id_tmp))
- return false;
- if (StartsWithASCII(app_id_tmp,
- FileTaskExecutor::kDriveTaskExtensionPrefix,
- false)) {
- // Strip off the prefix from the extension ID so we convert it to an app id.
- if (app_id) {
- *app_id = app_id_tmp.substr(
- FileTaskExecutor::kDriveTaskExtensionPrefixLength);
- }
- if (action_id)
- *action_id = action_id_tmp;
- return true;
- }
- return false;
+ DCHECK(task_type == kTaskFile ||
+ task_type == kTaskDrive ||
+ task_type == kTaskWebIntent);
+ return base::StringPrintf("%s|%s|%s",
+ extension_id.c_str(),
+ task_type.c_str(),
+ action_id.c_str());
}
// Breaks down task_id that is used between getFileTasks() and executeTask() on
// its building blocks. task_id field the following structure:
-// <extension-id>|<task-action-id>
+// <extension-id>|<task-type>|<task-action-id>
bool CrackTaskID(const std::string& task_id,
std::string* extension_id,
+ std::string* task_type,
std::string* action_id) {
std::vector<std::string> result;
int count = Tokenize(task_id, std::string("|"), &result);
- if (count != 2)
+
+ // Parse historic task_id parameters that only contain two parts. Drive tasks
+ // are identified by a prefix "drive-app:" on the extension ID.
+ if (count == 2) {
+ if (StartsWithASCII(result[0], kDriveTaskExtensionPrefix, true)) {
+ if (task_type)
+ *task_type = kTaskDrive;
+
+ if (extension_id)
+ *extension_id = result[0].substr(kDriveTaskExtensionPrefixLength);
+ } else {
+ if (task_type)
+ *task_type = kTaskFile;
+
+ if (extension_id)
+ *extension_id = result[0];
+ }
+
+ if (action_id)
+ *action_id = result[1];
+
+ return true;
+ }
+
+ if (count != 3)
return false;
+
if (extension_id)
*extension_id = result[0];
+
+ if (task_type) {
+ *task_type = result[1];
+ DCHECK(*task_type == kTaskFile ||
+ *task_type == kTaskDrive ||
+ *task_type == kTaskWebIntent);
+ }
+
if (action_id)
- *action_id = result[1];
+ *action_id = result[2];
+
return true;
}
@@ -309,6 +330,8 @@ FileBrowserHandlerSet::iterator FindHandler(
return iter;
}
+// Given the list of selected files, returns array of file action tasks
+// that are shared between them.
void FindDefaultTasks(Profile* profile,
const std::vector<GURL>& files_list,
const FileBrowserHandlerSet& common_tasks,
@@ -337,7 +360,7 @@ void FindDefaultTasks(Profile* profile,
// from common_tasks.
for (FileBrowserHandlerSet::const_iterator task_iter = common_tasks.begin();
task_iter != common_tasks.end(); ++task_iter) {
- std::string task_id = MakeTaskID((*task_iter)->extension_id(),
+ std::string task_id = MakeTaskID((*task_iter)->extension_id(), kTaskFile,
(*task_iter)->id());
for (std::set<std::string>::iterator default_iter = default_ids.begin();
default_iter != default_ids.end(); ++default_iter) {
@@ -492,7 +515,6 @@ class ExtensionTaskExecutor : public FileTaskExecutor {
void InitHandlerHostFileAccessPermissions(
const FileDefinitionList& file_list,
const extensions::Extension* handler_extension,
- const std::string& action_id,
const base::Closure& callback);
// Invoked upon completion of InitHandlerHostFileAccessPermissions initiated
@@ -507,11 +529,7 @@ class ExtensionTaskExecutor : public FileTaskExecutor {
// ChildProcessSecurityPolicy for process with id |handler_pid|.
void SetupHandlerHostFileAccessPermissions(int handler_pid);
- // Helper function to get the extension pointer.
- const extensions::Extension* GetExtension();
-
const GURL source_url_;
- const std::string extension_id_;
const std::string action_id_;
FileTaskFinishedCallback done_;
@@ -519,28 +537,61 @@ class ExtensionTaskExecutor : public FileTaskExecutor {
std::vector<std::pair<FilePath, int> > handler_host_permissions_;
};
+class WebIntentTaskExecutor : public FileTaskExecutor {
+ public:
+ // FileTaskExecutor overrides.
+ virtual bool ExecuteAndNotify(const std::vector<GURL>& file_urls,
+ const FileTaskFinishedCallback& done) OVERRIDE;
+
+ private:
+ // FileTaskExecutor is the only class allowed to create one.
+ friend class FileTaskExecutor;
+
+ WebIntentTaskExecutor(Profile* profile,
+ const GURL source_url,
+ const std::string& extension_id,
+ const std::string& action_id);
+ virtual ~WebIntentTaskExecutor();
+
+ bool ExecuteForURL(const GURL& file_url);
+
+ const GURL source_url_;
+ const std::string extension_id_;
+ const std::string action_id_;
+};
+
// static
FileTaskExecutor* FileTaskExecutor::Create(Profile* profile,
const GURL source_url,
const std::string& extension_id,
+ const std::string& task_type,
const std::string& action_id) {
- // Check out the extension ID and see if this is a drive task,
- // and instantiate drive-specific executor if so.
- if (StartsWithASCII(extension_id,
- FileTaskExecutor::kDriveTaskExtensionPrefix,
- false)) {
+ if (task_type == kTaskFile)
+ return new ExtensionTaskExecutor(profile,
+ source_url,
+ extension_id,
+ action_id);
+
+ if (task_type == kTaskDrive)
return new gdata::DriveTaskExecutor(profile,
- extension_id, // really app_id
+ extension_id, // really app_id
action_id);
- } else {
- return new ExtensionTaskExecutor(profile,
+
+ if (task_type == kTaskWebIntent)
+ return new WebIntentTaskExecutor(profile,
source_url,
extension_id,
action_id);
- }
+
+ NOTREACHED();
+ return NULL;
}
-FileTaskExecutor::FileTaskExecutor(Profile* profile) : profile_(profile) {
+FileTaskExecutor::FileTaskExecutor(
+ Profile* profile,
+ const std::string& extension_id)
+ : profile_(profile),
+ extension_id_(extension_id) {
}
FileTaskExecutor::~FileTaskExecutor() {
@@ -555,6 +606,14 @@ Browser* FileTaskExecutor::GetBrowser() const {
profile_ ? profile_ : ProfileManager::GetDefaultProfileOrOffTheRecord());
}
+const Extension* FileTaskExecutor::GetExtension() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ ExtensionService* service = profile()->GetExtensionService();
+ return service ? service->GetExtensionById(extension_id_, false) :
+ NULL;
+}
+
ExtensionTaskExecutor::FileDefinition::FileDefinition() : is_directory(false) {
}
@@ -724,10 +783,9 @@ ExtensionTaskExecutor::ExtensionTaskExecutor(
const GURL source_url,
const std::string& extension_id,
const std::string& action_id)
- : FileTaskExecutor(profile),
- source_url_(source_url),
- extension_id_(extension_id),
- action_id_(action_id) {
+ : FileTaskExecutor(profile, extension_id),
+ source_url_(source_url),
+ action_id_(action_id) {
}
ExtensionTaskExecutor::~ExtensionTaskExecutor() {}
@@ -735,12 +793,7 @@ ExtensionTaskExecutor::~ExtensionTaskExecutor() {}
bool ExtensionTaskExecutor::ExecuteAndNotify(
const std::vector<GURL>& file_urls,
const FileTaskFinishedCallback& done) {
- ExtensionService* service = profile()->GetExtensionService();
- if (!service)
- return false;
-
- scoped_refptr<const Extension> handler =
- service->GetExtensionById(extension_id_, false);
+ scoped_refptr<const Extension> handler = GetExtension();
if (!handler.get())
return false;
@@ -797,14 +850,6 @@ void ExtensionTaskExecutor::ExecuteDoneOnUIThread(bool success) {
done_.Reset();
}
-const Extension* ExtensionTaskExecutor::GetExtension() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- ExtensionService* service = profile()->GetExtensionService();
- return service ? service->GetExtensionById(extension_id_, false) :
- NULL;
-}
-
void ExtensionTaskExecutor::ExecuteFileActionsOnUIThread(
const std::string& file_system_name,
const GURL& file_system_root,
@@ -821,7 +866,6 @@ void ExtensionTaskExecutor::ExecuteFileActionsOnUIThread(
InitHandlerHostFileAccessPermissions(
file_list,
extension,
- action_id_,
base::Bind(
&ExtensionTaskExecutor::OnInitAccessForExecuteFileActionsOnUIThread,
this,
@@ -857,7 +901,7 @@ void ExtensionTaskExecutor::OnInitAccessForExecuteFileActionsOnUIThread(
return;
}
queue->AddPendingTask(
- profile(), extension_id_,
+ profile(), extension_id(),
base::Bind(&ExtensionTaskExecutor::SetupPermissionsAndDispatchEvent,
this, file_system_name, file_system_root, file_list,
handler_pid));
@@ -916,7 +960,7 @@ void ExtensionTaskExecutor::SetupPermissionsAndDispatchEvent(
}
event_router->DispatchEventToExtension(
- extension_id_, std::string("fileBrowserHandler.onExecute"),
+ extension_id(), std::string("fileBrowserHandler.onExecute"),
event_args.Pass(), profile(), GURL());
ExecuteDoneOnUIThread(true);
}
@@ -924,7 +968,6 @@ void ExtensionTaskExecutor::SetupPermissionsAndDispatchEvent(
void ExtensionTaskExecutor::InitHandlerHostFileAccessPermissions(
const FileDefinitionList& file_list,
const Extension* handler_extension,
- const std::string& action_id,
const base::Closure& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -933,9 +976,9 @@ void ExtensionTaskExecutor::InitHandlerHostFileAccessPermissions(
iter != file_list.end();
++iter) {
// Setup permission for file's absolute file.
- handler_host_permissions_.push_back(std::make_pair(
- iter->absolute_path,
- GetAccessPermissionsForHandler(handler_extension, action_id)));
+ handler_host_permissions_.push_back(std::make_pair(iter->absolute_path,
+ GetAccessPermissionsForFileBrowserHandler(handler_extension,
+ action_id_)));
if (gdata::util::IsUnderDriveMountPoint(iter->absolute_path))
gdata_paths->push_back(iter->virtual_path);
@@ -968,4 +1011,55 @@ void ExtensionTaskExecutor::SetupHandlerHostFileAccessPermissions(
handler_host_permissions_.clear();
}
+WebIntentTaskExecutor::WebIntentTaskExecutor(
+ Profile* profile,
+ const GURL source_url,
+ const std::string& extension_id,
+ const std::string& action_id)
+ : FileTaskExecutor(profile, extension_id),
+ source_url_(source_url),
+ action_id_(action_id) {
+}
+
+WebIntentTaskExecutor::~WebIntentTaskExecutor() {}
+
+bool WebIntentTaskExecutor::ExecuteAndNotify(
+ const std::vector<GURL>& file_urls,
+ const FileTaskFinishedCallback& done) {
+ bool success = true;
+
+ for (std::vector<GURL>::const_iterator i = file_urls.begin();
+ i != file_urls.end(); ++i) {
+ if (!ExecuteForURL(*i))
+ success = false;
+ }
+
+ if (!done.is_null())
+ done.Run(success);
+
+ return true;
+}
+
+bool WebIntentTaskExecutor::ExecuteForURL(const GURL& file_url) {
+ fileapi::FileSystemURL url(file_url);
+ if (!chromeos::CrosMountPointProvider::CanHandleURL(url))
+ return false;
+
+ scoped_refptr<fileapi::FileSystemContext> file_system_context =
+ BrowserContext::GetDefaultStoragePartition(profile())->
+ GetFileSystemContext();
+ fileapi::ExternalFileSystemMountPointProvider* external_provider =
+ file_system_context->external_provider();
+ if (!external_provider || !external_provider->IsAccessAllowed(url))
+ return false;
+
+ // Make sure this url really being used by the right caller extension.
+ if (source_url_.GetOrigin() != url.origin())
+ return false;
+
+ FilePath local_path = url.path();
+ extensions::LaunchPlatformAppWithPath(profile(), GetExtension(), local_path);
+ return true;
+}
+
} // namespace file_handler_util
diff --git a/chrome/browser/chromeos/extensions/file_handler_util.h b/chrome/browser/chromeos/extensions/file_handler_util.h
index 8a0be47..8ab9e3d 100644
--- a/chrome/browser/chromeos/extensions/file_handler_util.h
+++ b/chrome/browser/chromeos/extensions/file_handler_util.h
@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_HANDLER_UTIL_H_
#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_HANDLER_UTIL_H_
+#include <string>
#include <vector>
#include "base/callback.h"
@@ -17,8 +18,20 @@ class Browser;
class GURL;
class Profile;
+namespace extensions {
+class Extension;
+} // namespace extensions
+
namespace file_handler_util {
+// Specifies the task type for a task id that represents some file action, Drive
+// action, or Web Intent action.
+extern const char kTaskFile[];
+extern const char kTaskDrive[];
+extern const char kTaskWebIntent[];
+
+void UpdateFileHandlerUsageStats(Profile* profile, const std::string& task_id);
+
// Update the default file handler for the given sets of suffixes and MIME
// types.
void UpdateDefaultTask(Profile* profile,
@@ -39,27 +52,18 @@ int GetReadWritePermissions();
// Gets read-only file access permission flags.
int GetReadOnlyPermissions();
-// Generates file task id for the file action specified by the extension.
+// Generates task id for the action specified by the extension. The |task_type|
+// must be one of kTaskFile, kTaskDrive, or kTaskWebIntent.
std::string MakeTaskID(const std::string& extension_id,
+ const std::string& task_type,
const std::string& action_id);
-// Make a task id specific to drive apps instead of extensions.
-std::string MakeDriveTaskID(const std::string& app_id,
- const std::string& action_id);
-
-// Returns the |target_id| and |action_id| of a drive app or extension, given
-// the drive |task_id| created by MakeDriveTaskID. If the |task_id| is a drive
-// task_id then it will return true. If not, or if parsing fails, will return
-// false and not set |app_id| or |action_id|.
-bool CrackDriveTaskID(const std::string& task_id,
- std::string* app_id,
- std::string* action_id);
-
-// Extracts action and extension id bound to the file task. Either
+// Extracts action, type and extension id bound to the file task. Either
// |target_extension_id| or |action_id| are allowed to be NULL if caller isn't
// interested in those values. Returns false on failure to parse.
bool CrackTaskID(const std::string& task_id,
std::string* target_extension_id,
+ std::string* task_type,
std::string* action_id);
// This generates a list of default tasks (tasks set as default by the user in
@@ -88,13 +92,11 @@ typedef base::Callback<void(bool)> FileTaskFinishedCallback;
// Helper class for executing file browser file action.
class FileTaskExecutor : public base::RefCountedThreadSafe<FileTaskExecutor> {
public:
- static const char kDriveTaskExtensionPrefix[];
- static const size_t kDriveTaskExtensionPrefixLength;
-
// Creates the appropriate FileTaskExecutor for the given |extension_id|.
static FileTaskExecutor* Create(Profile* profile,
const GURL source_url,
const std::string& extension_id,
+ const std::string& task_type,
const std::string& action_id);
// Same as ExecuteAndNotify, but no notification is performed.
@@ -110,7 +112,7 @@ class FileTaskExecutor : public base::RefCountedThreadSafe<FileTaskExecutor> {
const FileTaskFinishedCallback& done) = 0;
protected:
- explicit FileTaskExecutor(Profile* profile);
+ explicit FileTaskExecutor(Profile* profile, const std::string& extension_id);
virtual ~FileTaskExecutor();
// Returns the profile that this task was created with.
@@ -118,10 +120,18 @@ class FileTaskExecutor : public base::RefCountedThreadSafe<FileTaskExecutor> {
// Returns a browser to use for the current browser.
Browser* GetBrowser() const;
+
+ // Returns the extension for this profile.
+ const extensions::Extension* GetExtension();
+
+ // Returns the extension ID set for this FileTaskExecutor.
+ const std::string& extension_id() { return extension_id_; }
+
private:
friend class base::RefCountedThreadSafe<FileTaskExecutor>;
Profile* profile_;
+ const std::string extension_id_;
};
} // namespace file_handler_util
diff --git a/chrome/browser/chromeos/extensions/file_manager_util.cc b/chrome/browser/chromeos/extensions/file_manager_util.cc
index e21c64a..283dbfa 100644
--- a/chrome/browser/chromeos/extensions/file_manager_util.cc
+++ b/chrome/browser/chromeos/extensions/file_manager_util.cc
@@ -594,8 +594,8 @@ bool ExecuteDefaultHandler(Profile* profile, const FilePath& path) {
std::vector<GURL> urls;
urls.push_back(url);
- scoped_refptr<FileTaskExecutor> executor = FileTaskExecutor::Create(
- profile, source_url, extension_id, action_id);
+ scoped_refptr<FileTaskExecutor> executor = FileTaskExecutor::Create(profile,
+ source_url, extension_id, file_handler_util::kTaskFile, action_id);
executor->Execute(urls);
return true;
}
diff --git a/chrome/browser/chromeos/gdata/drive_task_executor.cc b/chrome/browser/chromeos/gdata/drive_task_executor.cc
index 9bd0895..67e54bb 100644
--- a/chrome/browser/chromeos/gdata/drive_task_executor.cc
+++ b/chrome/browser/chromeos/gdata/drive_task_executor.cc
@@ -31,17 +31,10 @@ using file_handler_util::FileTaskExecutor;
DriveTaskExecutor::DriveTaskExecutor(Profile* profile,
const std::string& app_id,
const std::string& action_id)
- : file_handler_util::FileTaskExecutor(profile),
- app_id_(app_id),
+ : file_handler_util::FileTaskExecutor(profile, app_id),
action_id_(action_id),
current_index_(0) {
DCHECK("open-with" == action_id_);
- DCHECK(app_id.size() > FileTaskExecutor::kDriveTaskExtensionPrefixLength);
- DCHECK(StartsWithASCII(app_id,
- FileTaskExecutor::kDriveTaskExtensionPrefix,
- false));
- // Strip off the prefix from the extension ID so we convert it to an app id.
- app_id_ = app_id_.substr(FileTaskExecutor::kDriveTaskExtensionPrefixLength);
}
DriveTaskExecutor::~DriveTaskExecutor() {
@@ -105,7 +98,7 @@ void DriveTaskExecutor::OnFileEntryFetched(
// open-with-<app_id> urls from the document entry.
drive_service->AuthorizeApp(
GURL(entry_proto->edit_url()),
- app_id_,
+ extension_id(), // really app_id
base::Bind(&DriveTaskExecutor::OnAppAuthorized,
this,
entry_proto->resource_id()));
@@ -138,7 +131,7 @@ void DriveTaskExecutor::OnAppAuthorized(
link_list->GetDictionary(i, &entry);
std::string app_id;
entry->GetString("app_id", &app_id);
- if (app_id == app_id_) {
+ if (app_id == extension_id()) {
std::string href;
entry->GetString("href", &href);
open_with_url = GURL(href);
diff --git a/chrome/browser/chromeos/gdata/drive_task_executor.h b/chrome/browser/chromeos/gdata/drive_task_executor.h
index bb94fbc..4a3e3fe 100644
--- a/chrome/browser/chromeos/gdata/drive_task_executor.h
+++ b/chrome/browser/chromeos/gdata/drive_task_executor.h
@@ -46,7 +46,6 @@ class DriveTaskExecutor : public file_handler_util::FileTaskExecutor {
void Done(bool success);
const GURL source_url_;
- std::string app_id_;
const std::string action_id_;
int current_index_;
file_handler_util::FileTaskFinishedCallback done_;
diff --git a/chrome/browser/extensions/extension_special_storage_policy.cc b/chrome/browser/extensions/extension_special_storage_policy.cc
index 3d78c16..f5fb427 100644
--- a/chrome/browser/extensions/extension_special_storage_policy.cc
+++ b/chrome/browser/extensions/extension_special_storage_policy.cc
@@ -7,16 +7,36 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/stl_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/content_settings/cookie_settings.h"
+#include "chrome/browser/intents/web_intents_util.h"
#include "chrome/common/content_settings.h"
#include "chrome/common/content_settings_types.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/browser_thread.h"
+#include "webkit/glue/web_intent_service_data.h"
using content::BrowserThread;
using extensions::APIPermission;
+namespace {
+
+// Does the specified extension support the passed Web Intent, |action|?
+bool ExtensionSupportsIntentAction(
+ const extensions::Extension* extension,
+ const std::string& action) {
+ for (std::vector<webkit_glue::WebIntentServiceData>::const_iterator i =
+ extension->intents_services().begin();
+ i != extension->intents_services().end(); ++i) {
+ if (UTF16ToUTF8(i->action) == action)
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
ExtensionSpecialStoragePolicy::ExtensionSpecialStoragePolicy(
CookieSettings* cookie_settings)
: cookie_settings_(cookie_settings) {}
@@ -63,7 +83,8 @@ bool ExtensionSpecialStoragePolicy::HasSessionOnlyOrigins() {
bool ExtensionSpecialStoragePolicy::IsFileHandler(
const std::string& extension_id) {
base::AutoLock locker(lock_);
- return file_handler_extensions_.ContainsExtension(extension_id);
+ return web_intent_extensions_.ContainsExtension(extension_id) ||
+ file_handler_extensions_.ContainsExtension(extension_id);
}
bool ExtensionSpecialStoragePolicy::NeedsProtection(
@@ -80,11 +101,14 @@ const ExtensionSet* ExtensionSpecialStoragePolicy::ExtensionsProtectingOrigin(
void ExtensionSpecialStoragePolicy::GrantRightsForExtension(
const extensions::Extension* extension) {
DCHECK(extension);
+ const bool supports_intent_view = ExtensionSupportsIntentAction(
+ extension, web_intents::kActionView);
if (!NeedsProtection(extension) &&
!extension->HasAPIPermission(
APIPermission::kUnlimitedStorage) &&
!extension->HasAPIPermission(
- APIPermission::kFileBrowserHandler)) {
+ APIPermission::kFileBrowserHandler) &&
+ !supports_intent_view) {
return;
}
{
@@ -97,9 +121,10 @@ void ExtensionSpecialStoragePolicy::GrantRightsForExtension(
if (extension->HasAPIPermission(APIPermission::kUnlimitedStorage))
unlimited_extensions_.Add(extension);
if (extension->HasAPIPermission(
- APIPermission::kFileBrowserHandler)) {
+ APIPermission::kFileBrowserHandler))
file_handler_extensions_.Add(extension);
- }
+ if (supports_intent_view)
+ web_intent_extensions_.Add(extension);
}
NotifyChanged();
}
@@ -107,11 +132,14 @@ void ExtensionSpecialStoragePolicy::GrantRightsForExtension(
void ExtensionSpecialStoragePolicy::RevokeRightsForExtension(
const extensions::Extension* extension) {
DCHECK(extension);
+ const bool supports_intent_view = ExtensionSupportsIntentAction(
+ extension, web_intents::kActionView);
if (!NeedsProtection(extension) &&
!extension->HasAPIPermission(
APIPermission::kUnlimitedStorage) &&
!extension->HasAPIPermission(
- APIPermission::kFileBrowserHandler)) {
+ APIPermission::kFileBrowserHandler) &&
+ !supports_intent_view) {
return;
}
{
@@ -124,6 +152,8 @@ void ExtensionSpecialStoragePolicy::RevokeRightsForExtension(
unlimited_extensions_.Remove(extension);
if (extension->HasAPIPermission(APIPermission::kFileBrowserHandler))
file_handler_extensions_.Remove(extension);
+ if (supports_intent_view)
+ web_intent_extensions_.Remove(extension);
}
NotifyChanged();
}
@@ -135,6 +165,7 @@ void ExtensionSpecialStoragePolicy::RevokeRightsForAllExtensions() {
installed_apps_.Clear();
unlimited_extensions_.Clear();
file_handler_extensions_.Clear();
+ web_intent_extensions_.Clear();
}
NotifyChanged();
}
diff --git a/chrome/browser/extensions/extension_special_storage_policy.h b/chrome/browser/extensions/extension_special_storage_policy.h
index 54f0119..7a7a2c1 100644
--- a/chrome/browser/extensions/extension_special_storage_policy.h
+++ b/chrome/browser/extensions/extension_special_storage_policy.h
@@ -79,6 +79,7 @@ class ExtensionSpecialStoragePolicy : public quota::SpecialStoragePolicy {
SpecialCollection installed_apps_;
SpecialCollection unlimited_extensions_;
SpecialCollection file_handler_extensions_;
+ SpecialCollection web_intent_extensions_;
scoped_refptr<CookieSettings> cookie_settings_;
};
diff --git a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
index 0d5ff45..ed8f2d4 100644
--- a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
+++ b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
@@ -122,6 +122,39 @@ class ExtensionSpecialStoragePolicyTest : public testing::Test {
return handler_app;
}
+ scoped_refptr<Extension> CreateWebIntentViewApp() {
+#if defined(OS_WIN)
+ FilePath path(FILE_PATH_LITERAL("c:\\bar"));
+#elif defined(OS_POSIX)
+ FilePath path(FILE_PATH_LITERAL("/bar"));
+#endif
+ DictionaryValue manifest;
+ manifest.SetString(keys::kName, "WebIntent");
+ manifest.SetString(keys::kVersion, "1");
+ manifest.SetString(keys::kLaunchWebURL, "http://explicit/unlimited/start");
+
+ ListValue* view_intent_types = new ListValue;
+ view_intent_types->Append(Value::CreateStringValue("text/plain"));
+
+ DictionaryValue* view_intent = new DictionaryValue;
+ view_intent->SetString(keys::kIntentTitle, "Test Intent");
+ view_intent->Set(keys::kIntentType, view_intent_types);
+
+ ListValue* view_intent_list = new ListValue;
+ view_intent_list->Append(view_intent);
+
+ DictionaryValue* intents = new DictionaryValue;
+ intents->SetWithoutPathExpansion("http://webintents.org/view",
+ view_intent_list);
+ manifest.Set(keys::kIntents, intents);
+
+ std::string error;
+ scoped_refptr<Extension> intent_app = Extension::Create(
+ path, Extension::INVALID, manifest, Extension::NO_FLAGS, &error);
+ EXPECT_TRUE(intent_app.get()) << error;
+ return intent_app;
+ }
+
// Verifies that the set of extensions protecting |url| is *exactly* equal to
// |expected_extensions|. Pass in an empty set to verify that an origin is not
// protected.
@@ -243,6 +276,16 @@ TEST_F(ExtensionSpecialStoragePolicyTest, OverlappingApps) {
ExpectProtectedBy(empty_set, GURL("https://bar.wildcards/"));
}
+TEST_F(ExtensionSpecialStoragePolicyTest, WebIntentViewApp) {
+ scoped_refptr<Extension> intent_app(CreateWebIntentViewApp());
+
+ policy_->GrantRightsForExtension(intent_app);
+ EXPECT_TRUE(policy_->IsFileHandler(intent_app->id()));
+
+ policy_->RevokeRightsForExtension(intent_app);
+ EXPECT_FALSE(policy_->IsFileHandler(intent_app->id()));
+}
+
TEST_F(ExtensionSpecialStoragePolicyTest, HasSessionOnlyOrigins) {
MessageLoop message_loop;
content::TestBrowserThread ui_thread(BrowserThread::UI, &message_loop);
diff --git a/chrome/browser/resources/file_manager/js/file_tasks.js b/chrome/browser/resources/file_manager/js/file_tasks.js
index cc6fe91..baefa29 100644
--- a/chrome/browser/resources/file_manager/js/file_tasks.js
+++ b/chrome/browser/resources/file_manager/js/file_tasks.js
@@ -86,51 +86,55 @@ FileTasks.prototype.processTasks_ = function(tasks) {
// Tweak images, titles of internal tasks.
var task_parts = task.taskId.split('|');
- if (task_parts[0] == id) {
- if (task_parts[1] == 'play') {
+ if (task_parts[0] == id && task_parts[1] == 'file') {
+ if (task_parts[2] == 'play') {
// TODO(serya): This hack needed until task.iconUrl is working
// (see GetFileTasksFileBrowserFunction::RunImpl).
task.iconType = 'audio';
task.title = loadTimeData.getString('ACTION_LISTEN');
- } else if (task_parts[1] == 'mount-archive') {
+ } else if (task_parts[2] == 'mount-archive') {
task.iconType = 'archive';
task.title = loadTimeData.getString('MOUNT_ARCHIVE');
- } else if (task_parts[1] == 'gallery') {
+ } else if (task_parts[2] == 'gallery') {
task.iconType = 'image';
task.title = loadTimeData.getString('ACTION_OPEN');
- } else if (task_parts[1] == 'watch') {
+ } else if (task_parts[2] == 'watch') {
task.iconType = 'video';
task.title = loadTimeData.getString('ACTION_WATCH');
- } else if (task_parts[1] == 'open-hosted-generic') {
+ } else if (task_parts[2] == 'open-hosted-generic') {
if (this.urls_.length > 1)
task.iconType = 'generic';
else // Use specific icon.
task.iconType = FileType.getIcon(this.urls_[0]);
task.title = loadTimeData.getString('ACTION_OPEN');
- } else if (task_parts[1] == 'open-hosted-gdoc') {
+ } else if (task_parts[2] == 'open-hosted-gdoc') {
task.iconType = 'gdoc';
task.title = loadTimeData.getString('ACTION_OPEN_GDOC');
- } else if (task_parts[1] == 'open-hosted-gsheet') {
+ } else if (task_parts[2] == 'open-hosted-gsheet') {
task.iconType = 'gsheet';
task.title = loadTimeData.getString('ACTION_OPEN_GSHEET');
- } else if (task_parts[1] == 'open-hosted-gslides') {
+ } else if (task_parts[2] == 'open-hosted-gslides') {
task.iconType = 'gslides';
task.title = loadTimeData.getString('ACTION_OPEN_GSLIDES');
- } else if (task_parts[1] == 'view-pdf') {
+ } else if (task_parts[2] == 'view-pdf') {
// Do not render this task if disabled.
if (!loadTimeData.getBoolean('PDF_VIEW_ENABLED'))
continue;
task.iconType = 'pdf';
task.title = loadTimeData.getString('ACTION_VIEW');
- } else if (task_parts[1] == 'view-in-browser') {
+ } else if (task_parts[2] == 'view-in-browser') {
task.iconType = 'generic';
task.title = loadTimeData.getString('ACTION_VIEW');
- } else if (task_parts[1] == 'install-crx') {
+ } else if (task_parts[2] == 'install-crx') {
task.iconType = 'generic';
task.title = loadTimeData.getString('INSTALL_CRX');
}
}
+ if (!task.iconType && task_parts[1] == 'web-intent') {
+ task.iconType = 'generic';
+ }
+
this.tasks_.push(task);
if (this.defaultTask_ == null && task.isDefault) {
this.defaultTask_ = task;
@@ -190,11 +194,11 @@ FileTasks.prototype.execute_ = function(taskId, opt_urls) {
chrome.fileBrowserPrivate.executeTask(taskId, urls);
var task_parts = taskId.split('|');
- if (task_parts[0] == util.getExtensionId()) {
+ if (task_parts[0] == util.getExtensionId() && task_parts[1] == 'file') {
// For internal tasks we do not listen to the event to avoid
// handling the same task instance from multiple tabs.
// So, we manually execute the task.
- this.executeInternalTask_(task_parts[1], urls);
+ this.executeInternalTask_(task_parts[2], urls);
}
}.bind(this));
};
diff --git a/chrome/test/data/extensions/api_test/filebrowser_component/intent.html b/chrome/test/data/extensions/api_test/filebrowser_component/intent.html
new file mode 100644
index 0000000..4303faa
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/filebrowser_component/intent.html
@@ -0,0 +1,10 @@
+<!--
+ * Copyright (c) 2012 The Chromium Authors. All rights reserved. Use of this
+ * source code is governed by a BSD-style license that can be found in the
+ * LICENSE file.
+-->
+<script src="intent.js"></script>
+<html>
+<head><title>file browser component test</title></head>
+<body><h2>chrome.fileBrowserPrivate.* tests</h2></body>
+</html>
diff --git a/chrome/test/data/extensions/api_test/filebrowser_component/intent.js b/chrome/test/data/extensions/api_test/filebrowser_component/intent.js
new file mode 100644
index 0000000..810c02d
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/filebrowser_component/intent.js
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function testForUrl(fileUrl) {
+ chrome.fileBrowserPrivate.getFileTasks([fileUrl], [], function(tasks) {
+ if (!tasks || !tasks.length) {
+ chrome.test.fail('No tasks registered');
+ return;
+ }
+ console.log('Tasks: ' + tasks.length);
+ chrome.fileBrowserPrivate.executeTask(tasks[0].taskId, [fileUrl]);
+ });
+};
+
+chrome.test.runTests([function() {
+ var hash = window.location.hash.toString();
+
+ if (!hash.length) {
+ chrome.test.fail('No fileUrl given to test');
+ return;
+ }
+ var fileUrl = hash.substring(1);
+
+ // The local filesystem is not explicitly used, but this test still needs to
+ // request it; it configures local access permissions.
+ chrome.fileBrowserPrivate.requestLocalFileSystem(chrome.test.callbackPass(
+ function(fs) {
+ testForUrl(fileUrl);
+ }));
+}]);
diff --git a/chrome/test/data/extensions/api_test/webintent_handler/background.js b/chrome/test/data/extensions/api_test/webintent_handler/background.js
new file mode 100644
index 0000000..6d661af
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/webintent_handler/background.js
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/*
+This extension is a platform app that provides a Web Intent handler; it accepts
+incoming requests and invokes chrome.test.succeed() immediately.
+*/
+
+function launchedListener(args) {
+ if (!(args && args['intent'])) {
+ chrome.test.fail('Expected web intent on args: ' + args);
+ return;
+ }
+ var intent = args['intent'];
+ chrome.test.assertEq('http://webintents.org/view', intent['action']);
+ chrome.test.succeed();
+
+ // Note that we're not using chrome.extension.sendRequest here to call back
+ // to the source app - the call is not available in v2 packaged apps. The
+ // most we can do for now is succeed or fail the test (to be caught by a
+ // ResultCatcher in external_filesystem_apitest.cc).
+}
+
+chrome.app.runtime.onLaunched.addListener(launchedListener);
diff --git a/chrome/test/data/extensions/api_test/webintent_handler/manifest.json b/chrome/test/data/extensions/api_test/webintent_handler/manifest.json
new file mode 100644
index 0000000..5807ba3
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/webintent_handler/manifest.json
@@ -0,0 +1,23 @@
+{
+ "key": "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQChptAQ0n4R56N03nWQ1ogR7DVRBjGo80Vw6G9KLjzZv44D8rq5Q5IkeQrtKgWyZfXevlsCe3LaLo18rcz8iZx6lK2xhLdUR+ORjsjuBfdEL5a5cWeRTSxf75AcqndQsmpwMBdrMTCZ8jQNusUI+XlrihLNNJuI5TM4vNINI5bYFQIBIw==",
+ "name": "ChromeOS Web Intent handler extension",
+ "version": "0.1",
+ "manifest_version": 2,
+ "description": "Tests of chrome.fileSystem.* methods for handling Web Intents",
+ "app": {
+ "background": {
+ "scripts": ["background.js"]
+ }
+ },
+ "intents": {
+ "http://webintents.org/view": [{
+ "title": "View xul action",
+ "type": ["application/vnd.mozilla.xul+xml"]
+ }]
+ },
+ "permissions": [
+ "experimental",
+ "fileSystem",
+ "unlimitedStorage"
+ ]
+}