summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/generated_resources.grd9
-rw-r--r--chrome/browser/automation/automation_provider.cc4
-rw-r--r--chrome/browser/dom_ui/dom_ui_factory.cc6
-rw-r--r--chrome/browser/extensions/execute_code_in_tab_function.cc10
-rw-r--r--chrome/browser/extensions/extension_accessibility_api.cc4
-rw-r--r--chrome/browser/extensions/extension_bookmark_manager_api.cc4
-rw-r--r--chrome/browser/extensions/extension_bookmarks_module.cc4
-rw-r--r--chrome/browser/extensions/extension_browser_event_router.cc8
-rw-r--r--chrome/browser/extensions/extension_browsertest.cc16
-rw-r--r--chrome/browser/extensions/extension_browsertest.h4
-rw-r--r--chrome/browser/extensions/extension_devtools_bridge.cc9
-rw-r--r--chrome/browser/extensions/extension_dom_ui.cc16
-rw-r--r--chrome/browser/extensions/extension_dom_ui.h3
-rw-r--r--chrome/browser/extensions/extension_function.h10
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc14
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.h9
-rw-r--r--chrome/browser/extensions/extension_history_api.cc4
-rw-r--r--chrome/browser/extensions/extension_host.cc33
-rw-r--r--chrome/browser/extensions/extension_host.h3
-rwxr-xr-xchrome/browser/extensions/extension_incognito_apitest.cc (renamed from chrome/browser/extensions/incognito_noscript_apitest.cc)80
-rw-r--r--chrome/browser/extensions/extension_message_service.cc11
-rw-r--r--chrome/browser/extensions/extension_message_service.h3
-rw-r--r--chrome/browser/extensions/extension_page_actions_module.cc6
-rw-r--r--chrome/browser/extensions/extension_popup_api.cc5
-rw-r--r--chrome/browser/extensions/extension_process_manager.cc13
-rw-r--r--chrome/browser/extensions/extension_processes_api.cc4
-rw-r--r--chrome/browser/extensions/extension_protocols.cc14
-rw-r--r--chrome/browser/extensions/extension_tabs_module.cc97
-rw-r--r--chrome/browser/extensions/extension_tabs_module.h3
-rw-r--r--chrome/browser/extensions/extension_tabs_module_constants.cc1
-rw-r--r--chrome/browser/extensions/extension_tabs_module_constants.h1
-rw-r--r--chrome/browser/extensions/extension_test_api.cc11
-rw-r--r--chrome/browser/extensions/extension_test_api.h6
-rw-r--r--chrome/browser/extensions/extension_toolstrip_api.cc6
-rw-r--r--chrome/browser/extensions/extension_ui_unittest.cc4
-rw-r--r--chrome/browser/extensions/extension_uitest.cc10
-rw-r--r--chrome/browser/extensions/extensions_service.cc18
-rw-r--r--chrome/browser/extensions/extensions_service.h5
-rw-r--r--chrome/browser/extensions/extensions_ui.cc34
-rw-r--r--chrome/browser/extensions/extensions_ui.h9
-rw-r--r--chrome/browser/extensions/user_script_master.cc29
-rw-r--r--chrome/browser/extensions/user_script_master.h5
-rw-r--r--chrome/browser/resources/extensions_ui.html34
-rw-r--r--[-rwxr-xr-x]chrome/chrome_tests.gypi2
-rwxr-xr-xchrome/common/extensions/api/extension_api.json14
-rw-r--r--chrome/common/notification_type.h4
-rw-r--r--chrome/common/render_messages_internal.h6
-rw-r--r--chrome/renderer/extensions/extension_api_client_unittest.cc4
-rw-r--r--chrome/renderer/extensions/extension_process_bindings.cc25
-rw-r--r--chrome/renderer/extensions/extension_process_bindings.h4
-rw-r--r--chrome/renderer/render_thread.cc7
-rw-r--r--chrome/renderer/render_thread.h3
-rw-r--r--chrome/renderer/resources/event_bindings.js10
-rw-r--r--chrome/renderer/resources/extension_process_bindings.js5
-rw-r--r--chrome/test/data/extensions/api_test/incognito/apis/background.html76
-rw-r--r--chrome/test/data/extensions/api_test/incognito/apis/manifest.json7
-rw-r--r--chrome/test/data/extensions/api_test/incognito/apis_disabled/background.html28
-rw-r--r--chrome/test/data/extensions/api_test/incognito/apis_disabled/manifest.json7
-rw-r--r--[-rwxr-xr-x]chrome/test/data/extensions/api_test/incognito/content_scripts/change_page_title.js (renamed from chrome/test/data/extensions/api_test/incognito_no_script/change_page_title.js)0
-rw-r--r--[-rwxr-xr-x]chrome/test/data/extensions/api_test/incognito/content_scripts/manifest.json (renamed from chrome/test/data/extensions/api_test/incognito_no_script/manifest.json)0
-rw-r--r--chrome/test/data/extensions/api_test/incognito/popup/manifest.json9
-rw-r--r--chrome/test/data/extensions/api_test/incognito/popup/popup.html15
-rw-r--r--chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension1.json2
-rw-r--r--chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension2.json2
-rw-r--r--chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension3.json2
65 files changed, 660 insertions, 151 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index adcf2f9..6c0f4de 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3037,6 +3037,15 @@ each locale. -->
<message name="IDS_EXTENSIONS_ENABLE" desc="The link for enabling extensions.">
Enable
</message>
+ <message name="IDS_EXTENSIONS_ENABLE_INCOGNITO" desc="The link for enabling extensions in incognito.">
+ Enable in Incognito
+ </message>
+ <message name="IDS_EXTENSIONS_DISABLE_INCOGNITO" desc="The link for disabling extensions in incognito.">
+ Disable in Incognito
+ </message>
+ <message name="IDS_EXTENSIONS_ENABLE_INCOGNITO_WARNING" desc="A warning message displayed when the user attempts to enable a non-incognito-safe extension in incognito.">
+ This extension doesn't officially support running in incognito mode. Enable anyway?
+ </message>
<message name="IDS_EXTENSIONS_RELOAD" desc="The link for reloading extensions.">
Reload
</message>
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index 5bf39b0..d993afb 100644
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -1787,8 +1787,8 @@ bool AutomationProvider::InterceptBrowserEventMessageFromExternalHost(
}
if (profile()->GetExtensionMessageService()) {
- profile()->GetExtensionMessageService()->
- DispatchEventToRenderers(event_name.c_str(), json_args);
+ profile()->GetExtensionMessageService()->DispatchEventToRenderers(
+ event_name, json_args, profile()->IsOffTheRecord());
}
return true;
diff --git a/chrome/browser/dom_ui/dom_ui_factory.cc b/chrome/browser/dom_ui/dom_ui_factory.cc
index 6f0c275..e35063e 100644
--- a/chrome/browser/dom_ui/dom_ui_factory.cc
+++ b/chrome/browser/dom_ui/dom_ui_factory.cc
@@ -35,11 +35,13 @@ DOMUI* NewDOMUI(TabContents* contents, const GURL& url) {
// Special case for extensions.
template<>
DOMUI* NewDOMUI<ExtensionDOMUI>(TabContents* contents, const GURL& url) {
- // Don't use a DOMUI for non-existent extensions.
+ // Don't use a DOMUI for non-existent extensions or for incognito tabs. The
+ // latter restriction is because we require extensions to run within a single
+ // process.
ExtensionsService* service = contents->profile()->GetExtensionsService();
bool valid_extension =
(service && service->GetExtensionById(url.host(), false));
- if (valid_extension)
+ if (valid_extension && !contents->profile()->IsOffTheRecord())
return new ExtensionDOMUI(contents);
return NULL;
}
diff --git a/chrome/browser/extensions/execute_code_in_tab_function.cc b/chrome/browser/extensions/execute_code_in_tab_function.cc
index da16d80..27ccf3f 100644
--- a/chrome/browser/extensions/execute_code_in_tab_function.cc
+++ b/chrome/browser/extensions/execute_code_in_tab_function.cc
@@ -48,7 +48,7 @@ bool ExecuteCodeInTabFunction::RunImpl() {
Value* tab_value = NULL;
EXTENSION_FUNCTION_VALIDATE(args->Get(0, &tab_value));
if (tab_value->IsType(Value::TYPE_NULL)) {
- browser = dispatcher()->GetBrowser();
+ browser = GetBrowser();
if (!browser) {
error_ = keys::kNoCurrentWindowError;
return false;
@@ -57,8 +57,9 @@ bool ExecuteCodeInTabFunction::RunImpl() {
return false;
} else {
EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&execute_tab_id_));
- if (!ExtensionTabUtil::GetTabById(execute_tab_id_, profile(), &browser,
- NULL, &contents, NULL)) {
+ if (!ExtensionTabUtil::GetTabById(execute_tab_id_, profile(),
+ include_incognito(),
+ &browser, NULL, &contents, NULL)) {
return false;
}
}
@@ -127,7 +128,8 @@ void ExecuteCodeInTabFunction::DidLoadFile(bool success,
bool ExecuteCodeInTabFunction::Execute(const std::string& code_string) {
TabContents* contents = NULL;
Browser* browser = NULL;
- if (!ExtensionTabUtil::GetTabById(execute_tab_id_, profile(), &browser, NULL,
+ if (!ExtensionTabUtil::GetTabById(execute_tab_id_, profile(),
+ include_incognito(), &browser, NULL,
&contents, NULL) && contents && browser) {
SendResponse(false);
return false;
diff --git a/chrome/browser/extensions/extension_accessibility_api.cc b/chrome/browser/extensions/extension_accessibility_api.cc
index 2ea3775..38745a7 100644
--- a/chrome/browser/extensions/extension_accessibility_api.cc
+++ b/chrome/browser/extensions/extension_accessibility_api.cc
@@ -157,8 +157,8 @@ void ExtensionAccessibilityEventRouter::DispatchEvent(
const char* event_name,
const std::string& json_args) {
if (enabled_ && profile && profile->GetExtensionMessageService()) {
- profile->GetExtensionMessageService()->
- DispatchEventToRenderers(event_name, json_args);
+ profile->GetExtensionMessageService()->DispatchEventToRenderers(
+ event_name, json_args, profile->IsOffTheRecord());
}
}
diff --git a/chrome/browser/extensions/extension_bookmark_manager_api.cc b/chrome/browser/extensions/extension_bookmark_manager_api.cc
index 81848f3..a67b716 100644
--- a/chrome/browser/extensions/extension_bookmark_manager_api.cc
+++ b/chrome/browser/extensions/extension_bookmark_manager_api.cc
@@ -170,8 +170,8 @@ void ExtensionBookmarkManagerEventRouter::DispatchEvent(const char* event_name,
std::string json_args;
base::JSONWriter::Write(args, false, &json_args);
- profile_->GetExtensionMessageService()->
- DispatchEventToRenderers(event_name, json_args);
+ profile_->GetExtensionMessageService()->DispatchEventToRenderers(
+ event_name, json_args, profile_->IsOffTheRecord());
}
void ExtensionBookmarkManagerEventRouter::DispatchDragEvent(
diff --git a/chrome/browser/extensions/extension_bookmarks_module.cc b/chrome/browser/extensions/extension_bookmarks_module.cc
index 993cb05..d561e2a 100644
--- a/chrome/browser/extensions/extension_bookmarks_module.cc
+++ b/chrome/browser/extensions/extension_bookmarks_module.cc
@@ -170,8 +170,8 @@ void ExtensionBookmarkEventRouter::DispatchEvent(Profile *profile,
const char* event_name,
const std::string json_args) {
if (profile->GetExtensionMessageService()) {
- profile->GetExtensionMessageService()->
- DispatchEventToRenderers(event_name, json_args);
+ profile->GetExtensionMessageService()->DispatchEventToRenderers(
+ event_name, json_args, profile->IsOffTheRecord());
}
}
diff --git a/chrome/browser/extensions/extension_browser_event_router.cc b/chrome/browser/extensions/extension_browser_event_router.cc
index 388863a..9b379bc 100644
--- a/chrome/browser/extensions/extension_browser_event_router.cc
+++ b/chrome/browser/extensions/extension_browser_event_router.cc
@@ -88,8 +88,8 @@ static void DispatchEvent(Profile* profile,
const char* event_name,
const std::string json_args) {
if (profile->GetExtensionMessageService()) {
- profile->GetExtensionMessageService()->
- DispatchEventToRenderers(event_name, json_args);
+ profile->GetExtensionMessageService()->DispatchEventToRenderers(
+ event_name, json_args, profile->IsOffTheRecord());
}
}
@@ -437,8 +437,8 @@ void ExtensionBrowserEventRouter::PageActionExecuted(
DispatchOldPageActionEvent(profile, extension_id, page_action_id, tab_id, url,
button);
TabContents* tab_contents = NULL;
- if (!ExtensionTabUtil::GetTabById(tab_id, profile, NULL, NULL, &tab_contents,
- NULL)) {
+ if (!ExtensionTabUtil::GetTabById(tab_id, profile, profile->IsOffTheRecord(),
+ NULL, NULL, &tab_contents, NULL)) {
return;
}
std::string event_name = std::string("pageAction/") + extension_id;
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index 9b4ddd8..d96d6dc 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -51,7 +51,8 @@ void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) {
command_line->AppendSwitch(switches::kEnableExtensionToolstrips);
}
-bool ExtensionBrowserTest::LoadExtension(const FilePath& path) {
+bool ExtensionBrowserTest::LoadExtensionImpl(const FilePath& path,
+ bool incognito_enabled) {
ExtensionsService* service = browser()->profile()->GetExtensionsService();
size_t num_before = service->extensions()->size();
{
@@ -67,9 +68,22 @@ bool ExtensionBrowserTest::LoadExtension(const FilePath& path) {
if (num_after != (num_before + 1))
return false;
+ if (incognito_enabled) {
+ Extension* extension = service->extensions()->at(num_after - 1);
+ service->SetIsIncognitoEnabled(extension->id(), true);
+ }
+
return WaitForExtensionHostsToLoad();
}
+bool ExtensionBrowserTest::LoadExtension(const FilePath& path) {
+ return LoadExtensionImpl(path, false);
+}
+
+bool ExtensionBrowserTest::LoadExtensionIncognito(const FilePath& path) {
+ return LoadExtensionImpl(path, true);
+}
+
// This class is used to simulate an installation abort by the user.
class MockAbortExtensionInstallUI : public ExtensionInstallUI {
public:
diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h
index 263f582..8a34903 100644
--- a/chrome/browser/extensions/extension_browsertest.h
+++ b/chrome/browser/extensions/extension_browsertest.h
@@ -25,6 +25,9 @@ class ExtensionBrowserTest
virtual void SetUpCommandLine(CommandLine* command_line);
bool LoadExtension(const FilePath& path);
+ // Same as above, but enables the extension in incognito mode first.
+ bool LoadExtensionIncognito(const FilePath& path);
+
// |expected_change| indicates how many extensions should be installed (or
// disabled, if negative).
// 1 means you expect a new install, 0 means you expect an upgrade, -1 means
@@ -93,6 +96,7 @@ class ExtensionBrowserTest
bool InstallOrUpdateExtension(const std::string& id, const FilePath& path,
bool should_cancel,
int expected_change);
+ bool LoadExtensionImpl(const FilePath& path, bool incognito_enabled);
bool WaitForExtensionHostsToLoad();
diff --git a/chrome/browser/extensions/extension_devtools_bridge.cc b/chrome/browser/extensions/extension_devtools_bridge.cc
index c9a5f50..a6399d8 100644
--- a/chrome/browser/extensions/extension_devtools_bridge.cc
+++ b/chrome/browser/extensions/extension_devtools_bridge.cc
@@ -36,7 +36,8 @@ bool ExtensionDevToolsBridge::RegisterAsDevToolsClientHost() {
TabStripModel* tab_strip;
TabContents* contents;
int tab_index;
- if (ExtensionTabUtil::GetTabById(tab_id_, profile_, &browser, &tab_strip,
+ if (ExtensionTabUtil::GetTabById(tab_id_, profile_, true,
+ &browser, &tab_strip,
&contents, &tab_index)) {
DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
devtools_manager->RegisterDevToolsClientHostFor(
@@ -63,8 +64,8 @@ void ExtensionDevToolsBridge::InspectedTabClosing() {
// TODO(knorton): Remove this event in favor of the standard tabs.onRemoved
// event in extensions.
std::string json("[{}]");
- profile_->GetExtensionMessageService()->
- DispatchEventToRenderers(on_tab_close_event_name_, json);
+ profile_->GetExtensionMessageService()->DispatchEventToRenderers(
+ on_tab_close_event_name_, json, profile_->IsOffTheRecord());
// This may result in this object being destroyed.
extension_devtools_manager_->BridgeClosingForTab(tab_id_);
@@ -87,7 +88,7 @@ void ExtensionDevToolsBridge::OnRpcMessage(const DevToolsMessageData& data) {
&& data.method_name == kApuPageEventMessageName) {
std::string json = StringPrintf("[%s]", data.arguments[0].c_str());
profile_->GetExtensionMessageService()->DispatchEventToRenderers(
- on_page_event_name_, json);
+ on_page_event_name_, json, profile_->IsOffTheRecord());
}
}
diff --git a/chrome/browser/extensions/extension_dom_ui.cc b/chrome/browser/extensions/extension_dom_ui.cc
index de2d13b..b39b15b 100644
--- a/chrome/browser/extensions/extension_dom_ui.cc
+++ b/chrome/browser/extensions/extension_dom_ui.cc
@@ -76,11 +76,19 @@ void ExtensionDOMUI::ProcessDOMUIMessage(const std::string& message,
has_callback);
}
-Browser* ExtensionDOMUI::GetBrowser() const {
+Browser* ExtensionDOMUI::GetBrowser(bool include_incognito) const {
+ Browser* browser = NULL;
TabContentsDelegate* tab_contents_delegate = tab_contents()->delegate();
- if (tab_contents_delegate)
- return tab_contents_delegate->GetBrowser();
- return NULL;
+ if (tab_contents_delegate) {
+ browser = tab_contents_delegate->GetBrowser();
+ if (browser && browser->profile()->IsOffTheRecord() && !include_incognito) {
+ // Fall back to the toplevel regular browser if we don't want to include
+ // incognito browsers.
+ browser = BrowserList::GetLastActiveWithProfile(
+ browser->profile()->GetOriginalProfile());
+ }
+ }
+ return browser;
}
Profile* ExtensionDOMUI::GetProfile() {
diff --git a/chrome/browser/extensions/extension_dom_ui.h b/chrome/browser/extensions/extension_dom_ui.h
index 59a89a8..9d85ccb 100644
--- a/chrome/browser/extensions/extension_dom_ui.h
+++ b/chrome/browser/extensions/extension_dom_ui.h
@@ -41,11 +41,12 @@ class ExtensionDOMUI
bool has_callback);
// ExtensionFunctionDispatcher::Delegate
- virtual Browser* GetBrowser() const;
+ virtual Browser* GetBrowser(bool include_incognito) const;
virtual ExtensionDOMUI* GetExtensionDOMUI() { return this; }
virtual gfx::NativeWindow GetFrameNativeWindow();
// ExtensionPopupHost::Delegate
+ virtual Browser* GetBrowser() const { return GetBrowser(true); }
virtual RenderViewHost* GetRenderViewHost();
virtual Profile* GetProfile();
virtual gfx::NativeView GetNativeViewOfHost();
diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h
index 6db6443..06f69ab 100644
--- a/chrome/browser/extensions/extension_function.h
+++ b/chrome/browser/extensions/extension_function.h
@@ -68,6 +68,9 @@ class ExtensionFunction : public base::RefCounted<ExtensionFunction> {
void set_has_callback(bool has_callback) { has_callback_ = has_callback; }
bool has_callback() { return has_callback_; }
+ void set_include_incognito(bool include) { include_incognito_ = include; }
+ bool include_incognito() { return include_incognito_; }
+
// Execute the API. Clients should call set_raw_args() and
// set_request_id() before calling this method. Derived classes should be
// ready to return raw_result() and error() before returning from this
@@ -88,6 +91,10 @@ class ExtensionFunction : public base::RefCounted<ExtensionFunction> {
return NULL;
}
+ Browser* GetBrowser() {
+ return dispatcher()->GetBrowser(include_incognito_);
+ }
+
// The peer to the dispatcher that will service this extension function call.
scoped_refptr<ExtensionFunctionDispatcher::Peer> peer_;
@@ -101,6 +108,9 @@ class ExtensionFunction : public base::RefCounted<ExtensionFunction> {
// of this call.
bool has_callback_;
+ // True if this callback should include information from incognito contexts.
+ bool include_incognito_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionFunction);
};
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 69e4d54..35b73a5 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -174,6 +174,7 @@ void FactoryRegistry::ResetFunctions() {
RegisterFunction<ExtensionTestFailFunction>();
RegisterFunction<ExtensionTestLogFunction>();
RegisterFunction<ExtensionTestQuotaResetFunction>();
+ RegisterFunction<ExtensionTestCreateIncognitoTabFunction>();
// Accessibility.
RegisterFunction<GetFocusedControlFunction>();
@@ -212,7 +213,7 @@ ExtensionFunction* FactoryRegistry::NewFunction(const std::string& name) {
gfx::NativeWindow ExtensionFunctionDispatcher::Delegate::
GetFrameNativeWindow() {
- Browser* browser = GetBrowser();
+ Browser* browser = GetBrowser(true);
// If a browser is bound to this dispatcher, then return the widget hosting
// the window. Extensions hosted in ExternalTabContainer objects may not
// have a running browser instance.
@@ -266,6 +267,9 @@ ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
epm->RegisterExtensionProcess(extension_id(),
render_view_host->process()->id());
+ bool incognito_enabled =
+ profile()->GetExtensionsService()->IsIncognitoEnabled(extension->id());
+
// Update the extension permissions. Doing this each time we create an EFD
// ensures that new processes are informed of permissions for newly installed
// extensions.
@@ -273,6 +277,8 @@ ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
extension->id(), extension->api_permissions()));
render_view_host->Send(new ViewMsg_Extension_SetHostPermissions(
extension->url(), extension->host_permissions()));
+ render_view_host->Send(new ViewMsg_Extension_ExtensionSetIncognitoEnabled(
+ extension->id(), incognito_enabled));
}
ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() {
@@ -280,8 +286,8 @@ ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() {
peer_->dispatcher_ = NULL;
}
-Browser* ExtensionFunctionDispatcher::GetBrowser() {
- return delegate_->GetBrowser();
+Browser* ExtensionFunctionDispatcher::GetBrowser(bool include_incognito) {
+ return delegate_->GetBrowser(include_incognito);
}
ExtensionPopupHost* ExtensionFunctionDispatcher::GetPopupHost() {
@@ -324,6 +330,8 @@ void ExtensionFunctionDispatcher::HandleRequest(const std::string& name,
function->SetArgs(args);
function->set_request_id(request_id);
function->set_has_callback(has_callback);
+ function->set_include_incognito(
+ profile()->GetExtensionsService()->IsIncognitoEnabled(extension_id()));
ExtensionsService* service = profile()->GetExtensionsService();
DCHECK(service);
diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h
index 38376e7..1bdfca2 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.h
+++ b/chrome/browser/extensions/extension_function_dispatcher.h
@@ -34,7 +34,10 @@ class ExtensionFunctionDispatcher {
public:
class Delegate {
public:
- virtual Browser* GetBrowser() const = 0;
+ // Returns the browser that this delegate is associated with. If the browser
+ // is incognito, but |include_incognito_windows| is false, we fall back to
+ // the toplevel browser in the original profile.
+ virtual Browser* GetBrowser(bool include_incognito_windows) const = 0;
// Returns the gfx::NativeWindow that contains the view hosting the
// environment in which the function dispatcher resides.
@@ -89,7 +92,9 @@ class ExtensionFunctionDispatcher {
// Gets the browser extension functions should operate relative to. For
// example, for positioning windows, or alert boxes, or creating tabs.
- Browser* GetBrowser();
+ // If |include_incognito| is false, and the appropriate browser is incognito,
+ // we will fall back to a regular browser window or NULL if unavailable.
+ Browser* GetBrowser(bool include_incognito);
// Get the extension popup hosting environment for the ExtensionHost
// or ExtensionDOMUI associted with this dispatcher.
diff --git a/chrome/browser/extensions/extension_history_api.cc b/chrome/browser/extensions/extension_history_api.cc
index c1808d5..75ed48a 100644
--- a/chrome/browser/extensions/extension_history_api.cc
+++ b/chrome/browser/extensions/extension_history_api.cc
@@ -140,8 +140,8 @@ void ExtensionHistoryEventRouter::DispatchEvent(Profile* profile,
const char* event_name,
const std::string& json_args) {
if (profile && profile->GetExtensionMessageService()) {
- profile->GetExtensionMessageService()->
- DispatchEventToRenderers(event_name, json_args);
+ profile->GetExtensionMessageService()->DispatchEventToRenderers(
+ event_name, json_args, profile->IsOffTheRecord());
}
}
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index e139899..5c01d69 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -483,8 +483,8 @@ void ExtensionHost::ProcessDOMUIMessage(const std::string& message,
int request_id,
bool has_callback) {
if (extension_function_dispatcher_.get()) {
- extension_function_dispatcher_->HandleRequest(message, content, request_id,
- has_callback);
+ extension_function_dispatcher_->HandleRequest(
+ message, content, request_id, has_callback);
}
}
@@ -612,19 +612,28 @@ void ExtensionHost::HandleMouseLeave() {
#endif
}
-Browser* ExtensionHost::GetBrowser() const {
+Browser* ExtensionHost::GetBrowser(bool include_incognito) const {
+ Browser* browser = NULL;
+
if (view_.get())
- return view_->browser();
+ browser = view_->browser();
- Profile* profile = render_view_host()->process()->profile();
- Browser* browser = BrowserList::GetLastActiveWithProfile(profile);
+ if (!browser ||
+ (browser->profile()->IsOffTheRecord() && !include_incognito)) {
+ Profile* profile = render_view_host()->process()->profile();
+ // Make sure we don't return an incognito browser without proper access.
+ if (!include_incognito)
+ profile = profile->GetOriginalProfile();
- // It's possible for a browser to exist, but to have never been active.
- // This can happen if you launch the browser on a machine without an active
- // desktop (a headless buildbot) or if you quickly give another app focus
- // at launch time. This is easy to do with browser_tests.
- if (!browser)
- browser = BrowserList::FindBrowserWithProfile(profile);
+ browser = BrowserList::GetLastActiveWithProfile(profile);
+
+ // It's possible for a browser to exist, but to have never been active.
+ // This can happen if you launch the browser on a machine without an active
+ // desktop (a headless buildbot) or if you quickly give another app focus
+ // at launch time. This is easy to do with browser_tests.
+ if (!browser)
+ browser = BrowserList::FindBrowserWithProfile(profile);
+ }
// TODO(erikkay): can this still return NULL? Is Rafael's comment still
// valid here?
diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h
index fd155d7..83f2cb2 100644
--- a/chrome/browser/extensions/extension_host.h
+++ b/chrome/browser/extensions/extension_host.h
@@ -196,10 +196,11 @@ class ExtensionHost : public ExtensionPopupHost::PopupDelegate,
// If this ExtensionHost has a view, this returns the Browser that view is a
// part of. If this is a global background page, we use the active Browser
// instead.
- virtual Browser* GetBrowser() const;
+ virtual Browser* GetBrowser(bool include_incognito) const;
virtual ExtensionHost* GetExtensionHost() { return this; }
// ExtensionPopupHost::Delegate
+ virtual Browser* GetBrowser() const { return GetBrowser(true); }
virtual RenderViewHost* GetRenderViewHost() { return render_view_host(); }
virtual gfx::NativeView GetNativeViewOfHost() {
return view()->native_view();
diff --git a/chrome/browser/extensions/incognito_noscript_apitest.cc b/chrome/browser/extensions/extension_incognito_apitest.cc
index d4e71a5..29de8fb 100755
--- a/chrome/browser/extensions/incognito_noscript_apitest.cc
+++ b/chrome/browser/extensions/extension_incognito_apitest.cc
@@ -5,7 +5,8 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/extensions/browser_action_test_util.h"
+#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/browser/profile.h"
@@ -24,7 +25,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoNoScript) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
- .AppendASCII("incognito_no_script")));
+ .AppendASCII("incognito").AppendASCII("content_scripts")));
// Open incognito window and navigate to test page.
ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
@@ -56,21 +57,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoYesScript) {
// that loads to "modified".
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
- ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
- .AppendASCII("incognito_no_script")));
+ ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_.AppendASCII("api_test")
+ .AppendASCII("incognito").AppendASCII("content_scripts")));
// Dummy extension #2.
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
.AppendASCII("content_scripts").AppendASCII("isolated_world1")));
- // Now enable the incognito_no_script extension in incognito mode, and ensure
- // that page titles are modified.
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
- service->extension_prefs()->SetIsIncognitoEnabled(
- service->extensions()->at(1)->id(), true);
- browser()->profile()->GetUserScriptMaster()->ReloadExtensionForTesting(
- service->extensions()->at(1));
-
// Open incognito window and navigate to test page.
ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
GURL("http://www.example.com:1337/files/extensions/test_file.html"));
@@ -86,3 +79,66 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoYesScript) {
&result);
EXPECT_TRUE(result);
}
+
+// Tests that the APIs in an incognito-enabled extension work properly.
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Incognito) {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ StartHTTPServer();
+
+ ResultCatcher catcher;
+
+ // Open incognito window and navigate to test page.
+ ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
+ GURL("http://www.example.com:1337/files/extensions/test_file.html"));
+
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalExtensionApis);
+ ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
+ .AppendASCII("incognito").AppendASCII("apis")));
+
+ EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
+// Tests that the APIs in an incognito-disabled extension don't see incognito
+// events or callbacks.
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoDisabled) {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ StartHTTPServer();
+
+ ResultCatcher catcher;
+
+ // Open incognito window and navigate to test page.
+ ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
+ GURL("http://www.example.com:1337/files/extensions/test_file.html"));
+
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalExtensionApis);
+ ASSERT_TRUE(LoadExtension(test_data_dir_
+ .AppendASCII("incognito").AppendASCII("apis_disabled")));
+
+ EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
+// Test that opening a popup from an incognito browser window works properly.
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoPopup) {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ StartHTTPServer();
+
+ ResultCatcher catcher;
+
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalExtensionApis);
+ ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
+ .AppendASCII("incognito").AppendASCII("popup")));
+
+ // Open incognito window and navigate to test page.
+ ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
+ GURL("http://www.example.com:1337/files/extensions/test_file.html"));
+ Browser* incognito_browser = BrowserList::FindBrowserWithType(
+ browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL);
+
+ // Simulate the incognito's browser action being clicked.
+ BrowserActionTestUtil(incognito_browser).Press(0);
+
+ EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc
index 9339196..dd464ea 100644
--- a/chrome/browser/extensions/extension_message_service.cc
+++ b/chrome/browser/extensions/extension_message_service.cc
@@ -92,10 +92,12 @@ static void DispatchOnMessage(const ExtensionMessageService::MessagePort& port,
static void DispatchEvent(const ExtensionMessageService::MessagePort& port,
const std::string& event_name,
- const std::string& event_args) {
+ const std::string& event_args,
+ bool has_incognito_data) {
ListValue args;
args.Set(0, Value::CreateStringValue(event_name));
args.Set(1, Value::CreateStringValue(event_args));
+ args.Set(2, Value::CreateBooleanValue(has_incognito_data));
port.sender->Send(new ViewMsg_ExtensionMessageInvoke(
port.routing_id, ExtensionMessageService::kDispatchEvent, args));
}
@@ -283,7 +285,7 @@ void ExtensionMessageService::OpenChannelToTabOnUIThread(
TabContents* contents = NULL;
MessagePort receiver;
receiver.debug_info = 2;
- if (ExtensionTabUtil::GetTabById(tab_id, source->profile(),
+ if (ExtensionTabUtil::GetTabById(tab_id, source->profile(), true,
NULL, NULL, &contents, NULL)) {
receiver.sender = contents->render_view_host();
receiver.routing_id = contents->render_view_host()->routing_id();
@@ -451,7 +453,8 @@ void ExtensionMessageService::PostMessageFromRenderer(
}
void ExtensionMessageService::DispatchEventToRenderers(
- const std::string& event_name, const std::string& event_args) {
+ const std::string& event_name, const std::string& event_args,
+ bool has_incognito_data) {
DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
std::set<int>& pids = listeners_[event_name];
@@ -467,7 +470,7 @@ void ExtensionMessageService::DispatchEventToRenderers(
continue;
}
- DispatchEvent(renderer, event_name, event_args);
+ DispatchEvent(renderer, event_name, event_args, has_incognito_data);
}
}
diff --git a/chrome/browser/extensions/extension_message_service.h b/chrome/browser/extensions/extension_message_service.h
index b04780c..6b8ade6 100644
--- a/chrome/browser/extensions/extension_message_service.h
+++ b/chrome/browser/extensions/extension_message_service.h
@@ -82,7 +82,8 @@ class ExtensionMessageService
// Send an event to every registered extension renderer.
void DispatchEventToRenderers(
- const std::string& event_name, const std::string& event_args);
+ const std::string& event_name, const std::string& event_args,
+ bool has_incognito_data);
// Given an extension ID, opens a channel between the given
// automation "port" or DevTools service and that extension. the
diff --git a/chrome/browser/extensions/extension_page_actions_module.cc b/chrome/browser/extensions/extension_page_actions_module.cc
index 1379b2f..5fcbf45 100644
--- a/chrome/browser/extensions/extension_page_actions_module.cc
+++ b/chrome/browser/extensions/extension_page_actions_module.cc
@@ -70,7 +70,8 @@ bool PageActionFunction::SetPageActionEnabled(bool enable) {
// Find the TabContents that contains this tab id.
TabContents* contents = NULL;
- ExtensionTabUtil::GetTabById(tab_id, profile(), NULL, NULL, &contents, NULL);
+ ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(),
+ NULL, NULL, &contents, NULL);
if (!contents) {
error_ = ExtensionErrorUtils::FormatErrorMessage(kNoTabError,
IntToString(tab_id));
@@ -102,7 +103,8 @@ bool PageActionFunction::InitCommon(int tab_id) {
// Find the TabContents that contains this tab id.
contents_ = NULL;
- ExtensionTabUtil::GetTabById(tab_id, profile(), NULL, NULL, &contents_, NULL);
+ ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(),
+ NULL, NULL, &contents_, NULL);
if (!contents_) {
error_ = ExtensionErrorUtils::FormatErrorMessage(kNoTabError,
IntToString(tab_id));
diff --git a/chrome/browser/extensions/extension_popup_api.cc b/chrome/browser/extensions/extension_popup_api.cc
index 48e414c..d6edbc0 100644
--- a/chrome/browser/extensions/extension_popup_api.cc
+++ b/chrome/browser/extensions/extension_popup_api.cc
@@ -155,7 +155,7 @@ bool PopupShowFunction::RunImpl() {
BubbleBorder::ArrowLocation arrow_location =
(NULL != dispatcher()->GetExtensionHost()) ? BubbleBorder::BOTTOM_LEFT :
BubbleBorder::TOP_LEFT;
- popup_ = ExtensionPopup::Show(url, dispatcher()->GetBrowser(),
+ popup_ = ExtensionPopup::Show(url, GetBrowser(),
dispatcher()->profile(),
dispatcher()->GetFrameNativeWindow(),
rect,
@@ -238,5 +238,6 @@ void PopupEventRouter::OnPopupClosed(Profile* profile,
profile->GetExtensionMessageService()->DispatchEventToRenderers(
full_event_name,
- base::JSONWriter::kEmptyArray);
+ base::JSONWriter::kEmptyArray,
+ profile->IsOffTheRecord());
}
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc
index 3121d3c..7ecee27 100644
--- a/chrome/browser/extensions/extension_process_manager.cc
+++ b/chrome/browser/extensions/extension_process_manager.cc
@@ -232,6 +232,19 @@ void ExtensionProcessManager::Observe(NotificationType type,
break;
}
+ case NotificationType::EXTENSION_INCOGNITO_CHANGED: {
+ Extension* extension =
+ Details<std::pair<Extension*, bool> >(details).ptr()->first;
+ bool incognito_enabled =
+ Details<std::pair<Extension*, bool> >(details).ptr()->second;
+ RenderProcessHost* rph = GetExtensionProcess(extension->id());
+ if (rph) {
+ rph->Send(new ViewMsg_Extension_ExtensionSetIncognitoEnabled(
+ extension->id(), incognito_enabled));
+ }
+ break;
+ }
+
case NotificationType::EXTENSION_HOST_DESTROYED: {
ExtensionHost* host = Details<ExtensionHost>(details).ptr();
all_hosts_.erase(host);
diff --git a/chrome/browser/extensions/extension_processes_api.cc b/chrome/browser/extensions/extension_processes_api.cc
index 8495d9d..fda8c7f 100644
--- a/chrome/browser/extensions/extension_processes_api.cc
+++ b/chrome/browser/extensions/extension_processes_api.cc
@@ -24,8 +24,8 @@ bool GetProcessForTabFunction::RunImpl() {
TabContents* contents = NULL;
int tab_index = -1;
- if (!ExtensionTabUtil::GetTabById(tab_id, profile(), NULL, NULL,
- &contents, &tab_index))
+ if (!ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(),
+ NULL, NULL, &contents, &tab_index))
return false;
int process_id = contents->GetRenderProcessHost()->id();
diff --git a/chrome/browser/extensions/extension_protocols.cc b/chrome/browser/extensions/extension_protocols.cc
index 21dcd12..b6e66f6 100644
--- a/chrome/browser/extensions/extension_protocols.cc
+++ b/chrome/browser/extensions/extension_protocols.cc
@@ -6,12 +6,16 @@
#include "base/string_util.h"
#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/url_util.h"
+#include "net/base/net_errors.h"
#include "net/url_request/url_request_file_job.h"
+#include "net/url_request/url_request_error_job.h"
// Factory registered with URLRequest to create URLRequestJobs for extension://
// URLs.
@@ -20,6 +24,16 @@ static URLRequestJob* CreateExtensionURLRequestJob(URLRequest* request,
ChromeURLRequestContext* context =
static_cast<ChromeURLRequestContext*>(request->context());
+ // Don't allow toplevel navigations to extension resources in incognito mode.
+ // This is because an extension must run in a single process, and an incognito
+ // tab prevents that.
+ // TODO(mpcomplete): better error code.
+ const ResourceDispatcherHostRequestInfo* info =
+ ResourceDispatcherHost::InfoForRequest(request);
+ if (context->is_off_the_record() &&
+ info && info->resource_type() == ResourceType::MAIN_FRAME)
+ return new URLRequestErrorJob(request, net::ERR_ADDRESS_UNREACHABLE);
+
// chrome-extension://extension-id/resource/path.js
FilePath directory_path = context->GetPathForExtension(request->url().host());
if (directory_path.value().empty()) {
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index e00964d..c602cf6 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -36,11 +36,14 @@ namespace keys = extension_tabs_module_constants;
// message if the window cannot be found by id.
static Browser* GetBrowserInProfileWithId(Profile* profile,
const int window_id,
+ bool include_incognito,
std::string* error_message);
-// |error_message| can optionally be passed in a will be set with an appropriate
-// message if the tab cannot be found by id.
-static bool GetTabById(int tab_id, Profile* profile, Browser** browser,
+// |error_message| can optionally be passed in and will be set with an
+// appropriate message if the tab cannot be found by id.
+static bool GetTabById(int tab_id, Profile* profile,
+ bool include_incognito,
+ Browser** browser,
TabStripModel** tab_strip,
TabContents** contents,
int* tab_index, std::string* error_message);
@@ -117,6 +120,8 @@ DictionaryValue* ExtensionTabUtil::CreateTabValue(
result->SetBoolean(keys::kSelectedKey,
tab_strip && tab_index == tab_strip->selected_index());
result->SetString(keys::kTitleKey, UTF16ToWide(contents->GetTitle()));
+ result->SetBoolean(keys::kIncognitoKey,
+ contents->profile()->IsOffTheRecord());
if (status != TAB_LOADING) {
NavigationEntry* entry = contents->controller().GetActiveEntry();
@@ -140,6 +145,8 @@ DictionaryValue* ExtensionTabUtil::CreateWindowValue(const Browser* browser,
if (browser->window())
focused = browser->window()->IsActive();
+ result->SetBoolean(keys::kIncognitoKey,
+ browser->profile()->IsOffTheRecord());
result->SetBoolean(keys::kFocusedKey, focused);
gfx::Rect bounds = browser->window()->GetRestoredBounds();
@@ -173,6 +180,7 @@ bool ExtensionTabUtil::GetDefaultTab(Browser* browser, TabContents** contents,
}
bool ExtensionTabUtil::GetTabById(int tab_id, Profile* profile,
+ bool include_incognito,
Browser** browser,
TabStripModel** tab_strip,
TabContents** contents,
@@ -180,10 +188,13 @@ bool ExtensionTabUtil::GetTabById(int tab_id, Profile* profile,
Browser* target_browser;
TabStripModel* target_tab_strip;
TabContents* target_contents;
+ Profile* incognito_profile =
+ include_incognito ? profile->GetOffTheRecordProfile() : NULL;
for (BrowserList::const_iterator iter = BrowserList::begin();
iter != BrowserList::end(); ++iter) {
target_browser = *iter;
- if (target_browser->profile() == profile) {
+ if (target_browser->profile() == profile ||
+ target_browser->profile() == incognito_profile) {
target_tab_strip = target_browser->tabstrip_model();
for (int i = 0; i < target_tab_strip->count(); ++i) {
target_contents = target_tab_strip->GetTabContentsAt(i);
@@ -210,7 +221,8 @@ bool GetWindowFunction::RunImpl() {
int window_id;
EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&window_id));
- Browser* browser = GetBrowserInProfileWithId(profile(), window_id, &error_);
+ Browser* browser = GetBrowserInProfileWithId(profile(), window_id,
+ include_incognito(), &error_);
if (!browser)
return false;
@@ -219,7 +231,7 @@ bool GetWindowFunction::RunImpl() {
}
bool GetCurrentWindowFunction::RunImpl() {
- Browser* browser = dispatcher()->GetBrowser();
+ Browser* browser = GetBrowser();
if (!browser) {
error_ = keys::kNoCurrentWindowError;
return false;
@@ -250,10 +262,13 @@ bool GetAllWindowsFunction::RunImpl() {
}
result_.reset(new ListValue());
+ Profile* incognito_profile =
+ include_incognito() ? profile()->GetOffTheRecordProfile() : NULL;
for (BrowserList::const_iterator browser = BrowserList::begin();
browser != BrowserList::end(); ++browser) {
// Only examine browsers in the current profile.
- if ((*browser)->profile() == profile()) {
+ if ((*browser)->profile() == profile() ||
+ (*browser)->profile() == incognito_profile) {
static_cast<ListValue*>(result_.get())->
Append(ExtensionTabUtil::CreateWindowValue(*browser, populate_tabs));
}
@@ -297,7 +312,7 @@ bool CreateWindowFunction::RunImpl() {
// NOTE(rafaelw): It's ok if dispatcher_->GetBrowser() returns NULL here.
// GetBrowserWindowBounds will default to saved "default" values for the app.
WindowSizer::GetBrowserWindowBounds(std::wstring(), empty_bounds,
- dispatcher()->GetBrowser(), &bounds,
+ GetBrowser(), &bounds,
&maximized);
// Any part of the bounds can optionally be set by the caller.
@@ -351,7 +366,8 @@ bool UpdateWindowFunction::RunImpl() {
DictionaryValue* update_props;
EXTENSION_FUNCTION_VALIDATE(args->GetDictionary(1, &update_props));
- Browser* browser = GetBrowserInProfileWithId(profile(), window_id, &error_);
+ Browser* browser = GetBrowserInProfileWithId(profile(), window_id,
+ include_incognito(), &error_);
if (!browser)
return false;
@@ -397,7 +413,8 @@ bool RemoveWindowFunction::RunImpl() {
int window_id;
EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&window_id));
- Browser* browser = GetBrowserInProfileWithId(profile(), window_id, &error_);
+ Browser* browser = GetBrowserInProfileWithId(profile(), window_id,
+ include_incognito(), &error_);
if (!browser)
return false;
@@ -415,9 +432,10 @@ bool GetSelectedTabFunction::RunImpl() {
if (!args_->IsType(Value::TYPE_NULL)) {
EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&window_id));
- browser = GetBrowserInProfileWithId(profile(), window_id, &error_);
+ browser = GetBrowserInProfileWithId(profile(), window_id,
+ include_incognito(), &error_);
} else {
- browser = dispatcher()->GetBrowser();
+ browser = GetBrowser();
if (!browser)
error_ = keys::kNoCurrentWindowError;
}
@@ -441,9 +459,10 @@ bool GetAllTabsInWindowFunction::RunImpl() {
int window_id = -1;
if (!args_->IsType(Value::TYPE_NULL)) {
EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&window_id));
- browser = GetBrowserInProfileWithId(profile(), window_id, &error_);
+ browser = GetBrowserInProfileWithId(profile(), window_id,
+ include_incognito(), &error_);
} else {
- browser = dispatcher()->GetBrowser();
+ browser = GetBrowser();
if (!browser)
error_ = keys::kNoCurrentWindowError;
}
@@ -465,9 +484,10 @@ bool CreateTabFunction::RunImpl() {
if (args->HasKey(keys::kWindowIdKey)) {
EXTENSION_FUNCTION_VALIDATE(args->GetInteger(
keys::kWindowIdKey, &window_id));
- browser = GetBrowserInProfileWithId(profile(), window_id, &error_);
+ browser = GetBrowserInProfileWithId(profile(), window_id,
+ include_incognito(), &error_);
} else {
- browser = dispatcher()->GetBrowser();
+ browser = GetBrowser();
if (!browser)
error_ = keys::kNoCurrentWindowError;
}
@@ -536,8 +556,8 @@ bool GetTabFunction::RunImpl() {
TabStripModel* tab_strip = NULL;
TabContents* contents = NULL;
int tab_index = -1;
- if (!GetTabById(tab_id, profile(), NULL, &tab_strip, &contents, &tab_index,
- &error_))
+ if (!GetTabById(tab_id, profile(), include_incognito(),
+ NULL, &tab_strip, &contents, &tab_index, &error_))
return false;
result_.reset(ExtensionTabUtil::CreateTabValue(contents, tab_strip,
@@ -556,8 +576,8 @@ bool UpdateTabFunction::RunImpl() {
TabStripModel* tab_strip = NULL;
TabContents* contents = NULL;
int tab_index = -1;
- if (!GetTabById(tab_id, profile(), NULL, &tab_strip, &contents, &tab_index,
- &error_))
+ if (!GetTabById(tab_id, profile(), include_incognito(),
+ NULL, &tab_strip, &contents, &tab_index, &error_))
return false;
if (tab_strip->IsTabPinned(tab_index)) {
@@ -645,8 +665,9 @@ bool MoveTabFunction::RunImpl() {
TabStripModel* source_tab_strip = NULL;
TabContents* contents = NULL;
int tab_index = -1;
- if (!GetTabById(tab_id, profile(), &source_browser, &source_tab_strip,
- &contents, &tab_index, &error_))
+ if (!GetTabById(tab_id, profile(), include_incognito(),
+ &source_browser, &source_tab_strip, &contents,
+ &tab_index, &error_))
return false;
if (update_props->HasKey(keys::kWindowIdKey)) {
@@ -655,7 +676,7 @@ bool MoveTabFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
keys::kWindowIdKey, &window_id));
target_browser = GetBrowserInProfileWithId(profile(), window_id,
- &error_);
+ include_incognito(), &error_);
if (!target_browser)
return false;
@@ -708,7 +729,8 @@ bool RemoveTabFunction::RunImpl() {
Browser* browser = NULL;
TabContents* contents = NULL;
- if (!GetTabById(tab_id, profile(), &browser, NULL, &contents, NULL, &error_))
+ if (!GetTabById(tab_id, profile(), include_incognito(),
+ &browser, NULL, &contents, NULL, &error_))
return false;
int tab_index = browser->GetIndexOfController(&contents->controller());
@@ -734,9 +756,10 @@ bool CaptureVisibleTabFunction::RunImpl() {
if (!args_->IsType(Value::TYPE_NULL)) {
EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&window_id));
- browser = GetBrowserInProfileWithId(profile(), window_id, &error_);
+ browser = GetBrowserInProfileWithId(profile(), window_id,
+ include_incognito(), &error_);
} else {
- browser = dispatcher()->GetBrowser();
+ browser = GetBrowser();
}
if (!browser) {
@@ -856,14 +879,14 @@ bool DetectTabLanguageFunction::RunImpl() {
// in the current window.
if (!args_->IsType(Value::TYPE_NULL)) {
EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&tab_id));
- if (!GetTabById(tab_id, profile(), &browser, NULL, &contents, NULL,
- &error_)) {
+ if (!GetTabById(tab_id, profile(), include_incognito(),
+ &browser, NULL, &contents, NULL, &error_)) {
return false;
}
if (!browser || !contents)
return false;
} else {
- browser = dispatcher()->GetBrowser();
+ browser = GetBrowser();
if (!browser)
return false;
contents = browser->tabstrip_model()->GetSelectedTabContents();
@@ -924,10 +947,14 @@ void DetectTabLanguageFunction::GotLanguage(const std::string& language) {
static Browser* GetBrowserInProfileWithId(Profile* profile,
const int window_id,
+ bool include_incognito,
std::string* error_message) {
+ Profile* incognito_profile =
+ include_incognito ? profile->GetOffTheRecordProfile() : NULL;
for (BrowserList::const_iterator browser = BrowserList::begin();
- browser != BrowserList::end(); ++browser) {
- if ((*browser)->profile() == profile &&
+ browser != BrowserList::end(); ++browser) {
+ if (((*browser)->profile() == profile ||
+ (*browser)->profile() == incognito_profile) &&
ExtensionTabUtil::GetWindowId(*browser) == window_id)
return *browser;
}
@@ -939,13 +966,15 @@ static Browser* GetBrowserInProfileWithId(Profile* profile,
return NULL;
}
-static bool GetTabById(int tab_id, Profile* profile, Browser** browser,
+static bool GetTabById(int tab_id, Profile* profile,
+ bool include_incognito,
+ Browser** browser,
TabStripModel** tab_strip,
TabContents** contents,
int* tab_index,
std::string* error_message) {
- if (ExtensionTabUtil::GetTabById(tab_id, profile, browser, tab_strip,
- contents, tab_index))
+ if (ExtensionTabUtil::GetTabById(tab_id, profile, include_incognito,
+ browser, tab_strip, contents, tab_index))
return true;
if (error_message)
diff --git a/chrome/browser/extensions/extension_tabs_module.h b/chrome/browser/extensions/extension_tabs_module.h
index 5282a17..c7d36f8 100644
--- a/chrome/browser/extensions/extension_tabs_module.h
+++ b/chrome/browser/extensions/extension_tabs_module.h
@@ -45,7 +45,8 @@ class ExtensionTabUtil {
int* tab_id);
// Any out parameter (|browser|, |tab_strip|, |contents|, & |tab_index|) may
// be NULL and will not be set within the function.
- static bool GetTabById(int tab_id, Profile* profile, Browser** browser,
+ static bool GetTabById(int tab_id, Profile* profile, bool incognito_enabled,
+ Browser** browser,
TabStripModel** tab_strip,
TabContents** contents,
int* tab_index);
diff --git a/chrome/browser/extensions/extension_tabs_module_constants.cc b/chrome/browser/extensions/extension_tabs_module_constants.cc
index 96176ea..6a75742 100644
--- a/chrome/browser/extensions/extension_tabs_module_constants.cc
+++ b/chrome/browser/extensions/extension_tabs_module_constants.cc
@@ -32,6 +32,7 @@ const wchar_t kTopKey[] = L"top";
const wchar_t kUrlKey[] = L"url";
const wchar_t kWidthKey[] = L"width";
const wchar_t kWindowIdKey[] = L"windowId";
+const wchar_t kIncognitoKey[] = L"incognito";
const char kStatusValueComplete[] = "complete";
const char kStatusValueLoading[] = "loading";
diff --git a/chrome/browser/extensions/extension_tabs_module_constants.h b/chrome/browser/extensions/extension_tabs_module_constants.h
index f51bc5a..9f72501 100644
--- a/chrome/browser/extensions/extension_tabs_module_constants.h
+++ b/chrome/browser/extensions/extension_tabs_module_constants.h
@@ -36,6 +36,7 @@ extern const wchar_t kTopKey[];
extern const wchar_t kUrlKey[];
extern const wchar_t kWidthKey[];
extern const wchar_t kWindowIdKey[];
+extern const wchar_t kIncognitoKey[];
// Value consts.
extern const char kStatusValueComplete[];
diff --git a/chrome/browser/extensions/extension_test_api.cc b/chrome/browser/extensions/extension_test_api.cc
index ac0a2eb..48323d4 100644
--- a/chrome/browser/extensions/extension_test_api.cc
+++ b/chrome/browser/extensions/extension_test_api.cc
@@ -2,10 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "chrome/browser/extensions/extension_test_api.h"
+
+#include "chrome/browser/browser.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/extensions_quota_service.h"
-#include "chrome/browser/extensions/extension_test_api.h"
#include "chrome/common/notification_service.h"
bool ExtensionTestPassFunction::RunImpl() {
@@ -41,3 +43,10 @@ bool ExtensionTestQuotaResetFunction::RunImpl() {
quota->violators_.clear();
return true;
}
+
+bool ExtensionTestCreateIncognitoTabFunction::RunImpl() {
+ std::string url;
+ EXTENSION_FUNCTION_VALIDATE(args_->GetAsString(&url));
+ Browser::OpenURLOffTheRecord(profile(), GURL(url));
+ return true;
+}
diff --git a/chrome/browser/extensions/extension_test_api.h b/chrome/browser/extensions/extension_test_api.h
index 3b89e53..ee62627 100644
--- a/chrome/browser/extensions/extension_test_api.h
+++ b/chrome/browser/extensions/extension_test_api.h
@@ -31,4 +31,10 @@ class ExtensionTestQuotaResetFunction : public SyncExtensionFunction {
DECLARE_EXTENSION_FUNCTION_NAME("test.resetQuota")
};
+class ExtensionTestCreateIncognitoTabFunction : public SyncExtensionFunction {
+ ~ExtensionTestCreateIncognitoTabFunction() {}
+ virtual bool RunImpl();
+ DECLARE_EXTENSION_FUNCTION_NAME("test.createIncognitoTab")
+};
+
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_API_H_
diff --git a/chrome/browser/extensions/extension_toolstrip_api.cc b/chrome/browser/extensions/extension_toolstrip_api.cc
index 18d1839..56ad0a2 100644
--- a/chrome/browser/extensions/extension_toolstrip_api.cc
+++ b/chrome/browser/extensions/extension_toolstrip_api.cc
@@ -40,7 +40,7 @@ bool ToolstripFunction::RunImpl() {
error_ = kNotAToolstripError;
return false;
}
- Browser* browser = dispatcher()->GetBrowser();
+ Browser* browser = GetBrowser();
if (!browser) {
error_ = kNotAToolstripError;
return false;
@@ -133,8 +133,8 @@ void ToolstripEventRouter::DispatchEvent(Profile *profile,
std::string json_args;
base::JSONWriter::Write(&json, false, &json_args);
std::string full_event_name = StringPrintf(event_name, routing_id);
- profile->GetExtensionMessageService()->
- DispatchEventToRenderers(full_event_name, json_args);
+ profile->GetExtensionMessageService()->DispatchEventToRenderers(
+ full_event_name, json_args, profile->IsOffTheRecord());
}
}
diff --git a/chrome/browser/extensions/extension_ui_unittest.cc b/chrome/browser/extensions/extension_ui_unittest.cc
index 4bffb44..f1bd648 100644
--- a/chrome/browser/extensions/extension_ui_unittest.cc
+++ b/chrome/browser/extensions/extension_ui_unittest.cc
@@ -50,8 +50,8 @@ namespace {
// Produce test output.
scoped_ptr<DictionaryValue> actual_output_data(
- ExtensionsDOMHandler::CreateExtensionDetailValue(&extension, pages,
- true));
+ ExtensionsDOMHandler::CreateExtensionDetailValue(NULL, &extension,
+ pages, true));
// Compare the outputs.
return expected_output_data->Equals(actual_output_data.get());
diff --git a/chrome/browser/extensions/extension_uitest.cc b/chrome/browser/extensions/extension_uitest.cc
index 8192968..5537dc4 100644
--- a/chrome/browser/extensions/extension_uitest.cc
+++ b/chrome/browser/extensions/extension_uitest.cc
@@ -218,8 +218,10 @@ public:
tab_dict.SetInteger(extension_tabs_module_constants::kIndexKey, 1);
tab_dict.SetInteger(extension_tabs_module_constants::kWindowIdKey, 1);
tab_dict.SetBoolean(extension_tabs_module_constants::kSelectedKey, true);
+ tab_dict.SetBoolean(extension_tabs_module_constants::kIncognitoKey,
+ false);
tab_dict.SetString(extension_tabs_module_constants::kUrlKey,
- "http://www.google.com");
+ "http://www.google.com");
std::string tab_json;
base::JSONWriter::Write(&tab_dict, false, &tab_json);
@@ -327,7 +329,7 @@ class ExtensionTestBrowserEvents : public ExtensionUITest {
const char* ExtensionTestBrowserEvents::events_[] = {
// Window events.
"[\"windows.onCreated\", \"[{'id':42,'focused':true,'top':0,'left':0,"
- "'width':100,'height':100}]\"]",
+ "'width':100,'height':100,'incognito':false}]\"]",
"[\"windows.onRemoved\", \"[42]\"]",
@@ -335,11 +337,11 @@ const char* ExtensionTestBrowserEvents::events_[] = {
// Tab events.
"[\"tabs.onCreated\", \"[{'id':42,'index':1,'windowId':1,"
- "'selected':true,'url':'http://www.google.com'}]\"]",
+ "'selected':true,'url':'http://www.google.com','incognito':false}]\"]",
"[\"tabs.onUpdated\", \"[42, {'status': 'complete',"
"'url':'http://www.google.com'}, {'id':42,'index':1,'windowId':1,"
- "'selected':true,'url':'http://www.google.com'}]\"]",
+ "'selected':true,'url':'http://www.google.com','incognito':false}]\"]",
"[\"tabs.onMoved\", \"[42, {'windowId':1,'fromIndex':1,'toIndex':2}]\"]",
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
index d171767..9cf2fb9 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -530,13 +530,19 @@ base::Time ExtensionsService::LastPingDay(const std::string& extension_id) {
}
bool ExtensionsService::IsIncognitoEnabled(const std::string& extension_id) {
- Extension* extension = GetExtensionById(extension_id, true);
- if (!extension)
- return false;
+ return extension_prefs_->IsIncognitoEnabled(extension_id);
+}
+
+void ExtensionsService::SetIsIncognitoEnabled(const std::string& extension_id,
+ bool enabled) {
+ Extension* extension = GetExtensionByIdInternal(extension_id, true, true);
+ extension_prefs_->SetIsIncognitoEnabled(extension_id, enabled);
- return extension_prefs_->IsIncognitoEnabled(extension_id) &&
- extension->HasApiPermission(Extension::kExperimentalPermission) &&
- extension->HasApiPermission(Extension::kIncognitoPermission);
+ std::pair<Extension*, bool> details(extension, enabled);
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_INCOGNITO_CHANGED,
+ Source<Profile>(profile_),
+ Details<std::pair<Extension*, bool> >(&details));
}
void ExtensionsService::CheckForExternalUpdates() {
diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h
index 078ac01..a95d0aa 100644
--- a/chrome/browser/extensions/extensions_service.h
+++ b/chrome/browser/extensions/extensions_service.h
@@ -106,10 +106,9 @@ class ExtensionsService
const base::Time& time);
virtual base::Time LastPingDay(const std::string& extension_id);
- // Returns true if this extension can run in an incognito window. The
- // decision is based on both user consent and the extension having the right
- // permission.
+ // Whether this extension can run in an incognito window.
bool IsIncognitoEnabled(const std::string& extension_id);
+ void SetIsIncognitoEnabled(const std::string& extension_id, bool enabled);
const FilePath& install_directory() const { return install_directory_; }
diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc
index 24dc43e..4201c17 100644
--- a/chrome/browser/extensions/extensions_ui.cc
+++ b/chrome/browser/extensions/extensions_ui.cc
@@ -31,6 +31,7 @@
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_error_reporter.h"
@@ -100,6 +101,12 @@ void ExtensionsUIHTMLSource::StartDataRequest(const std::string& path,
l10n_util::GetString(IDS_EXTENSIONS_DISABLE));
localized_strings.SetString(L"enable",
l10n_util::GetString(IDS_EXTENSIONS_ENABLE));
+ localized_strings.SetString(L"disableIncognito",
+ l10n_util::GetString(IDS_EXTENSIONS_DISABLE_INCOGNITO));
+ localized_strings.SetString(L"enableIncognito",
+ l10n_util::GetString(IDS_EXTENSIONS_ENABLE_INCOGNITO));
+ localized_strings.SetString(L"enableIncognitoWarning",
+ l10n_util::GetString(IDS_EXTENSIONS_ENABLE_INCOGNITO_WARNING));
localized_strings.SetString(L"reload",
l10n_util::GetString(IDS_EXTENSIONS_RELOAD));
localized_strings.SetString(L"uninstall",
@@ -251,6 +258,8 @@ void ExtensionsDOMHandler::RegisterMessages() {
NewCallback(this, &ExtensionsDOMHandler::HandleReloadMessage));
dom_ui_->RegisterMessageCallback("enable",
NewCallback(this, &ExtensionsDOMHandler::HandleEnableMessage));
+ dom_ui_->RegisterMessageCallback("enableIncognito",
+ NewCallback(this, &ExtensionsDOMHandler::HandleEnableIncognitoMessage));
dom_ui_->RegisterMessageCallback("uninstall",
NewCallback(this, &ExtensionsDOMHandler::HandleUninstallMessage));
dom_ui_->RegisterMessageCallback("options",
@@ -284,6 +293,7 @@ void ExtensionsDOMHandler::HandleRequestExtensionsData(const Value* value) {
// themes.
if (!(*extension)->IsTheme()) {
extensions_list->Append(CreateExtensionDetailValue(
+ extensions_service_.get(),
*extension, GetActivePagesForExtension((*extension)->id()), true));
extension_icons->push_back(PickExtensionIcon(*extension));
}
@@ -293,6 +303,7 @@ void ExtensionsDOMHandler::HandleRequestExtensionsData(const Value* value) {
extension != extensions->end(); ++extension) {
if (!(*extension)->IsTheme()) {
extensions_list->Append(CreateExtensionDetailValue(
+ extensions_service_.get(),
*extension, GetActivePagesForExtension((*extension)->id()), false));
extension_icons->push_back(PickExtensionIcon(*extension));
}
@@ -303,6 +314,10 @@ void ExtensionsDOMHandler::HandleRequestExtensionsData(const Value* value) {
->GetBoolean(prefs::kExtensionsUIDeveloperMode);
results->SetBoolean(L"developerMode", developer_mode);
+ results->SetBoolean(L"experimentalIncognito",
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalExtensionApis));
+
if (icon_loader_.get())
icon_loader_->Cancel();
@@ -402,6 +417,17 @@ void ExtensionsDOMHandler::HandleEnableMessage(const Value* value) {
}
}
+void ExtensionsDOMHandler::HandleEnableIncognitoMessage(const Value* value) {
+ CHECK(value->IsType(Value::TYPE_LIST));
+ const ListValue* list = static_cast<const ListValue*>(value);
+ CHECK(list->GetSize() == 2);
+ std::string extension_id, enable_str;
+ CHECK(list->GetString(0, &extension_id));
+ CHECK(list->GetString(1, &enable_str));
+ extensions_service_->SetIsIncognitoEnabled(extension_id,
+ (enable_str == "true"));
+}
+
void ExtensionsDOMHandler::HandleUninstallMessage(const Value* value) {
CHECK(value->IsType(Value::TYPE_LIST));
const ListValue* list = static_cast<const ListValue*>(value);
@@ -657,8 +683,8 @@ DictionaryValue* ExtensionsDOMHandler::CreateContentScriptDetailValue(
// Static
DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue(
- const Extension *extension, const std::vector<ExtensionPage>& pages,
- bool enabled) {
+ ExtensionsService* service, const Extension *extension,
+ const std::vector<ExtensionPage>& pages, bool enabled) {
DictionaryValue* extension_data = new DictionaryValue();
extension_data->SetString(L"id", extension->id());
@@ -666,6 +692,10 @@ DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue(
extension_data->SetString(L"description", extension->description());
extension_data->SetString(L"version", extension->version()->GetString());
extension_data->SetBoolean(L"enabled", enabled);
+ extension_data->SetBoolean(L"enabledIncognito",
+ service ? service->IsIncognitoEnabled(extension->id()) : false);
+ extension_data->SetBoolean(L"incognitoSafe",
+ extension->HasApiPermission(Extension::kIncognitoPermission));
extension_data->SetBoolean(L"allow_reload",
extension->location() == Extension::LOAD);
diff --git a/chrome/browser/extensions/extensions_ui.h b/chrome/browser/extensions/extensions_ui.h
index cabc5be..decdc64 100644
--- a/chrome/browser/extensions/extensions_ui.h
+++ b/chrome/browser/extensions/extensions_ui.h
@@ -106,9 +106,11 @@ class ExtensionsDOMHandler
virtual void RegisterMessages();
// Extension Detail JSON Struct for page. (static for ease of testing).
+ // Note: service can be NULL in unit tests.
static DictionaryValue* CreateExtensionDetailValue(
- const Extension *extension,
- const std::vector<ExtensionPage>&,
+ ExtensionsService* service,
+ const Extension* extension,
+ const std::vector<ExtensionPage>& pages,
bool enabled);
// ContentScript JSON Struct for page. (static for ease of testing).
@@ -143,6 +145,9 @@ class ExtensionsDOMHandler
// Callback for "enable" message.
void HandleEnableMessage(const Value* value);
+ // Callback for "enableIncognito" message.
+ void HandleEnableIncognitoMessage(const Value* value);
+
// Callback for "uninstall" message.
void HandleUninstallMessage(const Value* value);
diff --git a/chrome/browser/extensions/user_script_master.cc b/chrome/browser/extensions/user_script_master.cc
index a7d69f6..9506efd 100644
--- a/chrome/browser/extensions/user_script_master.cc
+++ b/chrome/browser/extensions/user_script_master.cc
@@ -294,6 +294,8 @@ UserScriptMaster::UserScriptMaster(const FilePath& script_dir, Profile* profile)
Source<Profile>(profile_));
registrar_.Add(this, NotificationType::EXTENSION_LOADED,
Source<Profile>(profile_));
+ registrar_.Add(this, NotificationType::EXTENSION_INCOGNITO_CHANGED,
+ Source<Profile>(profile_));
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
Source<Profile>(profile_));
}
@@ -348,6 +350,22 @@ void UserScriptMaster::Observe(NotificationType type,
StartScan();
break;
}
+ case NotificationType::EXTENSION_INCOGNITO_CHANGED: {
+ // Toggle the incognito_enabled bit for any content scripts inside the
+ // extension.
+ Extension* extension =
+ Details<std::pair<Extension*, bool> >(details).ptr()->first;
+ bool incognito_enabled =
+ Details<std::pair<Extension*, bool> >(details).ptr()->second;
+ for (UserScriptList::iterator iter = lone_scripts_.begin();
+ iter != lone_scripts_.end(); ++iter) {
+ if (iter->extension_id() == extension->id())
+ (*iter).set_incognito_enabled(incognito_enabled);
+ }
+ if (extensions_service_ready_)
+ StartScan();
+ break;
+ }
case NotificationType::EXTENSION_UNLOADED: {
// Remove any content scripts.
@@ -378,14 +396,3 @@ void UserScriptMaster::StartScan() {
script_reloader_->StartScan(user_script_dir_, lone_scripts_);
}
-
-void UserScriptMaster::ReloadExtensionForTesting(Extension* extension) {
- bool incognito_enabled = profile_->GetExtensionsService()->
- IsIncognitoEnabled(extension->id());
- for (UserScriptList::iterator iter = lone_scripts_.begin();
- iter != lone_scripts_.end(); ++iter) {
- if (iter->extension_id() == extension->id())
- (*iter).set_incognito_enabled(incognito_enabled);
- }
- StartScan();
-}
diff --git a/chrome/browser/extensions/user_script_master.h b/chrome/browser/extensions/user_script_master.h
index 19562f0..cc0b437 100644
--- a/chrome/browser/extensions/user_script_master.h
+++ b/chrome/browser/extensions/user_script_master.h
@@ -47,11 +47,6 @@ class UserScriptMaster : public base::RefCountedThreadSafe<UserScriptMaster>,
// Returns the path to the directory user scripts are stored in.
FilePath user_script_dir() const { return user_script_dir_; }
- // Note: this is only for testing. This will reload the scripts associated
- // with the given extension. This is only temporary until we get better
- // machinery in place for toggling incognito-enabled extensions.
- void ReloadExtensionForTesting(Extension* extension);
-
protected:
friend class base::RefCountedThreadSafe<UserScriptMaster>;
diff --git a/chrome/browser/resources/extensions_ui.html b/chrome/browser/resources/extensions_ui.html
index 39a6956..465fdcc 100644
--- a/chrome/browser/resources/extensions_ui.html
+++ b/chrome/browser/resources/extensions_ui.html
@@ -349,6 +349,7 @@ var extensionDataFormat = {
"description": "Extension long format description",
"version": "1.0.231",
"enabled": "true",
+ "enabledIncognito": "false",
"allow_reload": true,
"order": 1,
"options_url": "options.html",
@@ -388,6 +389,7 @@ var extensionDataFormat = {
"description": "Extension long format description",
"version": "1.0.231",
"enabled": "true",
+ "enabledIncognito": "false",
"allow_reload": false,
"order": 2,
"icon": "",
@@ -427,6 +429,9 @@ function toggleDevModeExpanded() {
chrome.send('toggleDeveloperMode', []);
}
+// Experimental flag that enables toggling an extension as incognito enabled.
+var experimentalIncognito = false;
+
/**
* Takes the |extensionsData| input argument which represents data about the
* currently installed/running extensions and populates the html jstemplate with
@@ -475,6 +480,7 @@ var rendered_once_ = false;
function returnExtensionsData(extensionsData){
domui_responded_ = true;
devModeExpanded = extensionsData.developerMode;
+ experimentalIncognito = extensionsData.experimentalIncognito;
var bodyContainer = document.getElementById('body-container');
var body = document.getElementsByTagName('body')[0];
@@ -549,6 +555,19 @@ function handleEnableExtension(node, enable) {
}
/**
+ * Handles a 'enableIncognito' or 'disableIncognito' button getting clicked.
+ */
+function handleEnableExtensionIncognito(node, enable) {
+ // Tell the C++ ExtensionDOMHandler to reload the extension.
+ if (enable && !node.incognitoSafe) {
+ if (!confirm(templateData["enableIncognitoWarning"]))
+ return;
+ }
+ chrome.send('enableIncognito', [node.extensionId, String(enable)]);
+ requestExtensionsData();
+}
+
+/**
* Handles an 'uninstall' button getting clicked.
*/
function handleUninstallExtension(node) {
@@ -815,6 +834,21 @@ function autoUpdate() {
>RELOAD</a>
<span jsdisplay="enabled && allow_reload">-</span>
<a
+ jsvalues=".extensionId:id;.enabled:enabled"
+ jsdisplay="enabled && enabledIncognito && experimentalIncognito"
+ onclick="handleEnableExtensionIncognito(this, false)"
+ href="javascript:void();"
+ i18n-content="disableIncognito"
+ >DISABLE INCOGNITO</a>
+ <a
+ jsvalues=".extensionId:id;.enabled=enabled"
+ jsdisplay="enabled && !enabledIncognito && experimentalIncognito"
+ onclick="handleEnableExtensionIncognito(this, true)"
+ href="javascript:void();"
+ i18n-content="enableIncognito"
+ >ENABLE INCOGNITO</a>
+ <span jsdisplay="enabled && experimentalIncognito">-</span>
+ <a
jsvalues=".extensionId:id"
jsdisplay="enabled"
onclick="handleEnableExtension(this, false)"
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 6a28cf8..9a506e0 100755..100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1156,6 +1156,7 @@
'browser/extensions/extension_crash_recovery_browsertest.cc',
'browser/extensions/extension_history_apitest.cc',
'browser/extensions/extension_i18n_apitest.cc',
+ 'browser/extensions/extension_incognito_apitest.cc',
'browser/extensions/extension_javascript_url_apitest.cc',
'browser/extensions/extension_management_tests.cc',
'browser/extensions/extension_messages_apitest.cc',
@@ -1167,7 +1168,6 @@
'browser/extensions/extension_toolstrip_apitest.cc',
'browser/extensions/extension_websocket_apitest.cc',
'browser/extensions/fragment_navigation_apitest.cc',
- 'browser/extensions/incognito_noscript_apitest.cc',
'browser/extensions/isolated_world_apitest.cc',
'browser/extensions/page_action_apitest.cc',
'browser/extensions/permissions_apitest.cc',
diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json
index a347888..58894e4 100755
--- a/chrome/common/extensions/api/extension_api.json
+++ b/chrome/common/extensions/api/extension_api.json
@@ -424,7 +424,8 @@
"left": {"type": "integer", "description": "The offset of the window from the left edge of the screen in pixels."},
"width": {"type": "integer", "description": "The width of the window in pixels."},
"height": {"type": "integer", "description": "The height of the window in pixels."},
- "tabs": {"type": "array", "items": { "$ref": "Tab" }, "optional": true, "description": "Array of <a href='tabs.html#type-Tab'>Tab</a> objects representing the current tabs in the window."}
+ "tabs": {"type": "array", "items": { "$ref": "Tab" }, "optional": true, "description": "Array of <a href='tabs.html#type-Tab'>Tab</a> objects representing the current tabs in the window."},
+ "incognito": {"type": "boolean", "description": "Whether the window is incognito."}
}
}
],
@@ -615,7 +616,8 @@
"url": {"type": "string", "description": "The URL the tab is displaying."},
"title": {"type": "string", "optional": true, "description": "The title of the tab. This may not be available if the tab is loading."},
"favIconUrl": {"type": "string", "optional": true, "description": "The URL of the tab's favicon. This may not be available if the tab is loading."},
- "status": {"type": "string", "optional": true, "description": "Either <em>loading</em> or <em>complete</em>."}
+ "status": {"type": "string", "optional": true, "description": "Either <em>loading</em> or <em>complete</em>."},
+ "incognito": {"type": "boolean", "description": "Whether the tab is in an incognito window."}
}
}
],
@@ -2287,6 +2289,14 @@
"parameters": [
{"type": "string", "name": "message"}
]
+ },
+ {
+ "name": "createIncognitoTab",
+ "type": "function",
+ "description": "Creates an incognito tab during internal testing. Succeeds even if the extension is not enabled in incognito mode.",
+ "parameters": [
+ {"type": "string", "name": "url"}
+ ]
}
],
"events": []
diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h
index ef3c0f9..2abe637 100644
--- a/chrome/common/notification_type.h
+++ b/chrome/common/notification_type.h
@@ -677,6 +677,10 @@ class NotificationType {
// details are an Extension*, and the source is a Profile*.
EXTENSION_UPDATE_DISABLED,
+ // Sent when an extension has been enabled/disabled in incognito. The
+ // details are std::pair<Extension*, bool>, and the source is a Profile.
+ EXTENSION_INCOGNITO_CHANGED,
+
// Sent when an extension is about to be installed so we can (in the case of
// themes) alert the user with a loading dialog. The source is the download
// manager and the details are the download url.
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 608716c..be83c9a8 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -722,6 +722,12 @@ IPC_BEGIN_MESSAGES(View)
GURL /* source extension's origin */,
std::vector<URLPattern> /* URLPatterns the extension can access */)
+ // Tell the renderer process that the given extension is enabled or disabled
+ // for incognito mode.
+ IPC_MESSAGE_CONTROL2(ViewMsg_Extension_ExtensionSetIncognitoEnabled,
+ std::string /* extension_id */,
+ bool /* enabled */)
+
// Tell the renderer process all known page action ids for a particular
// extension.
IPC_MESSAGE_CONTROL2(ViewMsg_Extension_UpdatePageActions,
diff --git a/chrome/renderer/extensions/extension_api_client_unittest.cc b/chrome/renderer/extensions/extension_api_client_unittest.cc
index 39d275f..7158a8c 100644
--- a/chrome/renderer/extensions/extension_api_client_unittest.cc
+++ b/chrome/renderer/extensions/extension_api_client_unittest.cc
@@ -80,7 +80,7 @@ TEST_F(ExtensionAPIClientTest, CallbackDispatching) {
"function callback(result) {"
" assert(typeof result == 'object', 'result not object');"
" assert(JSON.stringify(result) == '{\"id\":1,\"index\":1,\"windowId\":1,"
- "\"selected\":true,"
+ "\"selected\":true,\"incognito\":false,"
"\"url\":\"http://www.google.com/\"}',"
" 'incorrect result');"
" console.log('pass')"
@@ -103,7 +103,7 @@ TEST_F(ExtensionAPIClientTest, CallbackDispatching) {
// Now send the callback a response
ExtensionProcessBindings::HandleResponse(
callback_id, true, "{\"id\":1,\"index\":1,\"windowId\":1,\"selected\":true,"
- "\"url\":\"http://www.google.com/\"}", "");
+ "\"incognito\":false,\"url\":\"http://www.google.com/\"}", "");
// And verify that it worked
ASSERT_EQ("pass", GetConsoleMessage());
diff --git a/chrome/renderer/extensions/extension_process_bindings.cc b/chrome/renderer/extensions/extension_process_bindings.cc
index f065dd9..694c276 100644
--- a/chrome/renderer/extensions/extension_process_bindings.cc
+++ b/chrome/renderer/extensions/extension_process_bindings.cc
@@ -55,6 +55,9 @@ typedef std::map<std::string, bool> PermissionsMap;
// A map of extension ID to permissions map.
typedef std::map<std::string, PermissionsMap> ExtensionPermissionsMap;
+// A map of extension ID to whether this extension was enabled in incognito.
+typedef std::map<std::string, bool> IncognitoEnabledMap;
+
const char kExtensionName[] = "chrome/ExtensionProcessBindings";
const char* kExtensionDeps[] = {
BaseJsV8Extension::kName,
@@ -68,6 +71,7 @@ struct SingletonData {
std::set<std::string> function_names_;
PageActionIdMap page_action_ids_;
ExtensionPermissionsMap permissions_;
+ std::map<std::string, bool> incognito_enabled_map_;
};
static std::set<std::string>* GetFunctionNameSet() {
@@ -82,6 +86,10 @@ static PermissionsMap* GetPermissionsMap(const std::string& extension_id) {
return &Singleton<SingletonData>()->permissions_[extension_id];
}
+static std::map<std::string, bool>* GetIncognitoEnabledMap() {
+ return &Singleton<SingletonData>()->incognito_enabled_map_;
+}
+
static void GetActiveExtensionIDs(std::set<std::string>* extension_ids) {
ExtensionPermissionsMap& permissions =
Singleton<SingletonData>()->permissions_;
@@ -237,6 +245,8 @@ class ExtensionImpl : public ExtensionBase {
return v8::FunctionTemplate::New(GetPopupParentWindow);
} else if (name->Equals(v8::String::New("SetExtensionActionIcon"))) {
return v8::FunctionTemplate::New(SetExtensionActionIcon);
+ } else if (name->Equals(v8::String::New("CanAccessIncognito"))) {
+ return v8::FunctionTemplate::New(CanAccessIncognito);
}
return ExtensionBase::GetNativeFunction(name);
@@ -495,6 +505,16 @@ class ExtensionImpl : public ExtensionBase {
return StartRequestCommon(args, dict);
}
+ // Returns true if the extension can access incognito data.
+ static v8::Handle<v8::Value> CanAccessIncognito(const v8::Arguments& args) {
+ std::string extension_id = ExtensionIdForCurrentContext();
+ if (extension_id.empty())
+ return v8::False();
+
+ bool enabled = (*GetIncognitoEnabledMap())[extension_id];
+ return v8::Boolean::New(enabled);
+ }
+
static v8::Handle<v8::Value> GetRenderViewId(const v8::Arguments& args) {
RenderView* renderview = bindings_utils::GetRenderViewForCurrentContext();
if (!renderview)
@@ -520,6 +540,11 @@ void ExtensionProcessBindings::SetFunctionNames(
ExtensionImpl::SetFunctionNames(names);
}
+void ExtensionProcessBindings::SetIncognitoEnabled(
+ const std::string& extension_id, bool enabled) {
+ (*GetIncognitoEnabledMap())[extension_id] = enabled;
+}
+
// static
void ExtensionProcessBindings::HandleResponse(int request_id, bool success,
const std::string& response,
diff --git a/chrome/renderer/extensions/extension_process_bindings.h b/chrome/renderer/extensions/extension_process_bindings.h
index 2fd7613..93c7d24 100644
--- a/chrome/renderer/extensions/extension_process_bindings.h
+++ b/chrome/renderer/extensions/extension_process_bindings.h
@@ -46,6 +46,10 @@ class ExtensionProcessBindings {
static void SetHostPermissions(const GURL& extension_url,
const std::vector<URLPattern>& permissions);
+ // Sets whether incognito is enabled for a particular extension.
+ static void SetIncognitoEnabled(const std::string& extension_id,
+ bool enabled);
+
// Check if the extension in the currently running context has permission to
// access the given extension function. Must be called with a valid V8
// context in scope.
diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc
index cc622b1..30c56fd 100644
--- a/chrome/renderer/render_thread.cc
+++ b/chrome/renderer/render_thread.cc
@@ -457,6 +457,11 @@ void RenderThread::OnExtensionSetHostPermissions(
ExtensionProcessBindings::SetHostPermissions(extension_url, permissions);
}
+void RenderThread::OnExtensionSetIncognitoEnabled(
+ const std::string& extension_id, bool enabled) {
+ ExtensionProcessBindings::SetIncognitoEnabled(extension_id, enabled);
+}
+
void RenderThread::OnDOMStorageEvent(
const ViewMsg_DOMStorageEvent_Params& params) {
if (!dom_storage_event_dispatcher_.get())
@@ -511,6 +516,8 @@ void RenderThread::OnControlMessageReceived(const IPC::Message& msg) {
OnExtensionSetAPIPermissions)
IPC_MESSAGE_HANDLER(ViewMsg_Extension_SetHostPermissions,
OnExtensionSetHostPermissions)
+ IPC_MESSAGE_HANDLER(ViewMsg_Extension_ExtensionSetIncognitoEnabled,
+ OnExtensionSetIncognitoEnabled)
IPC_MESSAGE_HANDLER(ViewMsg_DOMStorageEvent,
OnDOMStorageEvent)
#if defined(IPC_MESSAGE_LOG_ENABLED)
diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h
index fb99d74..a7ad1fb 100644
--- a/chrome/renderer/render_thread.h
+++ b/chrome/renderer/render_thread.h
@@ -180,6 +180,9 @@ class RenderThread : public RenderThreadBase,
void OnExtensionSetHostPermissions(
const GURL& extension_url,
const std::vector<URLPattern>& permissions);
+ void OnExtensionSetIncognitoEnabled(
+ const std::string& extension_id,
+ bool enabled);
void OnSetNextPageID(int32 next_page_id);
void OnSetCSSColors(const std::vector<CSSColors::CSSColorMapping>& colors);
void OnCreateNewView(const ViewMsg_New_Params& params);
diff --git a/chrome/renderer/resources/event_bindings.js b/chrome/renderer/resources/event_bindings.js
index aaea01c..7ea6bbf 100644
--- a/chrome/renderer/resources/event_bindings.js
+++ b/chrome/renderer/resources/event_bindings.js
@@ -45,12 +45,20 @@ var chrome = chrome || {};
// An array of all attached event objects, used for detaching on unload.
var allAttachedEvents = [];
+ // By default (for content scripts), this function returns false. Extension
+ // contexts override this to do the right thing.
+ chromeHidden.canAccessIncognito = function() {
+ return false;
+ }
+
chromeHidden.Event = {};
// Dispatches a named event with the given JSON array, which is deserialized
// before dispatch. The JSON array is the list of arguments that will be
// sent with the event callback.
- chromeHidden.Event.dispatchJSON = function(name, args) {
+ chromeHidden.Event.dispatchJSON = function(name, args, hasIncognitoData) {
+ if (hasIncognitoData && !chromeHidden.canAccessIncognito())
+ return;
if (attachedNamedEvents[name]) {
if (args) {
args = JSON.parse(args);
diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js
index f543366..e91fe27 100644
--- a/chrome/renderer/resources/extension_process_bindings.js
+++ b/chrome/renderer/resources/extension_process_bindings.js
@@ -18,12 +18,17 @@ var chrome = chrome || {};
native function GetPopupParentWindow();
native function GetPopupView();
native function SetExtensionActionIcon();
+ native function CanAccessIncognito();
if (!chrome)
chrome = {};
var chromeHidden = GetChromeHidden();
+ chromeHidden.canAccessIncognito = function() {
+ return CanAccessIncognito();
+ }
+
// Validate arguments.
chromeHidden.validationTypes = [];
chromeHidden.validate = function(args, schemas) {
diff --git a/chrome/test/data/extensions/api_test/incognito/apis/background.html b/chrome/test/data/extensions/api_test/incognito/apis/background.html
new file mode 100644
index 0000000..ff13197
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/incognito/apis/background.html
@@ -0,0 +1,76 @@
+<script>
+var normalWindow, normalTab;
+var incognitoWindow, incognitoTab;
+
+var pass = chrome.test.callbackPass;
+var assertEq = chrome.test.assertEq;
+var assertTrue = chrome.test.assertTrue;
+
+chrome.test.runTests([
+ function setupWindows() {
+ // The test harness should have set us up with 2 windows: 1 incognito
+ // and 1 regular. Verify that we can see both when we ask for it.
+ chrome.windows.getAll({populate: true}, pass(function(windows) {
+ assertEq(2, windows.length);
+
+ if (windows[0].incognito) {
+ incognitoWindow = windows[0];
+ normalWindow = windows[1];
+ } else {
+ normalWindow = windows[0];
+ incognitoWindow = windows[1];
+ }
+ normalTab = normalWindow.tabs[0];
+ incognitoTab = incognitoWindow.tabs[0];
+ assertTrue(!normalWindow.incognito);
+ assertTrue(incognitoWindow.incognito);
+ }));
+ },
+
+ // Tests that we can update an incognito tab and get the event for it.
+ function tabUpdate() {
+ var newUrl = "about:blank";
+
+ // Prepare the event listeners first.
+ var done = chrome.test.listenForever(chrome.tabs.onUpdated,
+ function(id, info, tab) {
+ if (id == incognitoTab.id) {
+ assertTrue(tab.incognito);
+ assertEq(newUrl, tab.url);
+ if (info.status == "complete")
+ done();
+ }
+ });
+
+ // Update our tabs.
+ chrome.tabs.update(incognitoTab.id, {"url": newUrl}, pass());
+ },
+
+ // Tests a sequence of tab API calls.
+ function tabNested() {
+ // Setup our listeners. We check that the events fire in order.
+ var eventCounter = 0;
+ chrome.test.listenOnce(chrome.tabs.onCreated, function(tab) {
+ assertEq(1, ++eventCounter);
+ assertEq(incognitoTab.windowId, tab.windowId);
+ assertTrue(tab.incognito);
+ });
+ chrome.test.listenOnce(chrome.tabs.onMoved, function(tabId) {
+ assertEq(2, ++eventCounter);
+ });
+ chrome.test.listenOnce(chrome.tabs.onRemoved, function(tabId) {
+ assertEq(3, ++eventCounter);
+ });
+
+ // Create, select, move, and close a tab in our incognito window.
+ chrome.tabs.create({windowId: incognitoTab.windowId},
+ pass(function(tab) {
+ chrome.tabs.move(tab.id, {index: 0},
+ pass(function(tab) {
+ assertEq(incognitoTab.incognito, tab.incognito);
+ chrome.tabs.remove(tab.id, pass());
+ }));
+ }));
+ }
+]);
+</script>
diff --git a/chrome/test/data/extensions/api_test/incognito/apis/manifest.json b/chrome/test/data/extensions/api_test/incognito/apis/manifest.json
new file mode 100644
index 0000000..d8f6450
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/incognito/apis/manifest.json
@@ -0,0 +1,7 @@
+{
+ "name": "incognito apitest",
+ "version": "0.1",
+ "description": "test that an incognito extension behaves properly",
+ "background_page": "background.html",
+ "permissions": ["tabs", "experimental", "incognito"]
+}
diff --git a/chrome/test/data/extensions/api_test/incognito/apis_disabled/background.html b/chrome/test/data/extensions/api_test/incognito/apis_disabled/background.html
new file mode 100644
index 0000000..8e0868d
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/incognito/apis_disabled/background.html
@@ -0,0 +1,28 @@
+<script>
+var normalWindow, normalTab;
+
+var pass = chrome.test.callbackPass;
+var assertEq = chrome.test.assertEq;
+var assertTrue = chrome.test.assertTrue;
+
+chrome.test.runTests([
+ function getAllWindows() {
+ // The test harness should have set us up with 2 windows: 1 incognito
+ // and 1 regular. We should only see the regular one.
+ chrome.windows.getAll({populate: true}, pass(function(windows) {
+ assertEq(1, windows.length);
+ normalWindow = windows[0];
+ assertTrue(!normalWindow.incognito);
+ }));
+ },
+
+ function tabEvents() {
+ chrome.test.listenOnce(chrome.tabs.onCreated, function(tab) {
+ assertTrue(!tab.incognito);
+ });
+
+ chrome.test.createIncognitoTab("about:blank");
+ chrome.tabs.create({url: "about:blank"}, pass());
+ },
+]);
+</script>
diff --git a/chrome/test/data/extensions/api_test/incognito/apis_disabled/manifest.json b/chrome/test/data/extensions/api_test/incognito/apis_disabled/manifest.json
new file mode 100644
index 0000000..b26f0cb
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/incognito/apis_disabled/manifest.json
@@ -0,0 +1,7 @@
+{
+ "name": "incognito apitest",
+ "version": "0.1",
+ "description": "test that an non-incognito extension doesn't see incognito events",
+ "background_page": "background.html",
+ "permissions": ["tabs"]
+}
diff --git a/chrome/test/data/extensions/api_test/incognito_no_script/change_page_title.js b/chrome/test/data/extensions/api_test/incognito/content_scripts/change_page_title.js
index ed4cfd2..ed4cfd2 100755..100644
--- a/chrome/test/data/extensions/api_test/incognito_no_script/change_page_title.js
+++ b/chrome/test/data/extensions/api_test/incognito/content_scripts/change_page_title.js
diff --git a/chrome/test/data/extensions/api_test/incognito_no_script/manifest.json b/chrome/test/data/extensions/api_test/incognito/content_scripts/manifest.json
index e8f013c..e8f013c 100755..100644
--- a/chrome/test/data/extensions/api_test/incognito_no_script/manifest.json
+++ b/chrome/test/data/extensions/api_test/incognito/content_scripts/manifest.json
diff --git a/chrome/test/data/extensions/api_test/incognito/popup/manifest.json b/chrome/test/data/extensions/api_test/incognito/popup/manifest.json
new file mode 100644
index 0000000..c1683fe
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/incognito/popup/manifest.json
@@ -0,0 +1,9 @@
+{
+ "name": "Incognito popup tester",
+ "version": "0.1",
+ "description": "apitest for popups in incognito mode",
+ "permissions": [ "tabs", "experimental", "incognito" ],
+ "browser_action": {
+ "popup": "popup.html"
+ }
+}
diff --git a/chrome/test/data/extensions/api_test/incognito/popup/popup.html b/chrome/test/data/extensions/api_test/incognito/popup/popup.html
new file mode 100644
index 0000000..122da56
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/incognito/popup/popup.html
@@ -0,0 +1,15 @@
+<script>
+var pass = chrome.test.callbackPass;
+var assertEq = chrome.test.assertEq;
+var assertTrue = chrome.test.assertTrue;
+
+chrome.test.runTests([
+ function getCurrentWindow() {
+ // With incognito enabled, we should get our current window (which should
+ // be incognito).
+ chrome.windows.getCurrent(pass(function(win) {
+ assertTrue(win.incognito);
+ }));
+ }
+]);
+</script>
diff --git a/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension1.json b/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension1.json
index c76c336..228afc6 100644
--- a/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension1.json
+++ b/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension1.json
@@ -7,6 +7,8 @@
"permissions": ["http://*.google.com/*", "https://*.google.com/*"],
"allow_reload": false,
"order": 2,
+ "enabledIncognito": false,
+ "incognitoSafe": false,
"content_scripts": [
{
"matches": ["file://*", "http://*.google.com/*", "https://*.google.com/*"],
diff --git a/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension2.json b/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension2.json
index d6a70f5..e84e51a 100644
--- a/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension2.json
+++ b/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension2.json
@@ -7,6 +7,8 @@
"permissions": [],
"allow_reload": false,
"order": 2,
+ "enabledIncognito": false,
+ "incognitoSafe": false,
"content_scripts": [],
"views": [
{
diff --git a/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension3.json b/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension3.json
index 564053a..4a4ce6a 100644
--- a/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension3.json
+++ b/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension3.json
@@ -7,6 +7,8 @@
"permissions": [],
"allow_reload": false,
"order": 2,
+ "enabledIncognito": false,
+ "incognitoSafe": false,
"content_scripts": [],
"views": []
}