summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorbenwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-26 07:09:36 +0000
committerbenwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-26 07:09:36 +0000
commit12e54045b113f6aca10188b012b1ea529cec6bf2 (patch)
treefe3df5477fdf7c7dd0fe6a5f83c8a87b3f5d155b /chrome
parent7dc1be3f8b949012bb88a49faf0f81f0be363f06 (diff)
downloadchromium_src-12e54045b113f6aca10188b012b1ea529cec6bf2.zip
chromium_src-12e54045b113f6aca10188b012b1ea529cec6bf2.tar.gz
chromium_src-12e54045b113f6aca10188b012b1ea529cec6bf2.tar.bz2
Pass command line arguments onto platform apps which provide the right intent.
Any command line arguments which are file names are passed through in launchData.intent BUG=None TEST=New tests added Review URL: https://chromiumcodereview.appspot.com/10332071 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@139195 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/autocomplete/extension_app_provider.cc2
-rw-r--r--chrome/browser/automation/testing_automation_provider.cc2
-rw-r--r--chrome/browser/background/background_mode_manager.cc2
-rw-r--r--chrome/browser/chromeos/extensions/file_manager_util.cc4
-rw-r--r--chrome/browser/extensions/api/app/app_api.cc25
-rw-r--r--chrome/browser/extensions/api/app/app_api.h26
-rw-r--r--chrome/browser/extensions/app_notification_browsertest.cc3
-rw-r--r--chrome/browser/extensions/extension_apitest.cc4
-rw-r--r--chrome/browser/extensions/extension_management_api.cc2
-rw-r--r--chrome/browser/extensions/platform_app_browsertest.cc90
-rw-r--r--chrome/browser/extensions/platform_app_launcher.cc199
-rw-r--r--chrome/browser/extensions/platform_app_launcher.h25
-rw-r--r--chrome/browser/ui/browser.cc1
-rw-r--r--chrome/browser/ui/browser_browsertest.cc3
-rw-r--r--chrome/browser/ui/extensions/application_launch.cc8
-rw-r--r--chrome/browser/ui/extensions/application_launch.h10
-rw-r--r--chrome/browser/ui/panels/panel_app_browsertest.cc3
-rw-r--r--chrome/browser/ui/startup/startup_browser_creator_impl.cc3
-rw-r--r--chrome/browser/ui/views/ash/extension_utils.cc6
-rw-r--r--chrome/browser/ui/webui/ntp/app_launcher_handler.cc7
-rw-r--r--chrome/chrome_browser_extensions.gypi2
-rw-r--r--chrome/chrome_renderer.gypi2
-rw-r--r--chrome/common/extensions/api/experimental_app.json42
-rw-r--r--chrome/common/extensions/extension.cc6
-rw-r--r--chrome/renderer/extensions/experimental.app_custom_bindings.cc57
-rw-r--r--chrome/renderer/extensions/experimental.app_custom_bindings.h25
-rw-r--r--chrome/renderer/extensions/extension_dispatcher.cc6
-rw-r--r--chrome/renderer/renderer_resources.grd1
-rw-r--r--chrome/renderer/resources/extensions/experimental.app_custom_bindings.js35
-rw-r--r--chrome/test/data/extensions/platform_apps/launch_file/manifest.json18
-rw-r--r--chrome/test/data/extensions/platform_apps/launch_file/test.js35
-rw-r--r--chrome/test/data/extensions/platform_apps/launch_files/test.txt2
-rw-r--r--chrome/test/data/extensions/platform_apps/launch_files/test.unknownextension2
-rw-r--r--chrome/test/data/extensions/platform_apps/launch_invalid/manifest.json18
-rw-r--r--chrome/test/data/extensions/platform_apps/launch_invalid/test.js15
-rw-r--r--chrome/test/data/extensions/platform_apps/launch_no_intent/manifest.json10
-rw-r--r--chrome/test/data/extensions/platform_apps/launch_no_intent/test.js15
-rw-r--r--chrome/test/data/extensions/platform_apps/launch_nothing/manifest.json18
-rw-r--r--chrome/test/data/extensions/platform_apps/launch_nothing/test.js15
-rw-r--r--chrome/test/data/extensions/platform_apps/launch_wrong_intent/manifest.json18
-rw-r--r--chrome/test/data/extensions/platform_apps/launch_wrong_intent/test.js15
-rw-r--r--chrome/test/data/extensions/platform_apps/launch_wrong_type/manifest.json18
-rw-r--r--chrome/test/data/extensions/platform_apps/launch_wrong_type/test.js15
43 files changed, 785 insertions, 30 deletions
diff --git a/chrome/browser/autocomplete/extension_app_provider.cc b/chrome/browser/autocomplete/extension_app_provider.cc
index e57a429..b538469 100644
--- a/chrome/browser/autocomplete/extension_app_provider.cc
+++ b/chrome/browser/autocomplete/extension_app_provider.cc
@@ -51,7 +51,7 @@ void ExtensionAppProvider::LaunchAppFromOmnibox(
extension, ExtensionPrefs::LAUNCH_REGULAR);
application_launch::OpenApplication(profile, extension, launch_container,
- GURL(), disposition);
+ GURL(), disposition, NULL);
}
void ExtensionAppProvider::AddExtensionAppForTesting(
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index eea9313..037af48 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -5651,7 +5651,7 @@ void TestingAutomationProvider::LaunchApp(
new AppLaunchObserver(&old_contents->GetController(), this, reply_message,
launch_container);
application_launch::OpenApplication(profile(), extension, launch_container,
- GURL(), CURRENT_TAB);
+ GURL(), CURRENT_TAB, NULL);
}
// Sample JSON input: { "command": "SetAppLaunchType",
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc
index 2aa6f00..76d079d 100644
--- a/chrome/browser/background/background_mode_manager.cc
+++ b/chrome/browser/background/background_mode_manager.cc
@@ -267,7 +267,7 @@ void BackgroundModeManager::LaunchBackgroundApplication(
service->extension_prefs()->GetLaunchContainer(
extension, ExtensionPrefs::LAUNCH_REGULAR);
application_launch::OpenApplication(profile, extension, launch_container,
- GURL(), NEW_FOREGROUND_TAB);
+ GURL(), NEW_FOREGROUND_TAB, NULL);
}
bool BackgroundModeManager::IsBackgroundModeActiveForTest() {
diff --git a/chrome/browser/chromeos/extensions/file_manager_util.cc b/chrome/browser/chromeos/extensions/file_manager_util.cc
index 5d2bf9d..6e8ef44 100644
--- a/chrome/browser/chromeos/extensions/file_manager_util.cc
+++ b/chrome/browser/chromeos/extensions/file_manager_util.cc
@@ -471,8 +471,8 @@ void OpenFileBrowser(const FilePath& path,
GetLaunchContainer(extension, ExtensionPrefs::LAUNCH_DEFAULT);
content::RecordAction(UserMetricsAction("ShowFileBrowserFullTab"));
- application_launch::OpenApplication(
- profile, extension, launch_container, GURL(url), NEW_FOREGROUND_TAB);
+ application_launch::OpenApplication(profile, extension, launch_container,
+ GURL(url), NEW_FOREGROUND_TAB, NULL);
}
void ViewRemovableDrive(const FilePath& path) {
diff --git a/chrome/browser/extensions/api/app/app_api.cc b/chrome/browser/extensions/api/app/app_api.cc
index 14c9ece..3b74ab0 100644
--- a/chrome/browser/extensions/api/app/app_api.cc
+++ b/chrome/browser/extensions/api/app/app_api.cc
@@ -4,8 +4,10 @@
#include "chrome/browser/extensions/api/app/app_api.h"
+#include "base/json/json_writer.h"
#include "base/values.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/app_notification_manager.h"
#include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/extensions/extension_service.h"
@@ -121,4 +123,27 @@ void AppEventRouter::DispatchOnLaunchedEvent(
extension->id(), kOnLaunchedEvent, "[]", NULL, GURL());
}
+// static.
+void AppEventRouter::DispatchOnLaunchedEventWithFileEntry(
+ Profile* profile, const Extension* extension, const string16& action,
+ const std::string& file_system_id, const FilePath& base_name) {
+ ListValue args;
+ DictionaryValue* launch_data = new DictionaryValue();
+ DictionaryValue* intent = new DictionaryValue();
+ intent->SetString("action", UTF16ToUTF8(action));
+ launch_data->Set("intent", intent);
+ intent->SetString("type", "chrome-extension://fileentry");
+ args.Append(launch_data);
+ args.Append(Value::CreateStringValue(file_system_id));
+#if defined(OS_WIN)
+ args.Append(Value::CreateStringValue(UTF16ToUTF8(base_name.value())));
+#else
+ args.Append(Value::CreateStringValue(base_name.value()));
+#endif
+ std::string json_args;
+ base::JSONWriter::Write(&args, &json_args);
+ profile->GetExtensionEventRouter()->DispatchEventToExtension(
+ extension->id(), kOnLaunchedEvent, json_args, NULL, GURL());
+}
+
} // namespace extensions
diff --git a/chrome/browser/extensions/api/app/app_api.h b/chrome/browser/extensions/api/app/app_api.h
index 306c158..d5690ed 100644
--- a/chrome/browser/extensions/api/app/app_api.h
+++ b/chrome/browser/extensions/api/app/app_api.h
@@ -9,6 +9,7 @@
#include "chrome/browser/extensions/extension_function.h"
class Profile;
+class GURL;
namespace extensions {
@@ -34,9 +35,32 @@ class AppClearAllNotificationsFunction : public SyncExtensionFunction {
class AppEventRouter {
public:
- // Dispatches the onLaunched event to the given app.
+ // Dispatches the onLaunched event to the given app, providing no launch
+ // data.
static void DispatchOnLaunchedEvent(Profile* profile,
const Extension* extension);
+
+ // Dispatches the onLaunched event to the given app, providing launch data of
+ // the form:
+ // {
+ // "intent" : {
+ // "action" : |action|,
+ // "type" : "chrome-extension://fileentry",
+ // "data" : a FileEntry,
+ // "postResults" : a null function,
+ // "postFailure" : a null function
+ // }
+ // }
+
+ // launchData.intent.data and launchData.intent.postResults are created in a
+ // custom dispatch event in javascript. The FileEntry is created from
+ // |file_system_id| and |base_name|.
+ static void DispatchOnLaunchedEventWithFileEntry(
+ Profile* profile,
+ const Extension* extension,
+ const string16& action,
+ const std::string& file_system_id,
+ const FilePath& base_name);
};
} // namespace extensions
diff --git a/chrome/browser/extensions/app_notification_browsertest.cc b/chrome/browser/extensions/app_notification_browsertest.cc
index 639b155..fea0ef3 100644
--- a/chrome/browser/extensions/app_notification_browsertest.cc
+++ b/chrome/browser/extensions/app_notification_browsertest.cc
@@ -63,7 +63,8 @@ IN_PROC_BROWSER_TEST_F(AppNotificationTest, SaveClientId) {
app,
extension_misc::LAUNCH_TAB,
GURL(),
- NEW_FOREGROUND_TAB);
+ NEW_FOREGROUND_TAB,
+ NULL);
if (!interceptor.was_called())
ui_test_utils::RunMessageLoop();
EXPECT_TRUE(interceptor.was_called());
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc
index e0806b8..1042e32 100644
--- a/chrome/browser/extensions/extension_apitest.cc
+++ b/chrome/browser/extensions/extension_apitest.cc
@@ -210,12 +210,14 @@ bool ExtensionApiTest::RunExtensionTestImpl(const char* extension_name,
ui_test_utils::NavigateToURL(browser(), url);
} else if (launch_platform_app) {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
application_launch::OpenApplication(
browser()->profile(),
extension,
extension_misc::LAUNCH_NONE,
GURL(),
- NEW_WINDOW);
+ NEW_WINDOW,
+ command_line);
}
if (!catcher.GetNextResult()) {
diff --git a/chrome/browser/extensions/extension_management_api.cc b/chrome/browser/extensions/extension_management_api.cc
index f99ec40..8f3da298 100644
--- a/chrome/browser/extensions/extension_management_api.cc
+++ b/chrome/browser/extensions/extension_management_api.cc
@@ -341,7 +341,7 @@ bool LaunchAppFunction::RunImpl() {
service()->extension_prefs()->GetLaunchContainer(
extension, ExtensionPrefs::LAUNCH_DEFAULT);
application_launch::OpenApplication(profile(), extension, launch_container,
- GURL(), NEW_FOREGROUND_TAB);
+ GURL(), NEW_FOREGROUND_TAB, NULL);
#if !defined(OS_ANDROID)
AppLauncherHandler::RecordAppLaunchType(
extension_misc::APP_LAUNCH_EXTENSION_API);
diff --git a/chrome/browser/extensions/platform_app_browsertest.cc b/chrome/browser/extensions/platform_app_browsertest.cc
index 325aff9..f21edd9 100644
--- a/chrome/browser/extensions/platform_app_browsertest.cc
+++ b/chrome/browser/extensions/platform_app_browsertest.cc
@@ -4,7 +4,7 @@
#include "base/command_line.h"
#include "base/stringprintf.h"
-#include "base/utf_string_conversions.h"
+#include "base/string_util.h"
#include "base/values.h"
#include "chrome/browser/automation/automation_util.h"
#include "chrome/browser/extensions/extension_apitest.h"
@@ -77,7 +77,8 @@ class PlatformAppBrowserTest : public ExtensionApiTest {
extension,
extension_misc::LAUNCH_NONE,
GURL(),
- NEW_WINDOW);
+ NEW_WINDOW,
+ NULL);
app_loaded_observer.Wait();
@@ -128,6 +129,26 @@ class PlatformAppBrowserTest : public ExtensionApiTest {
return ShellWindowRegistry::Get(browser()->profile())->
shell_windows().size();
}
+
+ // The command line already has an argument on it - about:blank, which
+ // is set by InProcessBrowserTest::PrepareTestCommandLine. For platform app
+ // launch tests we need to clear this.
+ void ClearCommandLineArgs() {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ CommandLine::StringVector args = command_line->GetArgs();
+ CommandLine::StringVector argv = command_line->argv();
+ for (size_t i = 0; i < args.size(); i++)
+ argv.pop_back();
+ command_line->InitFromArgv(argv);
+ }
+
+ void SetCommandLineArg(const std::string& test_file) {
+ ClearCommandLineArgs();
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ FilePath test_doc(test_data_dir_.AppendASCII(test_file));
+ test_doc = test_doc.NormalizePathSeparators();
+ command_line->AppendArgPath(test_doc);
+ }
};
// Tests that platform apps received the "launch" event when launched.
@@ -272,3 +293,68 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ExtensionWindowingApis) {
ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(platform_app));
ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(platform_app2));
}
+
+// TODO(benwells): fix these tests for ChromeOS.
+#if !defined(OS_CHROMEOS)
+// Tests that command line parameters get passed through to platform apps
+// via launchData correctly when launching with a file.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFile) {
+ SetCommandLineArg( "platform_apps/launch_files/test.txt");
+ ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file"))
+ << message_;
+}
+
+// Tests that no launch data is sent through if the platform app provides
+// an intent with the wrong action.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongIntent) {
+ SetCommandLineArg("platform_apps/launch_files/test.txt");
+ ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_intent"))
+ << message_;
+}
+
+// Tests that no launch data is sent through if the file is of the wrong MIME
+// type.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongType) {
+ SetCommandLineArg("platform_apps/launch_files/test.txt");
+ ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_type"))
+ << message_;
+}
+
+// Tests that no launch data is sent through if the platform app does not
+// provide an intent.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNoIntent) {
+ SetCommandLineArg("platform_apps/launch_files/test.txt");
+ ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_no_intent"))
+ << message_;
+}
+
+// Tests that no launch data is sent through if the file MIME type cannot
+// be read.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoType) {
+ SetCommandLineArg("platform_apps/launch_files/test.unknownextension");
+ ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
+ << message_;
+}
+
+// Tests that no launch data is sent through if the file does not exist.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoFile) {
+ SetCommandLineArg("platform_apps/launch_files/doesnotexist.txt");
+ ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
+ << message_;
+}
+
+// Tests that no launch data is sent through if the argument is a directory.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithDirectory) {
+ SetCommandLineArg("platform_apps/launch_files");
+ ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
+ << message_;
+}
+
+// Tests that no launch data is sent through if there are no arguments passed
+// on the command line
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNothing) {
+ ClearCommandLineArgs();
+ ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_nothing"))
+ << message_;
+}
+#endif // defined(OS_CHROMEOS)
diff --git a/chrome/browser/extensions/platform_app_launcher.cc b/chrome/browser/extensions/platform_app_launcher.cc
new file mode 100644
index 0000000..47ea21a
--- /dev/null
+++ b/chrome/browser/extensions/platform_app_launcher.cc
@@ -0,0 +1,199 @@
+// 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.
+
+#include "chrome/browser/extensions/platform_app_launcher.h"
+
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/extensions/api/app/app_api.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/lazy_background_task_queue.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_messages.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/child_process_security_policy.h"
+#include "content/public/browser/render_process_host.h"
+#include "net/base/mime_util.h"
+#include "net/base/net_util.h"
+#include "webkit/fileapi/isolated_context.h"
+#include "webkit/glue/web_intent_service_data.h"
+
+using content::BrowserThread;
+using extensions::Extension;
+
+namespace {
+
+const char kViewIntent[] = "http://webintents.org/view";
+
+class PlatformAppLauncher
+ : public base::RefCountedThreadSafe<PlatformAppLauncher> {
+ public:
+ PlatformAppLauncher(Profile* profile,
+ const Extension* extension,
+ const CommandLine* command_line)
+ : profile_(profile),
+ extension_(extension),
+ command_line_(command_line) {}
+
+ void Launch() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!command_line_ || !command_line_->GetArgs().size()) {
+ LaunchWithNoLaunchData();
+ return;
+ }
+
+ FilePath file_path(command_line_->GetArgs()[0]);
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
+ &PlatformAppLauncher::GetMimeTypeAndLaunch, this, file_path));
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<PlatformAppLauncher>;
+
+ virtual ~PlatformAppLauncher() {}
+
+ void LaunchWithNoLaunchData() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ extensions::AppEventRouter::DispatchOnLaunchedEvent(profile_, extension_);
+ }
+
+ void GetMimeTypeAndLaunch(const FilePath& file_path) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ // If the file doesn't exist, or is a directory, launch with no launch data.
+ if (!file_util::PathExists(file_path) ||
+ file_util::DirectoryExists(file_path)) {
+ LOG(WARNING) << "No file exists with path " << file_path.value();
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
+ &PlatformAppLauncher::LaunchWithNoLaunchData, this));
+ return;
+ }
+
+ std::string mime_type;
+ // If we cannot obtain the MIME type, launch with no launch data.
+ if (!net::GetMimeTypeFromFile(file_path, &mime_type)) {
+ LOG(WARNING) << "Could not obtain MIME type for " << file_path.value();
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
+ &PlatformAppLauncher::LaunchWithNoLaunchData, this));
+ return;
+ }
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
+ &PlatformAppLauncher::LaunchWithMimeTypeAndPath, this, file_path,
+ mime_type));
+ }
+
+ void LaunchWithMimeTypeAndPath(const FilePath& file_path,
+ const std::string& mime_type) {
+ // Find the intent service from the platform app for the file being opened.
+ webkit_glue::WebIntentServiceData service;
+ bool found_service = false;
+
+ std::vector<webkit_glue::WebIntentServiceData> services =
+ extension_->intents_services();
+ for (size_t i = 0; i < services.size(); i++) {
+ std::string service_type_ascii = UTF16ToASCII(services[i].type);
+ if (services[i].action == ASCIIToUTF16(kViewIntent) &&
+ net::MatchesMimeType(service_type_ascii, mime_type)) {
+ service = services[i];
+ found_service = true;
+ break;
+ }
+ }
+
+ // If this app doesn't have an intent that supports the file, launch with
+ // no launch data.
+ if (!found_service) {
+ LOG(WARNING) << "Extension does not provide a valid intent for "
+ << file_path.value();
+ LaunchWithNoLaunchData();
+ return;
+ }
+
+ // We need to grant access to the file for the process associated with the
+ // extension. To do this we need the ExtensionHost. This might not be
+ // available, or it might be in the process of being unloaded, in which case
+ // we can use the lazy background task queue to load the extension and then
+ // call back to us.
+ extensions::LazyBackgroundTaskQueue* queue =
+ ExtensionSystem::Get(profile_)->lazy_background_task_queue();
+ if (queue->ShouldEnqueueTask(profile_, extension_)) {
+ queue->AddPendingTask(profile_, extension_->id(),
+ base::Bind(&PlatformAppLauncher::GrantAccessToFileAndLaunch,
+ this, file_path, mime_type));
+ return;
+ }
+
+ ExtensionProcessManager* pm =
+ ExtensionSystem::Get(profile_)->process_manager();
+ ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_->id());
+ DCHECK(host);
+ GrantAccessToFileAndLaunch(file_path, mime_type, host);
+ }
+
+ void GrantAccessToFileAndLaunch(const FilePath& file_path,
+ const std::string& mime_type,
+ ExtensionHost* host) {
+ // If there was an error loading the app page, |host| will be NULL.
+ if (!host) {
+ LOG(ERROR) << "Could not load app page for " << extension_->id();
+ return;
+ }
+
+ content::ChildProcessSecurityPolicy* policy =
+ content::ChildProcessSecurityPolicy::GetInstance();
+ int renderer_id = host->render_process_host()->GetID();
+
+ // If the renderer already has permission to read these paths, we don't
+ // regrant, as this would overwrite any other permissions which the renderer
+ // may already have.
+ if (!policy->CanReadFile(renderer_id, file_path))
+ policy->GrantReadFile(renderer_id, file_path);
+
+ std::set<FilePath> filesets;
+ filesets.insert(file_path);
+
+ fileapi::IsolatedContext* isolated_context =
+ fileapi::IsolatedContext::GetInstance();
+ DCHECK(isolated_context);
+ std::string filesystem_id = isolated_context->RegisterIsolatedFileSystem(
+ filesets);
+ policy->GrantAccessFileSystem(renderer_id, filesystem_id);
+
+ extensions::AppEventRouter::DispatchOnLaunchedEventWithFileEntry(
+ profile_, extension_, ASCIIToUTF16(kViewIntent), filesystem_id,
+ file_path.BaseName());
+ }
+
+ Profile* profile_;
+ const Extension* extension_;
+ const CommandLine* command_line_;
+
+ DISALLOW_COPY_AND_ASSIGN(PlatformAppLauncher);
+};
+
+} // namespace
+
+namespace extensions {
+
+void LaunchPlatformApp(Profile* profile,
+ const Extension* extension,
+ const CommandLine* command_line) {
+ // launcher will be freed when nothing has a reference to it. The message
+ // queue will retain a reference for any outstanding task, so when the
+ // launcher has finished it will be freed.
+ scoped_refptr<PlatformAppLauncher> launcher =
+ new PlatformAppLauncher(profile, extension, command_line);
+ launcher->Launch();
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/platform_app_launcher.h b/chrome/browser/extensions/platform_app_launcher.h
new file mode 100644
index 0000000..20181cd
--- /dev/null
+++ b/chrome/browser/extensions/platform_app_launcher.h
@@ -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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_LAUNCHER_H_
+#define CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_LAUNCHER_H_
+#pragma once
+
+class CommandLine;
+class Profile;
+
+namespace extensions {
+
+class Extension;
+
+// Launches the platform app |extension|. Creates appropriate launch data for
+// the |command_line| fields present. |extension| and |profile| must not be
+// NULL. A NULL |command_line| means there is no launch data.
+void LaunchPlatformApp(Profile* profile,
+ const Extension* extension,
+ const CommandLine* command_line);
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_LAUNCHER_H_
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index afa8dc8..e6b3163 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -48,7 +48,6 @@
#include "chrome/browser/download/download_shelf.h"
#include "chrome/browser/download/download_started_animation.h"
#include "chrome/browser/download/download_util.h"
-#include "chrome/browser/extensions/api/app/app_api.h"
#include "chrome/browser/extensions/browser_extension_window_controller.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/default_apps_trial.h"
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index bc3c43e..46fc8a8 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -1564,7 +1564,8 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, OpenAppWindowLikeNtp) {
extension_app,
extension_misc::LAUNCH_WINDOW,
GURL(),
- NEW_WINDOW);
+ NEW_WINDOW,
+ NULL);
ASSERT_TRUE(app_window);
// Apps launched in a window from the NTP do not have extension_app set in
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index 05d59f1d..3446c05 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -4,13 +4,14 @@
#include "chrome/browser/ui/extensions/application_launch.h"
+#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
-#include "chrome/browser/extensions/api/app/app_api.h"
#include "chrome/browser/extensions/default_apps_trial.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tab_helper.h"
+#include "chrome/browser/extensions/platform_app_launcher.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/browser/ui/browser.h"
@@ -81,7 +82,8 @@ WebContents* OpenApplication(Profile* profile,
const Extension* extension,
extension_misc::LaunchContainer container,
const GURL& override_url,
- WindowOpenDisposition disposition) {
+ WindowOpenDisposition disposition,
+ const CommandLine* command_line) {
WebContents* tab = NULL;
ExtensionPrefs* prefs = profile->GetExtensionService()->extension_prefs();
prefs->SetActiveBit(extension->id(), true);
@@ -93,7 +95,7 @@ WebContents* OpenApplication(Profile* profile,
#endif
if (extension->is_platform_app()) {
- extensions::AppEventRouter::DispatchOnLaunchedEvent(profile, extension);
+ extensions::LaunchPlatformApp(profile, extension, command_line);
return NULL;
}
diff --git a/chrome/browser/ui/extensions/application_launch.h b/chrome/browser/ui/extensions/application_launch.h
index 7bb3dcc..5b9627a 100644
--- a/chrome/browser/ui/extensions/application_launch.h
+++ b/chrome/browser/ui/extensions/application_launch.h
@@ -10,6 +10,7 @@
#include "webkit/glue/window_open_disposition.h"
class Browser;
+class CommandLine;
class GURL;
class Profile;
@@ -25,12 +26,17 @@ namespace application_launch {
// Open |extension| in |container|, using |disposition| if container type is
// TAB. Returns the WebContents* that was created or NULL. If non-empty,
-// |override_url| is used in place of the app launch url.
+// |override_url| is used in place of the app launch url. Pass relevant
+// information in |command_line| onto platform app as launch data.
+// |command_line| can be NULL, indicating there is no launch data to pass on.
+// TODO(benwells): Put the parameters to this into an ApplicationLaunchParams
+// struct.
content::WebContents* OpenApplication(Profile* profile,
const extensions::Extension* extension,
extension_misc::LaunchContainer container,
const GURL& override_url,
- WindowOpenDisposition disposition);
+ WindowOpenDisposition disposition,
+ const CommandLine* command_line);
#if defined(USE_ASH)
// Opens |url| in a new application panel window for the specified url.
diff --git a/chrome/browser/ui/panels/panel_app_browsertest.cc b/chrome/browser/ui/panels/panel_app_browsertest.cc
index f62d4a3..93b76f5 100644
--- a/chrome/browser/ui/panels/panel_app_browsertest.cc
+++ b/chrome/browser/ui/panels/panel_app_browsertest.cc
@@ -55,7 +55,8 @@ class PanelAppBrowserTest : public ExtensionBrowserTest {
// Overriding manifest to open in a panel.
extension_misc::LAUNCH_PANEL,
GURL(),
- NEW_WINDOW);
+ NEW_WINDOW,
+ NULL);
// Now we have a new browser instance.
EXPECT_EQ(browser_count + 1, BrowserList::size());
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 34e7e3a..5d94e6b 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -427,7 +427,8 @@ bool StartupBrowserCreatorImpl::OpenApplicationWindow(Profile* profile) {
RecordCmdLineAppHistogram();
WebContents* tab_in_app_window = application_launch::OpenApplication(
- profile, extension, launch_container, GURL(), NEW_WINDOW);
+ profile, extension, launch_container, GURL(), NEW_WINDOW,
+ &command_line_);
// Platform apps fire off a launch event which may or may not open a window.
return (tab_in_app_window != NULL || extension->is_platform_app());
}
diff --git a/chrome/browser/ui/views/ash/extension_utils.cc b/chrome/browser/ui/views/ash/extension_utils.cc
index 586d11e..b0f6c69 100644
--- a/chrome/browser/ui/views/ash/extension_utils.cc
+++ b/chrome/browser/ui/views/ash/extension_utils.cc
@@ -32,12 +32,12 @@ void OpenExtension(Profile* profile,
if (disposition == NEW_FOREGROUND_TAB || disposition == NEW_BACKGROUND_TAB) {
// Opens in a tab.
application_launch::OpenApplication(
- profile, extension, extension_misc::LAUNCH_TAB, url, disposition);
+ profile, extension, extension_misc::LAUNCH_TAB, url, disposition, NULL);
} else if (disposition == NEW_WINDOW) {
// Force a new window open.
application_launch::OpenApplication(
profile, extension, extension_misc::LAUNCH_WINDOW, url,
- disposition);
+ disposition, NULL);
} else {
// Look at preference to find the right launch container. If no preference
// is set, launch as a regular tab.
@@ -47,7 +47,7 @@ void OpenExtension(Profile* profile,
application_launch::OpenApplication(
profile, extension, launch_container, GURL(url),
- NEW_FOREGROUND_TAB);
+ NEW_FOREGROUND_TAB, NULL);
}
}
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index 7cf5db8..212b64f 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -545,12 +545,13 @@ void AppLauncherHandler::HandleLaunchApp(const ListValue* args) {
if (disposition == NEW_FOREGROUND_TAB || disposition == NEW_BACKGROUND_TAB) {
// TODO(jamescook): Proper support for background tabs.
application_launch::OpenApplication(
- profile, extension, extension_misc::LAUNCH_TAB, GURL(url), disposition);
+ profile, extension, extension_misc::LAUNCH_TAB, GURL(url), disposition,
+ NULL);
} else if (disposition == NEW_WINDOW) {
// Force a new window open.
application_launch::OpenApplication(
profile, extension, extension_misc::LAUNCH_WINDOW, GURL(url),
- disposition);
+ disposition, NULL);
} else {
// Look at preference to find the right launch container. If no preference
// is set, launch as a regular tab.
@@ -567,7 +568,7 @@ void AppLauncherHandler::HandleLaunchApp(const ListValue* args) {
WebContents* new_contents = application_launch::OpenApplication(
profile, extension, launch_container, GURL(url),
- old_contents ? CURRENT_TAB : NEW_FOREGROUND_TAB);
+ old_contents ? CURRENT_TAB : NEW_FOREGROUND_TAB, NULL);
// This will also destroy the handler, so do not perform any actions after.
if (new_contents != old_contents && browser && browser->tab_count() > 1)
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 6f83d81..cde56c6 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -407,6 +407,8 @@
'browser/extensions/pack_extension_job.h',
'browser/extensions/page_action_controller.cc',
'browser/extensions/page_action_controller.h',
+ 'browser/extensions/platform_app_launcher.cc',
+ 'browser/extensions/platform_app_launcher.h',
'browser/extensions/pending_extension_info.cc',
'browser/extensions/pending_extension_info.h',
'browser/extensions/pending_extension_manager.cc',
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index 6a5b1e1..58a9b7b 100644
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -78,6 +78,8 @@
'renderer/extensions/context_menus_custom_bindings.h',
'renderer/extensions/event_bindings.cc',
'renderer/extensions/event_bindings.h',
+ 'renderer/extensions/experimental.app_custom_bindings.cc',
+ 'renderer/extensions/experimental.app_custom_bindings.h',
'renderer/extensions/experimental.usb_custom_bindings.cc',
'renderer/extensions/experimental.usb_custom_bindings.h',
'renderer/extensions/extension_custom_bindings.cc',
diff --git a/chrome/common/extensions/api/experimental_app.json b/chrome/common/extensions/api/experimental_app.json
index a169fe5..0eeb43a 100644
--- a/chrome/common/extensions/api/experimental_app.json
+++ b/chrome/common/extensions/api/experimental_app.json
@@ -83,7 +83,47 @@
"nodoc": true,
"name": "onLaunched",
"type": "function",
- "description": "Fired when the app is launched."
+ "description": "Fired when the app is launched.",
+ "parameters": [
+ {
+ "type": "object",
+ "name": "launchData",
+ "description": "Optional data for the launch.",
+ "optional": true,
+ "properties": {
+ "intent": {
+ "type": "object",
+ "description": "File being opened in the form of a WebIntents intent object.",
+ "properties": {
+ "action": {
+ "type": "string",
+ "description": "The WebIntent being invoked."
+ },
+ "type": {
+ "type": "string",
+ "description": "The MIME type of the file being opened."
+ },
+ "data": {
+ "type": "object",
+ "isInstanceOf": "FileEntry",
+ "description": "A FileEntry for the file being opened.",
+ "additionalProperties": {
+ "type": "any"
+ }
+ },
+ "postResult": {
+ "type": "function",
+ "description": "Null callback to be compatible with WebIntents."
+ },
+ "postFailure": {
+ "type": "function",
+ "description": "Null callback to be compatible with WebIntents."
+ }
+ }
+ }
+ }
+ }
+ ]
}
]
}
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index bd79d1c..477764f 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -1790,13 +1790,13 @@ bool Extension::LoadWebIntentAction(const std::string& action_name,
if (href.empty()) {
if (is_hosted_app()) {
href = launch_web_url();
- } else if (is_packaged_app() || is_platform_app()) {
+ } else if (is_packaged_app()) {
href = launch_local_path();
}
}
// If we still don't have an href, the manifest is malformed.
- if (href.empty()) {
+ if (href.empty() && !is_platform_app()) {
*error = ExtensionErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidIntentHrefEmpty, action_name);
return false;
@@ -1812,7 +1812,7 @@ bool Extension::LoadWebIntentAction(const std::string& action_name,
return false;
}
service.service_url = service_url;
- } else {
+ } else if (!is_platform_app()) {
// We do not allow absolute intent URLs in non-hosted apps.
if (service_url.is_valid()) {
*error = ExtensionErrorUtils::FormatErrorMessageUTF16(
diff --git a/chrome/renderer/extensions/experimental.app_custom_bindings.cc b/chrome/renderer/extensions/experimental.app_custom_bindings.cc
new file mode 100644
index 0000000..683f883
--- /dev/null
+++ b/chrome/renderer/extensions/experimental.app_custom_bindings.cc
@@ -0,0 +1,57 @@
+// 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.
+
+#include "chrome/renderer/extensions/experimental.app_custom_bindings.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/renderer/extensions/user_script_slave.h"
+#include "grit/renderer_resources.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebFileSystem.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
+#include "webkit/fileapi/file_system_types.h"
+#include "webkit/fileapi/file_system_util.h"
+
+namespace {
+
+static v8::Handle<v8::Value> GetIsolatedFileSystem(
+ const v8::Arguments& args) {
+ DCHECK(args.Length() == 1);
+ DCHECK(args[0]->IsString());
+ std::string file_system_id(*v8::String::Utf8Value(args[0]));
+ WebKit::WebFrame* webframe = WebKit::WebFrame::frameForCurrentContext();
+ DCHECK(webframe);
+
+ GURL context_url = UserScriptSlave::GetDataSourceURLForFrame(webframe);
+ CHECK(context_url.SchemeIs(chrome::kExtensionScheme));
+
+ std::string name(fileapi::GetFileSystemName(context_url.GetOrigin(),
+ fileapi::kFileSystemTypeIsolated));
+ name.append(file_system_id);
+
+ std::string root(fileapi::GetFileSystemRootURI(context_url.GetOrigin(),
+ fileapi::kFileSystemTypeIsolated).spec());
+ root.append(file_system_id);
+ root.append("/");
+
+ return webframe->createFileSystem(
+ WebKit::WebFileSystem::TypeIsolated,
+ WebKit::WebString::fromUTF8(name.c_str()),
+ WebKit::WebString::fromUTF8(root.c_str()));
+}
+
+} // namespace
+
+namespace extensions {
+
+ExperimentalAppCustomBindings::ExperimentalAppCustomBindings()
+ : ChromeV8Extension(NULL) {
+ RouteStaticFunction("GetIsolatedFileSystem", &GetIsolatedFileSystem);
+}
+
+} // namespace extensions
diff --git a/chrome/renderer/extensions/experimental.app_custom_bindings.h b/chrome/renderer/extensions/experimental.app_custom_bindings.h
new file mode 100644
index 0000000..aa11c49a
--- /dev/null
+++ b/chrome/renderer/extensions/experimental.app_custom_bindings.h
@@ -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.
+
+#ifndef CHROME_RENDERER_EXTENSIONS_EXPERIMENTAL_APP_CUSTOM_BINDINGS_H_
+#define CHROME_RENDERER_EXTENSIONS_EXPERIMENTAL_APP_CUSTOM_BINDINGS_H_
+#pragma once
+
+#include "base/compiler_specific.h"
+#include "chrome/renderer/extensions/chrome_v8_extension.h"
+
+namespace extensions {
+
+// Custom bindings for the nativeFileSystem API.
+class ExperimentalAppCustomBindings : public ChromeV8Extension {
+ public:
+ ExperimentalAppCustomBindings();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ExperimentalAppCustomBindings);
+};
+
+} // namespace extensions
+
+#endif // CHROME_RENDERER_EXTENSIONS_EXPERIMENTAL_APP_CUSTOM_BINDINGS_H_
diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc
index 9895b8a..8226de8 100644
--- a/chrome/renderer/extensions/extension_dispatcher.cc
+++ b/chrome/renderer/extensions/extension_dispatcher.cc
@@ -25,6 +25,7 @@
#include "chrome/renderer/extensions/chrome_v8_extension.h"
#include "chrome/renderer/extensions/context_menus_custom_bindings.h"
#include "chrome/renderer/extensions/event_bindings.h"
+#include "chrome/renderer/extensions/experimental.app_custom_bindings.h"
#include "chrome/renderer/extensions/experimental.usb_custom_bindings.h"
#include "chrome/renderer/extensions/extension_custom_bindings.h"
#include "chrome/renderer/extensions/extension_groups.h"
@@ -75,6 +76,7 @@ using extensions::ApiDefinitionsNatives;
using extensions::AppWindowCustomBindings;
using extensions::ContextMenusCustomBindings;
using extensions::Extension;
+using extensions::ExperimentalAppCustomBindings;
using extensions::ExperimentalUsbCustomBindings;
using extensions::ExtensionAPI;
using extensions::ExtensionCustomBindings;
@@ -503,6 +505,8 @@ void ExtensionDispatcher::RegisterNativeHandlers(ModuleSystem* module_system,
new ExtensionCustomBindings(this)));
module_system->RegisterNativeHandler("experimental_mediaGalleries",
scoped_ptr<NativeHandler>(new MediaGalleryCustomBindings()));
+ module_system->RegisterNativeHandler("experimental_app",
+ scoped_ptr<NativeHandler>(new ExperimentalAppCustomBindings()));
module_system->RegisterNativeHandler("experimental_usb",
scoped_ptr<NativeHandler>(new ExperimentalUsbCustomBindings()));
module_system->RegisterNativeHandler("file_browser_handler",
@@ -552,6 +556,8 @@ void ExtensionDispatcher::PopulateSourceMap() {
source_map_.RegisterSource("declarativeWebRequest",
IDR_DECLARATIVE_WEBREQUEST_CUSTOM_BINDINGS_JS);
source_map_.RegisterSource("devtools", IDR_DEVTOOLS_CUSTOM_BINDINGS_JS);
+ source_map_.RegisterSource("experimental.app",
+ IDR_EXPERIMENTAL_APP_CUSTOM_BINDINGS_JS);
source_map_.RegisterSource("experimental.mediaGalleries",
IDR_MEDIA_GALLERY_CUSTOM_BINDINGS_JS);
source_map_.RegisterSource("experimental.offscreen",
diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd
index 5699b6a..1edc9ec 100644
--- a/chrome/renderer/renderer_resources.grd
+++ b/chrome/renderer/renderer_resources.grd
@@ -43,6 +43,7 @@ without changes to the corresponding grd file. fb9 -->
<include name="IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS" file="resources\extensions\context_menus_custom_bindings.js" type="BINDATA" />
<include name="IDR_DECLARATIVE_WEBREQUEST_CUSTOM_BINDINGS_JS" file="resources\extensions\declarative_webrequest_custom_bindings.js" type="BINDATA" />
<include name="IDR_DEVTOOLS_CUSTOM_BINDINGS_JS" file="resources\extensions\devtools_custom_bindings.js" type="BINDATA" />
+ <include name="IDR_EXPERIMENTAL_APP_CUSTOM_BINDINGS_JS" file="resources\extensions\experimental.app_custom_bindings.js" type="BINDATA" />
<include name="IDR_EXPERIMENTAL_OFFSCREENTABS_CUSTOM_BINDINGS_JS" file="resources\extensions\experimental.offscreenTabs_custom_bindings.js" type="BINDATA" />
<include name="IDR_EXPERIMENTAL_USB_CUSTOM_BINDINGS_JS" file="resources\extensions\experimental.usb_custom_bindings.js" type="BINDATA" />
<include name="IDR_EXTENSION_CUSTOM_BINDINGS_JS" file="resources\extensions\extension_custom_bindings.js" type="BINDATA" />
diff --git a/chrome/renderer/resources/extensions/experimental.app_custom_bindings.js b/chrome/renderer/resources/extensions/experimental.app_custom_bindings.js
new file mode 100644
index 0000000..575ca47
--- /dev/null
+++ b/chrome/renderer/resources/extensions/experimental.app_custom_bindings.js
@@ -0,0 +1,35 @@
+// 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.
+
+// Custom bindings for the experimental.app API.
+
+var chromeHidden = requireNative('chrome_hidden').GetChromeHidden();
+var experimentalAppNatives = requireNative('experimental_app');
+var GetIsolatedFileSystem = experimentalAppNatives.GetIsolatedFileSystem;
+
+chromeHidden.registerCustomHook('experimental.app', function(bindingsAPI) {
+ chrome.experimental.app.onLaunched.dispatch =
+ function(launchData, fileSystemId, baseName) {
+ if (launchData) {
+ event = this;
+ fs = GetIsolatedFileSystem(fileSystemId);
+ try {
+ fs.root.getFile(baseName, {}, function(fileEntry) {
+ launchData.intent.data = fileEntry;
+ launchData.intent.postResult = function() {};
+ launchData.intent.postFailure = function() {};
+ chrome.Event.prototype.dispatch.call(event, launchData);
+ }, function(fileError) {
+ console.error('Error getting fileEntry, code: ' + fileError.code);
+ chrome.Event.prototype.dispatch.call(event);
+ });
+ } catch (e) {
+ console.error('Error in event handler for onLaunched: ' + e.stack);
+ chrome.Event.prototype.dispatch.call(event);
+ }
+ } else {
+ chrome.Event.prototype.dispatch.call(this);
+ }
+ };
+});
diff --git a/chrome/test/data/extensions/platform_apps/launch_file/manifest.json b/chrome/test/data/extensions/platform_apps/launch_file/manifest.json
new file mode 100644
index 0000000..2f31fff
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/launch_file/manifest.json
@@ -0,0 +1,18 @@
+{
+ "name": "Platform App Launch Test",
+ "platform_app": true,
+ "version": "1",
+ "manifest_version": 2,
+ "intents": {
+ "http://webintents.org/view": {
+ "type": [
+ "text/*"
+ ],
+ "title": "Test editor"
+ }
+ },
+ "permissions": ["experimental"],
+ "background": {
+ "scripts": ["test.js"]
+ }
+}
diff --git a/chrome/test/data/extensions/platform_apps/launch_file/test.js b/chrome/test/data/extensions/platform_apps/launch_file/test.js
new file mode 100644
index 0000000..210234e
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/launch_file/test.js
@@ -0,0 +1,35 @@
+// 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.
+
+// Test that there is a launchData.intent, it is set up proerly, and that the
+// FileEntry in launchData.intent.data can be read.
+function onLaunched(launchData) {
+ chrome.test.runTests([
+ function testIntent() {
+ chrome.test.assertFalse(!launchData, "No launchData");
+ chrome.test.assertFalse(!launchData.intent, "No launchData.intent");
+ chrome.test.assertEq(launchData.intent.action,
+ "http://webintents.org/view");
+ chrome.test.assertEq(launchData.intent.type,
+ "chrome-extension://fileentry");
+ chrome.test.assertFalse(!launchData.intent.data,
+ "No launchData.intent.data");
+
+ launchData.intent.data.file(function(file) {
+ var reader = new FileReader();
+ reader.onloadend = function(e) {
+ chrome.test.assertEq(
+ reader.result.indexOf("This is a test. Word."), 0);
+ chrome.test.succeed();
+ };
+ reader.onerror = function(e) {
+ chrome.test.fail("Error reading file contents.");
+ };
+ reader.readAsText(file);
+ });
+ }
+ ]);
+}
+
+chrome.experimental.app.onLaunched.addListener(onLaunched);
diff --git a/chrome/test/data/extensions/platform_apps/launch_files/test.txt b/chrome/test/data/extensions/platform_apps/launch_files/test.txt
new file mode 100644
index 0000000..9a0b99f
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/launch_files/test.txt
@@ -0,0 +1,2 @@
+This is a test. Word.
+
diff --git a/chrome/test/data/extensions/platform_apps/launch_files/test.unknownextension b/chrome/test/data/extensions/platform_apps/launch_files/test.unknownextension
new file mode 100644
index 0000000..9a0b99f
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/launch_files/test.unknownextension
@@ -0,0 +1,2 @@
+This is a test. Word.
+
diff --git a/chrome/test/data/extensions/platform_apps/launch_invalid/manifest.json b/chrome/test/data/extensions/platform_apps/launch_invalid/manifest.json
new file mode 100644
index 0000000..2f31fff
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/launch_invalid/manifest.json
@@ -0,0 +1,18 @@
+{
+ "name": "Platform App Launch Test",
+ "platform_app": true,
+ "version": "1",
+ "manifest_version": 2,
+ "intents": {
+ "http://webintents.org/view": {
+ "type": [
+ "text/*"
+ ],
+ "title": "Test editor"
+ }
+ },
+ "permissions": ["experimental"],
+ "background": {
+ "scripts": ["test.js"]
+ }
+}
diff --git a/chrome/test/data/extensions/platform_apps/launch_invalid/test.js b/chrome/test/data/extensions/platform_apps/launch_invalid/test.js
new file mode 100644
index 0000000..4ec872a
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/launch_invalid/test.js
@@ -0,0 +1,15 @@
+// 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.
+
+// Check that there is no launch data.
+function onLaunched(launchData) {
+ chrome.test.runTests([
+ function testIntent() {
+ chrome.test.assertTrue(!launchData, "LaunchData found");
+ chrome.test.succeed();
+ }
+ ]);
+}
+
+chrome.experimental.app.onLaunched.addListener(onLaunched);
diff --git a/chrome/test/data/extensions/platform_apps/launch_no_intent/manifest.json b/chrome/test/data/extensions/platform_apps/launch_no_intent/manifest.json
new file mode 100644
index 0000000..084addf
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/launch_no_intent/manifest.json
@@ -0,0 +1,10 @@
+{
+ "name": "Platform App Launch Test",
+ "platform_app": true,
+ "version": "1",
+ "manifest_version": 2,
+ "permissions": ["experimental"],
+ "background": {
+ "scripts": ["test.js"]
+ }
+}
diff --git a/chrome/test/data/extensions/platform_apps/launch_no_intent/test.js b/chrome/test/data/extensions/platform_apps/launch_no_intent/test.js
new file mode 100644
index 0000000..4ec872a
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/launch_no_intent/test.js
@@ -0,0 +1,15 @@
+// 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.
+
+// Check that there is no launch data.
+function onLaunched(launchData) {
+ chrome.test.runTests([
+ function testIntent() {
+ chrome.test.assertTrue(!launchData, "LaunchData found");
+ chrome.test.succeed();
+ }
+ ]);
+}
+
+chrome.experimental.app.onLaunched.addListener(onLaunched);
diff --git a/chrome/test/data/extensions/platform_apps/launch_nothing/manifest.json b/chrome/test/data/extensions/platform_apps/launch_nothing/manifest.json
new file mode 100644
index 0000000..2f31fff
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/launch_nothing/manifest.json
@@ -0,0 +1,18 @@
+{
+ "name": "Platform App Launch Test",
+ "platform_app": true,
+ "version": "1",
+ "manifest_version": 2,
+ "intents": {
+ "http://webintents.org/view": {
+ "type": [
+ "text/*"
+ ],
+ "title": "Test editor"
+ }
+ },
+ "permissions": ["experimental"],
+ "background": {
+ "scripts": ["test.js"]
+ }
+}
diff --git a/chrome/test/data/extensions/platform_apps/launch_nothing/test.js b/chrome/test/data/extensions/platform_apps/launch_nothing/test.js
new file mode 100644
index 0000000..9f9f30f
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/launch_nothing/test.js
@@ -0,0 +1,15 @@
+// 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.
+
+// Check that there is no launchData.
+function onLaunched(launchData) {
+ chrome.test.runTests([
+ function testIntent() {
+ chrome.test.assertTrue(!launchData, "LaunchData found");
+ chrome.test.succeed();
+ }
+ ]);
+}
+
+chrome.experimental.app.onLaunched.addListener(onLaunched);
diff --git a/chrome/test/data/extensions/platform_apps/launch_wrong_intent/manifest.json b/chrome/test/data/extensions/platform_apps/launch_wrong_intent/manifest.json
new file mode 100644
index 0000000..91e2ea7
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/launch_wrong_intent/manifest.json
@@ -0,0 +1,18 @@
+{
+ "name": "Platform App Launch Test",
+ "platform_app": true,
+ "version": "1",
+ "manifest_version": 2,
+ "intents": {
+ "http://webintents.org/share": {
+ "type": [
+ "text/*"
+ ],
+ "title": "Test editor"
+ }
+ },
+ "permissions": ["experimental"],
+ "background": {
+ "scripts": ["test.js"]
+ }
+}
diff --git a/chrome/test/data/extensions/platform_apps/launch_wrong_intent/test.js b/chrome/test/data/extensions/platform_apps/launch_wrong_intent/test.js
new file mode 100644
index 0000000..4ec872a
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/launch_wrong_intent/test.js
@@ -0,0 +1,15 @@
+// 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.
+
+// Check that there is no launch data.
+function onLaunched(launchData) {
+ chrome.test.runTests([
+ function testIntent() {
+ chrome.test.assertTrue(!launchData, "LaunchData found");
+ chrome.test.succeed();
+ }
+ ]);
+}
+
+chrome.experimental.app.onLaunched.addListener(onLaunched);
diff --git a/chrome/test/data/extensions/platform_apps/launch_wrong_type/manifest.json b/chrome/test/data/extensions/platform_apps/launch_wrong_type/manifest.json
new file mode 100644
index 0000000..d29492a
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/launch_wrong_type/manifest.json
@@ -0,0 +1,18 @@
+{
+ "name": "Platform App Launch Test",
+ "platform_app": true,
+ "version": "1",
+ "manifest_version": 2,
+ "intents": {
+ "http://webintents.org/view": {
+ "type": [
+ "image/*"
+ ],
+ "title": "Test editor"
+ }
+ },
+ "permissions": ["experimental"],
+ "background": {
+ "scripts": ["test.js"]
+ }
+}
diff --git a/chrome/test/data/extensions/platform_apps/launch_wrong_type/test.js b/chrome/test/data/extensions/platform_apps/launch_wrong_type/test.js
new file mode 100644
index 0000000..4ec872a
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/launch_wrong_type/test.js
@@ -0,0 +1,15 @@
+// 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.
+
+// Check that there is no launch data.
+function onLaunched(launchData) {
+ chrome.test.runTests([
+ function testIntent() {
+ chrome.test.assertTrue(!launchData, "LaunchData found");
+ chrome.test.succeed();
+ }
+ ]);
+}
+
+chrome.experimental.app.onLaunched.addListener(onLaunched);