diff options
author | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-12 19:28:50 +0000 |
---|---|---|
committer | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-12 19:28:50 +0000 |
commit | 6e58a95b99e1c88172d5eae8925c8dfa39c2b765 (patch) | |
tree | 77e93bb7e93198024c36e5a6bba434b9412820ac /chrome_frame | |
parent | f24a74a242f8605d43085d6cc0cb36e5e376b2d4 (diff) | |
download | chromium_src-6e58a95b99e1c88172d5eae8925c8dfa39c2b765.zip chromium_src-6e58a95b99e1c88172d5eae8925c8dfa39c2b765.tar.gz chromium_src-6e58a95b99e1c88172d5eae8925c8dfa39c2b765.tar.bz2 |
Integrate the Ready Mode prompt with IE and Chrome Frame. In Ready Mode, prompts are displayed when the user browses to GCF-enabled sites, allowing the user to permanently activate, permanently decline, or temporarily decline Chrome Frame.
BUG=None
TEST=chrome_frame_unittests --gtest_filter=Ready* && chrome_frame_unittests --gtest_filter=Infobar* && setup.exe --chrome-frame --ready-mode --multi-install --system--level --chrome
Review URL: http://codereview.chromium.org/6040003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@71215 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame')
24 files changed, 955 insertions, 560 deletions
diff --git a/chrome_frame/bho.cc b/chrome_frame/bho.cc index f7e8129..7feb0ca 100644 --- a/chrome_frame/bho.cc +++ b/chrome_frame/bho.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -15,9 +15,11 @@ #include "chrome_tab.h" // NOLINT #include "chrome_frame/crash_reporting/crash_metrics.h" #include "chrome_frame/extra_system_apis.h" +#include "chrome_frame/html_utils.h" #include "chrome_frame/http_negotiate.h" #include "chrome_frame/metrics_service.h" #include "chrome_frame/protocol_sink_wrap.h" +#include "chrome_frame/ready_mode/ready_mode.h" #include "chrome_frame/urlmon_moniker.h" #include "chrome_frame/utils.h" #include "chrome_frame/vtable_patch_manager.h" @@ -66,6 +68,38 @@ HRESULT Bho::FinalConstruct() { void Bho::FinalRelease() { } +namespace { + +// Allows Ready Mode to disable Chrome Frame by deactivating User Agent +// modification and X-UA-Compatible header/tag detection. +class ReadyModeDelegateImpl : public ready_mode::Delegate { + public: + ReadyModeDelegateImpl() {} + + // ready_mode::Delegate implementation + virtual void DisableChromeFrame(); + + private: + DISALLOW_COPY_AND_ASSIGN(ReadyModeDelegateImpl); +}; // class ReadyModeDelegateImpl + +void SynchronizeEnablementState() { + std::string user_agent(http_utils::GetDefaultUserAgent()); + bool enabled = user_agent.find("chromeframe") != std::string::npos; + ProtocolSinkWrap::set_ignore_xua(!enabled); +} + +void ReadyModeDelegateImpl::DisableChromeFrame() { + if (GetIEVersion() != IE_9) { + SynchronizeEnablementState(); + } else { + HttpNegotiatePatch::set_modify_user_agent(false); + ProtocolSinkWrap::set_ignore_xua(true); + } +} + +} // namespace + STDMETHODIMP Bho::SetSite(IUnknown* site) { HRESULT hr = S_OK; if (site) { @@ -74,6 +108,15 @@ STDMETHODIMP Bho::SetSite(IUnknown* site) { if (web_browser2) { hr = DispEventAdvise(web_browser2, &DIID_DWebBrowserEvents2); DCHECK(SUCCEEDED(hr)) << "DispEventAdvise failed. Error: " << hr; + + ready_mode::Configure(new ReadyModeDelegateImpl(), web_browser2); + + // At this time, the user agent has been updated to reflect the Ready Mode + // state. We should make sure to modify our recognition of meta tags + // accordingly. On IE 9, another method is used to manage meta tags. + if (GetIEVersion() != IE_9) { + SynchronizeEnablementState(); + } } if (g_patch_helper.state() == PatchHelper::PATCH_IBROWSER) { diff --git a/chrome_frame/bho.h b/chrome_frame/bho.h index bae3385..d1f232d 100644 --- a/chrome_frame/bho.h +++ b/chrome_frame/bho.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -48,11 +48,11 @@ class PatchHelper { extern PatchHelper g_patch_helper; class ATL_NO_VTABLE Bho - : public CComObjectRootEx<CComSingleThreadModel>, - public CComCoClass<Bho, &CLSID_ChromeFrameBHO>, - public IObjectWithSiteImpl<Bho>, - public IDispEventSimpleImpl<0, Bho, &DIID_DWebBrowserEvents2>, - public NavigationManager { + : public CComObjectRootEx<CComSingleThreadModel>, + public CComCoClass<Bho, &CLSID_ChromeFrameBHO>, + public IObjectWithSiteImpl<Bho>, + public IDispEventSimpleImpl<0, Bho, &DIID_DWebBrowserEvents2>, + public NavigationManager { public: typedef HRESULT (STDMETHODCALLTYPE* IBrowserService_OnHttpEquiv_Fn)( IBrowserService* browser, IShellView* shell_view, BOOL done, diff --git a/chrome_frame/chrome_frame.gyp b/chrome_frame/chrome_frame.gyp index 0a25451..00785be 100644 --- a/chrome_frame/chrome_frame.gyp +++ b/chrome_frame/chrome_frame.gyp @@ -859,15 +859,17 @@ 'policy_settings.h', 'protocol_sink_wrap.cc', 'protocol_sink_wrap.h', - 'ready_mode/internal/installation_state.h', 'ready_mode/internal/ready_mode_state.h', + 'ready_mode/internal/ready_mode_web_browser_adapter.cc', + 'ready_mode/internal/ready_mode_web_browser_adapter.h', 'ready_mode/internal/ready_prompt_content.cc', 'ready_mode/internal/ready_prompt_content.h', 'ready_mode/internal/ready_prompt_window.cc', 'ready_mode/internal/ready_prompt_window.h', 'ready_mode/internal/registry_ready_mode_state.cc', 'ready_mode/internal/registry_ready_mode_state.h', - 'ready_mode/ready_mode_manager.h', + 'ready_mode/ready_mode.cc', + 'ready_mode/ready_mode.h', 'register_bho.rgs', 'stream_impl.cc', 'stream_impl.h', diff --git a/chrome_frame/chrome_frame_activex_base.h b/chrome_frame/chrome_frame_activex_base.h index 324c1f1..4f48c89 100644 --- a/chrome_frame/chrome_frame_activex_base.h +++ b/chrome_frame/chrome_frame_activex_base.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -179,8 +179,7 @@ class ATL_NO_VTABLE ChromeFrameActivexBase : // NOLINT : ready_state_(READYSTATE_UNINITIALIZED), url_fetcher_(new UrlmonUrlRequestManager()), failed_to_fetch_in_place_frame_(false), - draw_sad_tab_(false), - prev_resource_instance_(NULL) { + draw_sad_tab_(false) { m_bWindowOnly = TRUE; url_fetcher_->set_container(static_cast<IDispatch*>(this)); } @@ -248,7 +247,6 @@ END_MSG_MAP() DECLARE_PROTECT_FINAL_CONSTRUCT() void SetResourceModule() { - DCHECK(NULL == prev_resource_instance_); SimpleResourceLoader* loader_instance = SimpleResourceLoader::GetInstance(); DCHECK(loader_instance); HMODULE res_dll = loader_instance->GetResourceModuleHandle(); @@ -1283,8 +1281,6 @@ END_MSG_MAP() // Handle network requests when host network stack is used. Passed to the // automation client on initialization. scoped_ptr<UrlmonUrlRequestManager> url_fetcher_; - - HINSTANCE prev_resource_instance_; }; #endif // CHROME_FRAME_CHROME_FRAME_ACTIVEX_BASE_H_ diff --git a/chrome_frame/http_negotiate.cc b/chrome_frame/http_negotiate.cc index b593f28..370c52a 100644 --- a/chrome_frame/http_negotiate.cc +++ b/chrome_frame/http_negotiate.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -23,6 +23,7 @@ #include "net/http/http_response_headers.h" #include "net/http/http_util.h" +bool HttpNegotiatePatch::modify_user_agent_ = true; const char kUACompatibleHttpHeader[] = "x-ua-compatible"; const char kLowerCaseUserAgent[] = "user-agent"; @@ -229,10 +230,11 @@ HRESULT HttpNegotiatePatch::BeginningTransaction( DLOG(WARNING) << __FUNCTION__ << " Delegate returned an error"; return hr; } - std::string updated(AppendCFUserAgentString(headers, *additional_headers)); - *additional_headers = reinterpret_cast<wchar_t*>(::CoTaskMemRealloc( - *additional_headers, (updated.length() + 1) * sizeof(wchar_t))); - lstrcpyW(*additional_headers, ASCIIToWide(updated).c_str()); + if (modify_user_agent_) { + std::string updated(AppendCFUserAgentString(headers, *additional_headers)); + *additional_headers = reinterpret_cast<wchar_t*>(::CoTaskMemRealloc( + *additional_headers, (updated.length() + 1) * sizeof(wchar_t))); + lstrcpyW(*additional_headers, ASCIIToWide(updated).c_str()); + } return S_OK; } - diff --git a/chrome_frame/http_negotiate.h b/chrome_frame/http_negotiate.h index eb17c7f..70a3ca2 100644 --- a/chrome_frame/http_negotiate.h +++ b/chrome_frame/http_negotiate.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,9 +6,10 @@ #define CHROME_FRAME_HTTP_NEGOTIATE_H_ #include <shdeprecated.h> -#include <string> #include <urlmon.h> +#include <string> + #include "base/basictypes.h" #include "base/scoped_comptr_win.h" @@ -47,6 +48,10 @@ class HttpNegotiatePatch { static bool Initialize(); static void Uninitialize(); + // Enables and disables the User Agent header modification. It is enabled + // by default when the patch is installed. + static void set_modify_user_agent(bool value) { modify_user_agent_ = value; } + // IHttpNegotiate patch methods static STDMETHODIMP BeginningTransaction( IHttpNegotiate_BeginningTransaction_Fn original, IHttpNegotiate* me, @@ -56,6 +61,8 @@ class HttpNegotiatePatch { static HRESULT PatchHttpNegotiate(IUnknown* to_patch); private: + static bool modify_user_agent_; + DISALLOW_COPY_AND_ASSIGN(HttpNegotiatePatch); }; diff --git a/chrome_frame/infobars/internal/infobar_window.cc b/chrome_frame/infobars/internal/infobar_window.cc index 92c332a..c2964f1 100644 --- a/chrome_frame/infobars/internal/infobar_window.cc +++ b/chrome_frame/infobars/internal/infobar_window.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -23,7 +23,8 @@ const int kInfobarSlideCloseStep = 6; } // namespace void OnSliderTimer(InfobarWindow::Host* host) { - host->UpdateLayout(); + if (host) + host->UpdateLayout(); } InfobarWindow::InfobarWindow(InfobarType type) @@ -41,9 +42,10 @@ InfobarWindow::InfobarWindow(InfobarType type) } InfobarWindow::~InfobarWindow() { - StopTimer(); - if (timer_stub_ != NULL) + if (StopTimer() && timer_stub_ != NULL) FunctionStub::Destroy(timer_stub_); + else if (timer_stub_ != NULL) + timer_stub_->set_argument(NULL); // Couldn't stop it, so orphan and disable } void InfobarWindow::SetHost(Host* host) { @@ -137,6 +139,15 @@ void InfobarWindow::StartSlidingTowards(int target_height) { } bool InfobarWindow::StartTimer() { + return false; // TODO(erikwright): Diagnose and fix crashes on IE. +#if 0 + if (timer_id_ != 0) + return true; + + DCHECK(timer_stub_ != NULL); + if (timer_stub_ == NULL) + return false; + timer_id_ = ::SetTimer(NULL, timer_id_, kInfobarSlidingTimerIntervalMs, @@ -145,10 +156,20 @@ bool InfobarWindow::StartTimer() { DPLOG_IF(ERROR, timer_id_ == 0) << "Failure in SetTimer."; return timer_id_ != 0; +#endif } -void InfobarWindow::StopTimer() { - ::KillTimer(NULL, timer_id_); +bool InfobarWindow::StopTimer() { + if (timer_id_ == 0) + return true; + + if (::KillTimer(NULL, timer_id_)) { + timer_id_ = 0; + return true; + } + + DPLOG(ERROR) << "Failure in KillTimer."; + return false; } int InfobarWindow::CalculateHeight() { diff --git a/chrome_frame/infobars/internal/infobar_window.h b/chrome_frame/infobars/internal/infobar_window.h index cc81bcc..434c5cd 100644 --- a/chrome_frame/infobars/internal/infobar_window.h +++ b/chrome_frame/infobars/internal/infobar_window.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -82,7 +82,7 @@ class InfobarWindow { // Manage a timer that repeatedly calls Host::UpdateLayout bool StartTimer(); - void StopTimer(); + bool StopTimer(); scoped_ptr<InfobarContent> content_; Host* host_; diff --git a/chrome_frame/protocol_sink_wrap.cc b/chrome_frame/protocol_sink_wrap.cc index 5bae7e4..7f2e333 100644 --- a/chrome_frame/protocol_sink_wrap.cc +++ b/chrome_frame/protocol_sink_wrap.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -27,6 +27,8 @@ #define BINDSTATUS_SERVER_MIMETYPEAVAILABLE 54 #endif +bool ProtocolSinkWrap::ignore_xua_ = false; + static const char kTextHtmlMimeType[] = "text/html"; const wchar_t kUrlMonDllName[] = L"urlmon.dll"; @@ -166,6 +168,10 @@ bool ShouldWrapSink(IInternetProtocolSink* sink, const wchar_t* url) { // |url| is already normalized (i.e. no leading spaces, capital letters in // protocol etc) and non-null (we check in Hook_Start). DCHECK(url != NULL); + + if (ProtocolSinkWrap::ignore_xua()) + return false; // No need to intercept, we're ignoring X-UA-Compatible tags + if ((url != StrStrW(url, L"http://")) && (url != StrStrW(url, L"https://"))) return false; diff --git a/chrome_frame/protocol_sink_wrap.h b/chrome_frame/protocol_sink_wrap.h index 3c6897a..0f48429 100644 --- a/chrome_frame/protocol_sink_wrap.h +++ b/chrome_frame/protocol_sink_wrap.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -68,6 +68,11 @@ END_COM_MAP() static base::win::ScopedComPtr<IInternetProtocolSink> CreateNewSink( IInternetProtocolSink* sink, ProtData* prot_data); + // Enables or disables activation of Chrome Frame via the X-UA-Compatible + // header or meta tag. The tag/header is respected by default. + static void set_ignore_xua(bool ignore_xua) { ignore_xua_ = ignore_xua; } + static bool ignore_xua() { return ignore_xua_; } + // Apparently this has to be public, to satisfy COM_INTERFACE_BLIND_DELEGATE IInternetProtocolSink* delegate() { return delegate_; @@ -78,6 +83,8 @@ END_COM_MAP() ~ProtocolSinkWrap(); private: + static bool ignore_xua_; + // IInternetProtocolSink methods STDMETHOD(Switch)(PROTOCOLDATA* protocol_data); STDMETHOD(ReportProgress)(ULONG status_code, LPCWSTR status_text); @@ -170,4 +177,3 @@ struct TransactionHooks { DECLSPEC_SELECTANY struct TransactionHooks g_trans_hooks; #endif // CHROME_FRAME_PROTOCOL_SINK_WRAP_H_ - diff --git a/chrome_frame/ready_mode/internal/installation_state.h b/chrome_frame/ready_mode/internal/installation_state.h deleted file mode 100644 index 52bdfcb..0000000 --- a/chrome_frame/ready_mode/internal/installation_state.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_FRAME_READY_MODE_INTERNAL_INSTALLATION_STATE_H_ -#define CHROME_FRAME_READY_MODE_INTERNAL_INSTALLATION_STATE_H_ -#pragma once - -// Provides an interface to query and manipulate the registration and -// installation state of the product. -class InstallationState { - public: - virtual ~InstallationState() {} - - // Queries the installation state of the product (whether the product appears - // in "Add/Remove Programs" or its equivalent). - virtual bool IsProductInstalled() = 0; - - // Queries the registration state of the product (whether the COM objects, - // BHO, etc. are registered). - virtual bool IsProductRegistered() = 0; - - // Installs the product. Returns true iff successful. - virtual bool InstallProduct() = 0; - - // Unregisters the product. Fails if the product is installed. Returns true - // iff successful. - virtual bool UnregisterProduct() = 0; -}; // class InstallationState - -#endif // CHROME_FRAME_READY_MODE_INTERNAL_INSTALLATION_STATE_H_ diff --git a/chrome_frame/ready_mode/internal/ready_mode_web_browser_adapter.cc b/chrome_frame/ready_mode/internal/ready_mode_web_browser_adapter.cc new file mode 100644 index 0000000..45ff01b --- /dev/null +++ b/chrome_frame/ready_mode/internal/ready_mode_web_browser_adapter.cc @@ -0,0 +1,114 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome_frame/ready_mode/internal/ready_mode_web_browser_adapter.h" + +#include "base/logging.h" +#include "base/win/win_util.h" +#include "chrome_tab.h" // NOLINT + +_ATL_FUNC_INFO ReadyModeWebBrowserAdapter::kBeforeNavigate2Info = { + CC_STDCALL, VT_EMPTY, 7, { + VT_DISPATCH, + VT_VARIANT | VT_BYREF, + VT_VARIANT | VT_BYREF, + VT_VARIANT | VT_BYREF, + VT_VARIANT | VT_BYREF, + VT_VARIANT | VT_BYREF, + VT_BOOL | VT_BYREF + } +}; + +_ATL_FUNC_INFO ReadyModeWebBrowserAdapter::kDocumentCompleteInfo = { + CC_STDCALL, VT_EMPTY, 2, { + VT_DISPATCH, + VT_VARIANT | VT_BYREF + } +}; + +_ATL_FUNC_INFO ReadyModeWebBrowserAdapter::kOnQuitInfo = { + CC_STDCALL, VT_EMPTY, 0, {NULL}}; + +ReadyModeWebBrowserAdapter::ReadyModeWebBrowserAdapter() { +} + +bool ReadyModeWebBrowserAdapter::Initialize(IWebBrowser2* web_browser, + Observer* observer) { + base::win::ScopedComPtr<ReadyModeWebBrowserAdapter, NULL> self(this); + + DCHECK(web_browser != NULL); + DCHECK(web_browser_ == NULL); + DCHECK(observer != NULL); + DCHECK(observer_ == NULL); + + observer_.reset(observer); + + web_browser->AddRef(); + web_browser_.Attach(web_browser); + + HRESULT hr = DispEventAdvise(web_browser_, &DIID_DWebBrowserEvents2); + if (FAILED(hr)) { + observer_.reset(); + web_browser_.Release(); + DLOG(ERROR) << "DispEventAdvise failed. Error: " << hr; + } + + return SUCCEEDED(hr); +} + +void ReadyModeWebBrowserAdapter::Uninitialize() { + // DispEventUnadvise will free the WebBrowser's reference to us. In case + // that's the last reference, take a temporary reference in this function's + // scope to allow us to finish the cleanup we would otherwise like to do. + base::win::ScopedComPtr<ReadyModeWebBrowserAdapter, NULL> self(this); + + observer_.reset(); + + DCHECK(web_browser_ != NULL); + if (web_browser_ == NULL) + return; + + HRESULT hr = DispEventUnadvise(web_browser_, &DIID_DWebBrowserEvents2); + if (FAILED(hr)) { + DLOG(ERROR) << "DispEventUnadvise failed. Error: " << hr; + } else { + web_browser_.Release(); + } +} + +STDMETHODIMP_(void) ReadyModeWebBrowserAdapter::OnQuit() { + Uninitialize(); +} + +STDMETHODIMP ReadyModeWebBrowserAdapter::BeforeNavigate2( + IDispatch* /*dispatch*/, VARIANT* url, VARIANT* /*flags*/, + VARIANT* /*target_frame_name*/, VARIANT* /*post_data*/, + VARIANT* /*headers*/, VARIANT_BOOL* /*cancel*/) { + if (observer_ != NULL) + observer_->OnNavigateTo(url->bstrVal); + + return S_OK; +} + +STDMETHODIMP_(void) ReadyModeWebBrowserAdapter::DocumentComplete( + IDispatch* /*dispatch*/, VARIANT* url) { + if (!url || V_VT(url) != VT_BSTR || url->bstrVal == NULL) + return; + + if (observer_ == NULL) + return; + + base::win::ScopedComPtr<IDispatch> doc_disp; + web_browser_->get_Document(doc_disp.Receive()); + if (!doc_disp) + return; + + base::win::ScopedComPtr<IChromeFrame> chrome_frame_doc; + chrome_frame_doc.QueryFrom(doc_disp); + + if (chrome_frame_doc) + observer_->OnRenderInChromeFrame(url->bstrVal); + else + observer_->OnRenderInHost(url->bstrVal); +} diff --git a/chrome_frame/ready_mode/internal/ready_mode_web_browser_adapter.h b/chrome_frame/ready_mode/internal/ready_mode_web_browser_adapter.h new file mode 100644 index 0000000..aa362a2 --- /dev/null +++ b/chrome_frame/ready_mode/internal/ready_mode_web_browser_adapter.h @@ -0,0 +1,88 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_FRAME_READY_MODE_INTERNAL_READY_MODE_WEB_BROWSER_ADAPTER_H_ +#define CHROME_FRAME_READY_MODE_INTERNAL_READY_MODE_WEB_BROWSER_ADAPTER_H_ +#pragma once + +#include <atlbase.h> +#include <atlcom.h> +#include <exdisp.h> +#include <exdispid.h> + +#include <string> + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "base/win/scoped_comptr.h" + +// Observes navigation and rendering in an IWebBrowser2 instance and reports +// activity to an observer. +class ATL_NO_VTABLE ReadyModeWebBrowserAdapter + : public CComObjectRootEx<CComSingleThreadModel>, + public IDispEventSimpleImpl<0, ReadyModeWebBrowserAdapter, + &DIID_DWebBrowserEvents2> { + public: + // Receives notification of navigation and rendering activity in the + // IWebBrowser2 instance. + class Observer { + public: + virtual ~Observer() {} + + // Receives notification when the browser begins navigating. + virtual void OnNavigateTo(const std::wstring& url) = 0; + + // Receives notification when the browser has rendered a page in Chrome + // Frame. + virtual void OnRenderInChromeFrame(const std::wstring& url) = 0; + + // Receives notification when the browser has rendered a page in the host + // renderer. + virtual void OnRenderInHost(const std::wstring& url) = 0; + }; // class Observer + + ReadyModeWebBrowserAdapter(); + + // Begins observation of the specified IWebBrowser2 instance, reporting + // activity to the observer. Takes ownership of observer and deletes it + // either upon failure to initialize, during Uninstall(), or when the browser + // quits. + bool Initialize(IWebBrowser2* web_browser_, Observer* observer); + + // Stops observing the IWebBrowser2. + void Uninitialize(); + +DECLARE_NOT_AGGREGATABLE(ReadyModeWebBrowserAdapter) + +BEGIN_COM_MAP(ReadyModeWebBrowserAdapter) +END_COM_MAP() + +BEGIN_SINK_MAP(ReadyModeWebBrowserAdapter) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_BEFORENAVIGATE2, + BeforeNavigate2, &kBeforeNavigate2Info) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, + DocumentComplete, &kDocumentCompleteInfo) + SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_ONQUIT, + OnQuit, &kOnQuitInfo) +END_SINK_MAP() + + private: + // IWebBrowser2 event handlers + STDMETHOD(BeforeNavigate2)(IDispatch* dispatch, VARIANT* url, VARIANT* flags, + VARIANT* target_frame_name, VARIANT* post_data, VARIANT* headers, + VARIANT_BOOL* cancel); + STDMETHOD_(void, DocumentComplete)(IDispatch* dispatch, VARIANT* url); + STDMETHOD_(void, OnQuit)(); + + scoped_ptr<Observer> observer_; + base::win::ScopedComPtr<IWebBrowser2> web_browser_; + + static _ATL_FUNC_INFO kBeforeNavigate2Info; + static _ATL_FUNC_INFO kDocumentCompleteInfo; + static _ATL_FUNC_INFO kOnQuitInfo; + + DISALLOW_COPY_AND_ASSIGN(ReadyModeWebBrowserAdapter); +}; // class ReadyModeWebBrowserAdapter + +#endif // CHROME_FRAME_READY_MODE_INTERNAL_READY_MODE_WEB_BROWSER_ADAPTER_H_ diff --git a/chrome_frame/ready_mode/internal/registry_ready_mode_state.cc b/chrome_frame/ready_mode/internal/registry_ready_mode_state.cc index 8561732..244d63f5 100644 --- a/chrome_frame/ready_mode/internal/registry_ready_mode_state.cc +++ b/chrome_frame/ready_mode/internal/registry_ready_mode_state.cc @@ -1,27 +1,142 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome_frame/ready_mode/internal/registry_ready_mode_state.h" +#include <windows.h> + +#include "base/logging.h" +#include "base/process_util.h" +#include "base/string_util.h" #include "base/time.h" #include "base/task.h" #include "base/win/registry.h" -#include "chrome_frame/ready_mode/internal/installation_state.h" -#include "chrome_frame/ready_mode/ready_mode_manager.h" +#include "base/win/scoped_comptr.h" +#include "base/win/scoped_handle.h" +#include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/google_update_constants.h" +#include "chrome/installer/util/master_preferences.h" +#include "chrome/installer/util/util_constants.h" +#include "chrome_frame/ready_mode/ready_mode.h" +#include "google_update_idl.h" // NOLINT namespace { -const wchar_t kReadyModeStateValue[] = L"ReadyModeState"; +// Looks up a command entry in the registry and attempts to execute it directly. +// Returns the new process handle, which the caller is responsible for closing, +// or NULL upon failure. +HANDLE LaunchCommandDirectly(const std::wstring& command_field) { + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + std::wstring version_key_name(dist->GetVersionKey()); + + HKEY roots[] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE}; + + for (int i = 0; i < arraysize(roots); i++) { + base::win::RegKey version_key; + if (version_key.Open(roots[i], version_key_name.c_str(), KEY_QUERY_VALUE)) { + std::wstring command_line; + if (version_key.ReadValue(command_field.c_str(), &command_line)) { + HANDLE launched_process = NULL; + if (base::LaunchApp(command_line, false, true, &launched_process)) { + return launched_process; + } + } + } + } + return NULL; +} + +// Attempts to launch a command using the ProcessLauncher. Returns a handle to +// the launched process, which the caller is responsible for closing, or NULL +// upon failure. +HANDLE LaunchCommandViaProcessLauncher(const std::wstring& command_field) { + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + + base::win::ScopedComPtr<IProcessLauncher> ipl; + HRESULT hr = ipl.CreateInstance(__uuidof(ProcessLauncherClass)); + + if (FAILED(hr)) { + DLOG(ERROR) << "Failed to instantiate IProcessLauncher: " + << base::StringPrintf("0x%08x", hr); + } else { + ULONG_PTR phandle = NULL; + DWORD id = GetCurrentProcessId(); + + hr = ipl->LaunchCmdElevated(dist->GetAppGuid().c_str(), + command_field.c_str(), id, &phandle); + if (SUCCEEDED(hr)) + return reinterpret_cast<HANDLE>(phandle); + + DLOG(ERROR) << "Failed to invoke IProcessLauncher::LaunchCmdElevated: " + << base::StringPrintf("0x%08x", hr); + } + + return NULL; +} + +// Waits for the provided process to exit, and verifies that its exit code +// corresponds to one of the known "success" codes for the installer. If the +// exit code cannot be retrieved, or if it signals failure, returns false. +bool CheckProcessExitCode(HANDLE handle) { + // TODO(erikwright): Use RegisterWaitForSingleObject to wait + // asynchronously. + DWORD wait_result = WaitForSingleObject(handle, 5000); // (ms) + + if (wait_result == WAIT_OBJECT_0) { + DWORD exit_code = 0; + if (!::GetExitCodeProcess(handle, &exit_code)) { + DPLOG(ERROR) << "GetExitCodeProcess failed."; + return false; + } + + // These are the only two success codes returned by the installer. + // All other codes are errors. + if (exit_code != 0 && exit_code != installer::UNINSTALL_REQUIRES_REBOOT) { + DLOG(ERROR) << "Process failed with exit code " << exit_code << "."; + return false; + } + + return true; + } + + if (wait_result == WAIT_FAILED) + DPLOG(ERROR) << "Error while waiting for elevated child process."; + + if (wait_result == WAIT_ABANDONED) + DLOG(ERROR) << "Unexpeced WAIT_ABANDONED while waiting on child process."; -}; // namespace + if (wait_result == WAIT_TIMEOUT) + DLOG(ERROR) << "Timeout while waiting on child process."; + + return false; +} + +// Attempts to launch the specified command either directly or via the +// ProcessLauncher. Returns true if the command is launched and returns a +// success code. +bool LaunchAndCheckCommand(const std::wstring& command_field) { + base::win::ScopedHandle handle; + + handle.Set(LaunchCommandDirectly(command_field)); + if (handle.IsValid() && CheckProcessExitCode(handle)) + return true; + + handle.Set(LaunchCommandViaProcessLauncher(command_field)); + if (handle.IsValid() && CheckProcessExitCode(handle)) + return true; + + DLOG(ERROR) << "Command " << command_field << " could not be launched."; + return false; +} + +} // namespace RegistryReadyModeState::RegistryReadyModeState( const std::wstring& key_name, base::TimeDelta temporary_decline_duration, - InstallationState* installation_state, Observer* observer) + Observer* observer) : key_name_(key_name), temporary_decline_duration_(temporary_decline_duration), - installation_state_(installation_state), observer_(observer) { } @@ -33,24 +148,21 @@ base::Time RegistryReadyModeState::GetNow() { } ReadyModeStatus RegistryReadyModeState::GetStatus() { - if (installation_state_->IsProductInstalled()) - return READY_MODE_ACCEPTED; - - if (!installation_state_->IsProductRegistered()) - return READY_MODE_PERMANENTLY_DECLINED; - bool exists = false; int64 value = 0; if (!GetValue(&value, &exists)) - return READY_MODE_TEMPORARILY_DECLINED; + return READY_MODE_ACTIVE; if (!exists) - return READY_MODE_ACTIVE; + return READY_MODE_ACCEPTED; if (value == 0) return READY_MODE_PERMANENTLY_DECLINED; + if (value == 1) + return READY_MODE_ACTIVE; + base::Time when_declined(base::Time::FromInternalValue(value)); base::Time now(GetNow()); @@ -59,85 +171,83 @@ ReadyModeStatus RegistryReadyModeState::GetStatus() { bool expired = (now - when_declined) > temporary_decline_duration_ || (when_declined - now) > temporary_decline_duration_; - // To avoid a race-condition in GetValue (between ValueExists and ReadValue) - // we never delete the temporary decline flag. if (expired) - return READY_MODE_ACTIVE; + return READY_MODE_TEMPORARY_DECLINE_EXPIRED; + else + return READY_MODE_TEMPORARILY_DECLINED; +} - return READY_MODE_TEMPORARILY_DECLINED; +void RegistryReadyModeState::NotifyObserver() { + if (observer_ != NULL) + observer_->OnStateChange(GetStatus()); } bool RegistryReadyModeState::GetValue(int64* value, bool* exists) { *exists = false; *value = 0; - base::win::RegKey config_key; - if (!config_key.Open(HKEY_CURRENT_USER, key_name_.c_str(), KEY_QUERY_VALUE)) { - DLOG(ERROR) << "Failed to open registry key " << key_name_; - return false; - } - - if (!config_key.ValueExists(kReadyModeStateValue)) - return true; - - int64 temp; - DWORD value_size = sizeof(temp); - DWORD type = 0; - if (!config_key.ReadValue(kReadyModeStateValue, &temp, &value_size, &type)) { - DLOG(ERROR) << "Failed to open registry key " << key_name_; - return false; - } - - if (value_size != sizeof(temp) || type != REG_QWORD) { - DLOG(ERROR) << "Unexpected state found under registry key " << key_name_ - << " and value " << kReadyModeStateValue; - config_key.DeleteValue(kReadyModeStateValue); - return true; + HKEY roots[] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE}; + + for (int i = 0; i < arraysize(roots); i++) { + base::win::RegKey config_key; + + if (config_key.Open(roots[i], key_name_.c_str(), KEY_QUERY_VALUE)) { + if (config_key.ValueExists(installer::kChromeFrameReadyModeField)) { + int64 temp; + DWORD value_size = sizeof(temp); + DWORD type = 0; + if (!config_key.ReadValue(installer::kChromeFrameReadyModeField, + &temp, &value_size, &type)) { + DLOG(ERROR) << "Failed to read from registry key " << key_name_ + << " and value " << installer::kChromeFrameReadyModeField; + return false; + } + + if (value_size != sizeof(temp) || type != REG_QWORD) { + DLOG(ERROR) << "Unexpected state found under registry key " + << key_name_ << " and value " + << installer::kChromeFrameReadyModeField; + return false; + } + + *value = temp; + *exists = true; + return true; + } + } } - *value = temp; - *exists = true; return true; } -bool RegistryReadyModeState::StoreValue(int64 value) { - base::win::RegKey config_key; - if (config_key.Open(HKEY_CURRENT_USER, key_name_.c_str(), KEY_SET_VALUE) && - config_key.WriteValue(kReadyModeStateValue, &value, sizeof(value), - REG_QWORD)) { - return true; +void RegistryReadyModeState::RefreshStateAndNotify() { + HRESULT hr = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT_REFRESH, + NULL, 0, 0); + if (FAILED(hr)) { + DLOG(ERROR) << "Failed to refresh user agent string from registry. " + << "UrlMkSetSessionOption returned " + << base::StringPrintf("0x%08x", hr); + } else { + NotifyObserver(); } +} - DLOG(ERROR) << "Failed to open or write to registry key " << key_name_ - << " and value " << kReadyModeStateValue; - - return false; +void RegistryReadyModeState::ExpireTemporaryDecline() { + if (LaunchAndCheckCommand(google_update::kRegCFEndTempOptOutCmdField)) + RefreshStateAndNotify(); } void RegistryReadyModeState::TemporarilyDeclineChromeFrame() { - int64 value = GetNow().ToInternalValue(); - - if (StoreValue(value)) - observer_->OnStateChange(); + if (LaunchAndCheckCommand(google_update::kRegCFTempOptOutCmdField)) + RefreshStateAndNotify(); } void RegistryReadyModeState::PermanentlyDeclineChromeFrame() { - bool success = false; - - // Either change, by itself, will deactivate Ready Mode, though we prefer to - // also unregister, in order to free up resources. - - if (StoreValue(0)) - success = true; - - if (installation_state_->UnregisterProduct()) - success = true; - - if (success) - observer_->OnStateChange(); + if (LaunchAndCheckCommand(google_update::kRegCFOptOutCmdField)) + RefreshStateAndNotify(); } void RegistryReadyModeState::AcceptChromeFrame() { - if (installation_state_->InstallProduct()) - observer_->OnStateChange(); + if (LaunchAndCheckCommand(google_update::kRegCFOptInCmdField)) + NotifyObserver(); } diff --git a/chrome_frame/ready_mode/internal/registry_ready_mode_state.h b/chrome_frame/ready_mode/internal/registry_ready_mode_state.h index 54f44e3..e605d1c 100644 --- a/chrome_frame/ready_mode/internal/registry_ready_mode_state.h +++ b/chrome_frame/ready_mode/internal/registry_ready_mode_state.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,14 +13,19 @@ #include "base/time.h" #include "chrome_frame/ready_mode/internal/ready_mode_state.h" -enum ReadyModeStatus; - class InstallationState; class Task; -// Implements ReadyModeState, storing state in the Registry and delegating to an -// instance of InstallationState to interact with the installer. Notifies a -// single Observer when the state changes. +enum ReadyModeStatus { + READY_MODE_PERMANENTLY_DECLINED, + READY_MODE_TEMPORARILY_DECLINED, + READY_MODE_TEMPORARY_DECLINE_EXPIRED, + READY_MODE_ACTIVE, + READY_MODE_ACCEPTED +}; // enum ReadyModeStatus + +// Implements ReadyModeState, reading state from the Registry and delegating to +// an elevated process launcher to effect state changes. class RegistryReadyModeState : public ReadyModeState { public: // Receives notification when the Ready Mode state changes in response to a @@ -29,25 +34,27 @@ class RegistryReadyModeState : public ReadyModeState { class Observer { public: virtual ~Observer() {} - // Indicates that a state change has occurred. - virtual void OnStateChange() = 0; + // Indicates that a state change has occurred, passing the new status. + virtual void OnStateChange(ReadyModeStatus status) = 0; }; // class Observer - // Construct an instance backed by the specified key - // (pre-existing under HKCU). The provided duration indicates how long, after - // a temporary decline, Ready Mode re-activates. + // Construct an instance backed by the specified key (pre-existing under + // HKCU or HKLM). The provided duration indicates how long, after a temporary + // decline, Ready Mode re-activates. // - // Takes ownership of the Observer and InstallationState instances. + // Takes ownership of the Observer instance, which may be null if the client + // does not need to be notified of changes. RegistryReadyModeState(const std::wstring& key_name, base::TimeDelta temporary_decline_duration, - InstallationState* installation_state, Observer* observer); virtual ~RegistryReadyModeState(); - // Returns the current Ready Mode status, as determined using our registry - // state and InstallationState instance. + // Returns the current Ready Mode status. ReadyModeStatus GetStatus(); + // Transitions from temporarily declined to active Ready Mode. + void ExpireTemporaryDecline(); + // ReadyModeState implementation virtual void TemporarilyDeclineChromeFrame(); virtual void PermanentlyDeclineChromeFrame(); @@ -58,16 +65,18 @@ class RegistryReadyModeState : public ReadyModeState { virtual base::Time GetNow(); private: + // Sends the result of GetStatus() to our observer. + void NotifyObserver(); // Retrieves state from the registry. Returns true upon success. bool GetValue(int64* value, bool* exists); - // Stores value in the registry. Returns true upon success. - bool StoreValue(int64 value); + // Refreshes the process state after mutating installation state. + void RefreshStateAndNotify(); base::TimeDelta temporary_decline_duration_; - int temporary_decline_length_seconds_; std::wstring key_name_; - scoped_ptr<InstallationState> installation_state_; scoped_ptr<Observer> observer_; + + DISALLOW_COPY_AND_ASSIGN(RegistryReadyModeState); }; // class RegistryReadyModeState #endif // CHROME_FRAME_READY_MODE_INTERNAL_REGISTRY_READY_MODE_STATE_H_ diff --git a/chrome_frame/ready_mode/ready_mode.cc b/chrome_frame/ready_mode/ready_mode.cc new file mode 100644 index 0000000..82b5d23 --- /dev/null +++ b/chrome_frame/ready_mode/ready_mode.cc @@ -0,0 +1,362 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome_frame/ready_mode/ready_mode.h" + +#include <atlbase.h> +#include <shlguid.h> + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/linked_ptr.h" +#include "base/scoped_ptr.h" +#include "base/weak_ptr.h" +#include "base/win/scoped_bstr.h" +#include "base/win/scoped_comptr.h" +#include "base/win/win_util.h" +#include "net/base/registry_controlled_domain.h" +#include "chrome/installer/util/package_properties.h" +#include "chrome_frame/infobars/infobar_manager.h" +#include "chrome_frame/ready_mode/internal/ready_mode_web_browser_adapter.h" +#include "chrome_frame/ready_mode/internal/ready_prompt_content.h" +#include "chrome_frame/ready_mode/internal/registry_ready_mode_state.h" +#include "chrome_frame/utils.h" + +namespace { + +// Temporarily disable Ready Mode for 36 hours when the user so indicates. +const int kTemporaryDeclineDurationMinutes = 60 * 36; + +class BrowserObserver; + +// A helper for BrowserObserver to observe the user's choice in the Ready Mode +// prompt. +class StateObserver : public RegistryReadyModeState::Observer { + public: + explicit StateObserver(const base::WeakPtr<BrowserObserver>& ready_mode_ui); + ~StateObserver(); + + // RegistryReadyModeState::Observer implementation + virtual void OnStateChange(ReadyModeStatus status); + + private: + base::WeakPtr<BrowserObserver> ready_mode_ui_; + + DISALLOW_COPY_AND_ASSIGN(StateObserver); +}; // class StateObserver + +// Manages the Ready Mode UI in response to browsing ChromeFrame- or Host- +// rendered pages. Shows the Ready Mode prompt when the user browses to a GCF- +// enabled page. Hides the prompt when the user begins navigating to a new +// domain or when they navigate to a new page in the same domain that is not +// GCF enabled. +// +// Uses InstallerAdapter and RegistryReadyMode to query and update the +// installation state. Uninstalls the ReadyModeWebBrowserAdapter when the user +// temporarily or permanently exits Ready Mode (decline or accept Chrome Frame). +// If the user declines Chrome Frame, the current page is reloaded in the Host +// renderer. +class BrowserObserver : public ReadyModeWebBrowserAdapter::Observer { + public: + BrowserObserver(ready_mode::Delegate* chrome_frame, + IWebBrowser2* web_browser, + ReadyModeWebBrowserAdapter* adapter); + + // ReadyModeWebBrowserAdapter::Observer implementation + virtual void OnNavigateTo(const std::wstring& url); + virtual void OnRenderInChromeFrame(const std::wstring& url); + virtual void OnRenderInHost(const std::wstring& url); + + private: + friend class StateObserver; + + // Called by the StateObserver + void OnReadyModeDisabled(); + void OnReadyModeAccepted(); + + // Helpers for showing infobar prompts + void ShowPrompt(); + void Hide(); + InfobarManager* GetInfobarManager(); + + GURL rendered_url_; + linked_ptr<ready_mode::Delegate> chrome_frame_; + base::win::ScopedComPtr<IWebBrowser2> web_browser_; + // The adapter owns us, so we use a weak reference + ReadyModeWebBrowserAdapter* adapter_; + base::WeakPtrFactory<BrowserObserver> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(BrowserObserver); +}; // class BrowserObserver + +StateObserver::StateObserver( + const base::WeakPtr<BrowserObserver>& ready_mode_ui) + : ready_mode_ui_(ready_mode_ui) { +} + +StateObserver::~StateObserver() { +} + +void StateObserver::OnStateChange(ReadyModeStatus status) { + if (ready_mode_ui_ == NULL) + return; + + switch (status) { + case READY_MODE_PERMANENTLY_DECLINED: + case READY_MODE_TEMPORARILY_DECLINED: + ready_mode_ui_->OnReadyModeDisabled(); + break; + + case READY_MODE_ACCEPTED: + ready_mode_ui_->OnReadyModeAccepted(); + break; + + case READY_MODE_ACTIVE: + break; + + default: + NOTREACHED(); + break; + } +} + +BrowserObserver::BrowserObserver(ready_mode::Delegate* chrome_frame, + IWebBrowser2* web_browser, + ReadyModeWebBrowserAdapter* adapter) + : web_browser_(web_browser), + chrome_frame_(chrome_frame), + adapter_(adapter), + weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { +} + +void BrowserObserver::OnNavigateTo(const std::wstring& url) { + if (!net::RegistryControlledDomainService:: + SameDomainOrHost(GURL(url), rendered_url_)) { + rendered_url_ = GURL(); + Hide(); + } +} + +void BrowserObserver::OnRenderInChromeFrame(const std::wstring& url) { + ShowPrompt(); + rendered_url_ = GURL(url); +} + +void BrowserObserver::OnRenderInHost(const std::wstring& url) { + Hide(); + rendered_url_ = GURL(url); +} + +void BrowserObserver::OnReadyModeDisabled() { + // We don't hold a reference to the adapter, since it owns us (in order to + // break circular dependency). But we should still AddRef it before + // invocation. + base::win::ScopedComPtr<ReadyModeWebBrowserAdapter, NULL> reference(adapter_); + + // adapter_->Uninitialize may delete us, so we should not refer to members + // after that point. + base::win::ScopedComPtr<IWebBrowser2> web_browser(web_browser_); + + chrome_frame_->DisableChromeFrame(); + adapter_->Uninitialize(); + + VARIANT flags = { VT_I4 }; + V_I4(&flags) = navNoHistory; + base::win::ScopedBstr location; + + HRESULT hr = web_browser->get_LocationURL(location.Receive()); + DLOG_IF(ERROR, FAILED(hr)) << "Failed to get current location from " + << "IWebBrowser2. Error: " << hr; + + if (SUCCEEDED(hr)) { + hr = web_browser->Navigate(location, &flags, NULL, NULL, NULL); + DLOG_IF(ERROR, FAILED(hr)) << "Failed to invoke Navigate on IWebBrowser2. " + << "Error: " << hr; + } +} + +void BrowserObserver::OnReadyModeAccepted() { + // See comment in OnReadyModeDisabled. + base::win::ScopedComPtr<ReadyModeWebBrowserAdapter, NULL> reference(adapter_); + adapter_->Uninitialize(); +} + +void BrowserObserver::ShowPrompt() { + // This pointer is self-managed and not guaranteed to survive handling of + // Windows events. + InfobarManager* infobar_manager = GetInfobarManager(); + + if (infobar_manager) { + // Owned by ready_mode_state + scoped_ptr<RegistryReadyModeState::Observer> ready_mode_state_observer( + new StateObserver(weak_ptr_factory_.GetWeakPtr())); + + installer::ActivePackageProperties package_properties; + + // Owned by infobar_content + scoped_ptr<ReadyModeState> ready_mode_state(new RegistryReadyModeState( + package_properties.GetStateKey(), + base::TimeDelta::FromMinutes(kTemporaryDeclineDurationMinutes), + ready_mode_state_observer.release())); + + // Owned by infobar_manager + scoped_ptr<InfobarContent> infobar_content( + new ReadyPromptContent(ready_mode_state.release())); + + infobar_manager->Show(infobar_content.release(), TOP_INFOBAR); + } +} + +void BrowserObserver::Hide() { + InfobarManager* infobar_manager = GetInfobarManager(); + if (infobar_manager) + infobar_manager->HideAll(); +} + +InfobarManager* BrowserObserver::GetInfobarManager() { + HRESULT hr = NOERROR; + + base::win::ScopedComPtr<IOleWindow> ole_window; + hr = DoQueryService(SID_SShellBrowser, web_browser_, ole_window.Receive()); + if (FAILED(hr) || ole_window == NULL) { + DLOG(ERROR) << "Failed to query SID_SShellBrowser from IWebBrowser2. " + << "Error: " << hr; + return NULL; + } + + HWND web_browserhwnd = NULL; + hr = ole_window->GetWindow(&web_browserhwnd); + if (FAILED(hr) || web_browserhwnd == NULL) { + DLOG(ERROR) << "Failed to query HWND from IOleWindow. " + << "Error: " << hr; + return NULL; + } + + return InfobarManager::Get(web_browserhwnd); +} + +// Wraps an existing Delegate so that ownership may be shared. +class DelegateWrapper : public ready_mode::Delegate { + public: + explicit DelegateWrapper(linked_ptr<ready_mode::Delegate> wrapped); + + // ready_mode::Delegate implementation + virtual void DisableChromeFrame(); + + private: + linked_ptr<ready_mode::Delegate> wrapped_; + + DISALLOW_COPY_AND_ASSIGN(DelegateWrapper); +}; // class DelegateWrapper + +DelegateWrapper::DelegateWrapper(linked_ptr<ready_mode::Delegate> wrapped) + : wrapped_(wrapped) { +} + +void DelegateWrapper::DisableChromeFrame() { + wrapped_->DisableChromeFrame(); +} + +// Attempts to create a ReadyModeWebBrowserAdapter instance. +bool CreateWebBrowserAdapter(ReadyModeWebBrowserAdapter** pointer) { + *pointer = NULL; + + CComObject<ReadyModeWebBrowserAdapter>* com_object; + HRESULT hr = + CComObject<ReadyModeWebBrowserAdapter>::CreateInstance(&com_object); + + if (FAILED(hr)) { + DLOG(ERROR) << "Failed to create instance of ReadyModeWebBrowserAdapter. " + << "Error: " << hr; + return false; + } + + com_object->AddRef(); + *pointer = com_object; + return true; +} + +// Attempts to install Ready Mode prompts in the provided web browser. Will +// notify the provided Delegate if the user declines Chrome Frame temporarily or +// permanently. +bool InstallPrompts(linked_ptr<ready_mode::Delegate> delegate, + IWebBrowser2* web_browser) { + base::win::ScopedComPtr<ReadyModeWebBrowserAdapter, NULL> adapter; + + if (!CreateWebBrowserAdapter(adapter.Receive())) + return false; + + // Wrap the original delegate so that we can share it with the + // ReadyModeWebBrowserAdapter + scoped_ptr<DelegateWrapper> delegate_wrapper(new DelegateWrapper(delegate)); + + // Pass ownership of our delegate to the BrowserObserver + scoped_ptr<ReadyModeWebBrowserAdapter::Observer> browser_observer( + new BrowserObserver(delegate_wrapper.release(), web_browser, adapter)); + + // Owns the BrowserObserver + return adapter->Initialize(web_browser, browser_observer.release()); +} + +// Checks if the provided status implies disabling Chrome Frame functionality. +bool ShouldDisableChromeFrame(ReadyModeStatus status) { + switch (status) { + case READY_MODE_PERMANENTLY_DECLINED: + case READY_MODE_TEMPORARILY_DECLINED: + case READY_MODE_TEMPORARY_DECLINE_EXPIRED: + return true; + + case READY_MODE_ACCEPTED: + case READY_MODE_ACTIVE: + return false; + + default: + NOTREACHED(); + return true; + } +} + +} // namespace + +namespace ready_mode { + +// Determines the current Ready Mode state. If it is active, attempts to set up +// prompting. If we cannot set up prompting, attempts to temporarily disable +// Ready Mode. In the end, if Ready Mode is disabled, pass that information on +// to the Delegate, so that it may disabled Chrome Frame functionality. +void Configure(Delegate* chrome_frame, IWebBrowser2* web_browser) { + // Take ownership of the delegate + linked_ptr<Delegate> delegate(chrome_frame); + chrome_frame = NULL; + + RegistryReadyModeState ready_mode_state( + installer::ActivePackageProperties().GetStateKey(), + base::TimeDelta::FromMinutes(kTemporaryDeclineDurationMinutes), + NULL); // NULL => no observer required + + ReadyModeStatus status = ready_mode_state.GetStatus(); + + // If the user temporarily declined Chrome Frame, but the timeout has elapsed, + // attempt to revert to active Ready Mode state. + if (status == READY_MODE_TEMPORARY_DECLINE_EXPIRED) { + ready_mode_state.ExpireTemporaryDecline(); + status = ready_mode_state.GetStatus(); + } + + // If Ready Mode is active, attempt to set up prompting. + if (status == READY_MODE_ACTIVE) { + if (!InstallPrompts(delegate, web_browser)) { + // Failed to set up prompting. Turn off Ready Mode for now. + ready_mode_state.TemporarilyDeclineChromeFrame(); + status = ready_mode_state.GetStatus(); + } + } + + // Depending on the state we finally end up in, tell our Delegate to disable + // Chrome Frame functionality. + if (ShouldDisableChromeFrame(status)) + delegate->DisableChromeFrame(); +} + +} // namespace ready_mode diff --git a/chrome_frame/ready_mode/ready_mode.h b/chrome_frame/ready_mode/ready_mode.h new file mode 100644 index 0000000..0d42ab3 --- /dev/null +++ b/chrome_frame/ready_mode/ready_mode.h @@ -0,0 +1,42 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_FRAME_READY_MODE_READY_MODE_H_ +#define CHROME_FRAME_READY_MODE_READY_MODE_H_ +#pragma once + +#include <atlbase.h> +#include <atlcom.h> + +#include "base/basictypes.h" + +interface IWebBrowser2; + +// Integrates Ready Mode functionality with a specified IWebBrowser2 instance. +// Displays prompts allowing the user to permanently activate, permanently +// disable, or temporarily disable Chrome Frame whenever a Chrome Frame-enabled +// site is rendered in the browser. +namespace ready_mode { + +// Defines an interface for disabling Chrome Frame based on user interaction +// with Ready Mode. +class Delegate { + public: + virtual ~Delegate() {} + + // Disables Chrome Frame functionality in the current process. Will be + // called after the installer has been invoked to manipulate the system or + // user-level state. + virtual void DisableChromeFrame() = 0; +}; // class Delegate + +// Enables Ready Mode for the specified IWebBrowser2 instance, if Chrome Frame +// is currently in Ready Mode. If Chrome Frame is temporarily or permanently +// declined, will invoke chrome_frame->DisableChromeFrame() to synchronize the +// process state with the system- / user-level state. +void Configure(Delegate* chrome_frame, IWebBrowser2* web_browser); + +}; // namespace ready_mode + +#endif // CHROME_FRAME_READY_MODE_READY_MODE_H_ diff --git a/chrome_frame/ready_mode/ready_mode_manager.cc b/chrome_frame/ready_mode/ready_mode_manager.cc deleted file mode 100644 index c0e03fc..0000000 --- a/chrome_frame/ready_mode/ready_mode_manager.cc +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome_frame/ready_mode/ready_mode_manager.h" - -#include <exdisp.h> -#include <atlbase.h> -#include <shlguid.h> - -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/scoped_ptr.h" -#include "base/utf_string_conversions.h" -#include "base/win/scoped_comptr.h" -#include "net/base/registry_controlled_domain.h" -#include "chrome_frame/infobars/infobar_manager.h" -#include "chrome_frame/ready_mode/internal/ready_prompt_content.h" -#include "chrome_frame/ready_mode/internal/registry_ready_mode_state.h" -#include "chrome_frame/utils.h" - -namespace { - -const int kTemporaryDeclineDurationMinutes = 1; - -}; // namespace - -class ReadyModeManagerImpl : public ReadyModeManager { - public: - bool Initialize(IUnknown* site) { - DCHECK(!web_browser_); - DCHECK(site); - - if (web_browser_ != NULL) - return false; - - if (site != NULL) - web_browser_.QueryFrom(site); - - return web_browser_ != NULL; - } - - protected: - virtual void OnDeclineChromeFrame() { - VARIANT flags = { VT_I4 }; - V_I4(&flags) = navNoHistory; - web_browser_->Navigate(CComBSTR(ASCIIToWide(rendered_url_.spec()).c_str()), - &flags, NULL, NULL, NULL); - } - - virtual InfobarManager* GetInfobarManager() { - base::win::ScopedComPtr<IOleWindow> ole_window; - HWND web_browserhwnd = NULL; - - if (web_browser_ != NULL) - DoQueryService(SID_SShellBrowser, web_browser_, ole_window.Receive()); - - if (ole_window != NULL) - ole_window->GetWindow(&web_browserhwnd); - - if (web_browserhwnd != NULL) - return InfobarManager::Get(web_browserhwnd); - - return NULL; - } - - private: - base::win::ScopedComPtr<IWebBrowser2> web_browser_; -}; - -class DisableReadyModeObserver : public RegistryReadyModeState::Observer { - public: - DisableReadyModeObserver(IWebBrowser2* web_browser) - : web_browser_(web_browser) { - DCHECK(web_browser != NULL); - } - virtual void OnStateChange() { - VARIANT flags = { VT_I4 }; - V_I4(&flags) = navNoHistory; - web_browser_->Navigate(CComBSTR(ASCIIToWide(rendered_url_.spec()).c_str()), - &flags, NULL, NULL, NULL); - } - private: - base::win::ScopedComPtr<IWebBrowser2> web_browser_; -}; - -class ReadyModeUIImpl : public ReadyModeWebBrowserAdapter::ReadyModeUI { - public: - virtual void ShowPrompt() { - InfobarManager* infobar_manager = GetInfobarManager(); - if (infobar_manager) { - InstallationState* = new DummyInstallationState(); - - ReadyModeState* ready_mode_state = new RegistryReadyModeState( - kChromeFrameConfigKey, - base::TimeDelta::FromMinutes(kTemporaryDeclineDurationMinutes), - installation_state, - observer); - base::WeakPtr<ReadyModeManager> weak_ptr(weak_ptr_factory_.GetWeakPtr()); - infobar_manager->Show(new ReadyPromptContent(NULL /* TODO(erikwright)*/), TOP_INFOBAR); - } - } - virtual void Hide() { - } - - private: - virtual InfobarManager* GetInfobarManager() { - base::win::ScopedComPtr<IOleWindow> ole_window; - HWND web_browserhwnd = NULL; - - if (web_browser_ != NULL) - DoQueryService(SID_SShellBrowser, web_browser_, ole_window.Receive()); - - if (ole_window != NULL) - ole_window->GetWindow(&web_browserhwnd); - - if (web_browserhwnd != NULL) - return InfobarManager::Get(web_browserhwnd); - - return NULL; - } - - base::win::ScopedComPtr<IWebBrowser2> web_browser_; -}; - -void ReadyMode::Configure(ChromeFrameIntegration* integration, - IWebBrowser2* site) { - -} - -ReadyModeManager::ReadyModeManager() - : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { -} - -ReadyModeManager::~ReadyModeManager() { -} - -ReadyModeManager* ReadyModeManager::CreateReadyModeManager(IUnknown* site) { - scoped_ptr<ReadyModeManagerImpl> impl(new ReadyModeManagerImpl()); - - if (impl->Initialize(site)) - return impl.release(); - - return NULL; -} - -void ReadyModeManager::BeginNavigationTo(std::string http_method, std::wstring url) { - if (!net::RegistryControlledDomainService::SameDomainOrHost(GURL(url), - rendered_url_)) { - InfobarManager* infobar_manager = GetInfobarManager(); - if (infobar_manager) - infobar_manager->HideAll(); - - rendered_url_ = GURL(); - } -} - -void ReadyModeManager::RenderingInHost(std::string http_method, std::wstring url) { - InfobarManager* infobar_manager = GetInfobarManager(); - if (infobar_manager) - infobar_manager->HideAll(); - rendered_url_ = GURL(url); -} - -void ReadyModeManager::RenderingInChromeFrame(std::string http_method, std::wstring url) { - InfobarManager* infobar_manager = GetInfobarManager(); - if (infobar_manager) { - base::WeakPtr<ReadyModeManager> weak_ptr(weak_ptr_factory_.GetWeakPtr()); - infobar_manager->Show(new ReadyPromptContent(NULL /* TODO(erikwright)*/), TOP_INFOBAR); - } - rendered_url_ = GURL(url); -} diff --git a/chrome_frame/ready_mode/ready_mode_manager.h b/chrome_frame/ready_mode/ready_mode_manager.h deleted file mode 100644 index f496a26..0000000 --- a/chrome_frame/ready_mode/ready_mode_manager.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_FRAME_READY_MODE_READY_MODE_MANAGER_H_ -#define CHROME_FRAME_READY_MODE_READY_MODE_MANAGER_H_ -#pragma once - -enum ReadyModeStatus { - READY_MODE_PERMANENTLY_DECLINED, - READY_MODE_TEMPORARILY_DECLINED, - READY_MODE_ACTIVE, - READY_MODE_ACCEPTED -}; // enum ReadyModeStatus - -#endif // CHROME_FRAME_READY_MODE_READY_MODE_MANAGER_H_ diff --git a/chrome_frame/test/chrome_frame_test_utils.cc b/chrome_frame/test/chrome_frame_test_utils.cc index dec04d6..e464d6f 100644 --- a/chrome_frame/test/chrome_frame_test_utils.cc +++ b/chrome_frame/test/chrome_frame_test_utils.cc @@ -4,8 +4,8 @@ #include "chrome_frame/test/chrome_frame_test_utils.h" -#include <atlbase.h> -#include <atlwin.h> +#include <atlapp.h> +#include <atlmisc.h> #include <iepmapi.h> #include <sddl.h> @@ -565,8 +565,8 @@ bool DetectRunningCrashService(int timeout_ms) { // Wait a bit longer break; default: - DLOG(WARNING) << "Unexpected error while checking crash_service.exe's " - << ::GetLastError(); + DPLOG(WARNING) << "Unexpected error while checking crash_service.exe's " + << "pipe."; // Go ahead and wait in case it clears up. break; } diff --git a/chrome_frame/test/chrome_frame_test_utils.h b/chrome_frame/test/chrome_frame_test_utils.h index 0bd0aad..cc3d2be 100644 --- a/chrome_frame/test/chrome_frame_test_utils.h +++ b/chrome_frame/test/chrome_frame_test_utils.h @@ -1,19 +1,14 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_FRAME_TEST_CHROME_FRAME_TEST_UTILS_H_ #define CHROME_FRAME_TEST_CHROME_FRAME_TEST_UTILS_H_ +#include <windows.h> + #include <atlbase.h> -#include <atlcom.h> #include <atlwin.h> -#include <exdisp.h> -#include <exdispid.h> -#include <mshtml.h> -#include <shlguid.h> -#include <shobjidl.h> -#include <windows.h> #include <string> @@ -38,6 +33,8 @@ #define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING #include "testing/gmock_mutant.h" +interface IWebBrowser2; + namespace chrome_frame_test { int CloseVisibleWindowsOnAllThreads(HANDLE process); diff --git a/chrome_frame/test/ie_event_sink.cc b/chrome_frame/test/ie_event_sink.cc index c570558..ebe41dd 100644 --- a/chrome_frame/test/ie_event_sink.cc +++ b/chrome_frame/test/ie_event_sink.cc @@ -4,6 +4,9 @@ #include "chrome_frame/test/ie_event_sink.h" +#include <shlguid.h> +#include <shobjidl.h> + #include "base/string_util.h" #include "base/stringprintf.h" #include "base/utf_string_conversions.h" diff --git a/chrome_frame/test/infobar_unittests.cc b/chrome_frame/test/infobar_unittests.cc index abd7c17..63aa898 100644 --- a/chrome_frame/test/infobar_unittests.cc +++ b/chrome_frame/test/infobar_unittests.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -208,7 +208,6 @@ template <typename WINDOW, typename DELEGATE> void ExpectNcCalcSizeSequence( OnSize(0, CSize(modified_rect->right - modified_rect->left, modified_rect->bottom - modified_rect->top))) .Times(testing::Between(0, 1)); - } template <typename WINDOW, typename DELEGATE, typename MANAGER> @@ -432,7 +431,9 @@ ACTION_P2(AsynchronousHideOnManager, loop, manager) { // If the test turns out to be flaky (i.e., because timers are not firing // frequently enough to hit all the ranges), increasing the infobar_height // should increase the margin (by increasing the time spent in each range). -TEST(InfobarsInfobarWindowTest, SlidingTest) { +// +// TODO(erikwright): re-enable when sliding is fixed (currently crashes in IE6). +TEST(InfobarsInfobarWindowTest, DISABLED_SlidingTest) { int infobar_height = 40; chrome_frame_test::TimedMsgLoop message_loop; @@ -441,7 +442,7 @@ TEST(InfobarsInfobarWindowTest, SlidingTest) { // Used to verify that the last RECT given to SetDimensions is the same RECT // reserved by ReserveSpace. - RECT current_infobar_dimensions = {0, 0, 0, 0}; // Used to verify that the + RECT current_infobar_dimensions = {0, 0, 0, 0}; // Used to make sure that each SetDimensions is matched by a return from // ReserveSpace. diff --git a/chrome_frame/test/ready_mode_unittest.cc b/chrome_frame/test/ready_mode_unittest.cc index 8262cbc..a462ff2 100644 --- a/chrome_frame/test/ready_mode_unittest.cc +++ b/chrome_frame/test/ready_mode_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -14,12 +14,10 @@ #include "base/scoped_ptr.h" #include "base/win/registry.h" #include "chrome_frame/infobars/infobar_content.h" -#include "chrome_frame/ready_mode/internal/installation_state.h" #include "chrome_frame/ready_mode/internal/ready_mode_state.h" #include "chrome_frame/ready_mode/internal/ready_prompt_content.h" #include "chrome_frame/ready_mode/internal/ready_prompt_window.h" #include "chrome_frame/ready_mode/internal/registry_ready_mode_state.h" -#include "chrome_frame/ready_mode/ready_mode_manager.h" #include "chrome_frame/simple_resource_loader.h" #include "chrome_frame/test/chrome_frame_test_utils.h" @@ -99,35 +97,11 @@ class MockReadyModeState : public ReadyModeState { MOCK_METHOD0(AcceptChromeFrame, void(void)); }; // class MockReadyModeState -ACTION_P(ReturnPointee, pointer) { - return *pointer; -} - -ACTION_P2(SetPointeeTo, pointer, value) { - *pointer = value; -} - -class MockInstallationState : public InstallationState { - public: - // InstallationState implementation - MOCK_METHOD0(IsProductInstalled, bool(void)); - MOCK_METHOD0(IsProductRegistered, bool(void)); - MOCK_METHOD0(InstallProduct, bool(void)); - MOCK_METHOD0(UnregisterProduct, bool(void)); -}; // class MockInstallationState - -class MockRegistryReadyModeStateObserver - : public RegistryReadyModeState::Observer { - public: - // RegistryReadyModeState::Observer implementation - MOCK_METHOD0(OnStateChange, void(void)); -}; // class MockRegistryReadyModeStateObserver - } // namespace class ReadyPromptTest : public testing::Test { public: - ReadyPromptTest() : hwnd_(NULL) {}; + ReadyPromptTest() : hwnd_(NULL) {} void SetUp() { hwnd_ = window_.Create(NULL); @@ -299,175 +273,6 @@ TEST_F(ReadyPromptWindowButtonTest, ClickNo) { RunUntilCloseInfobar(); } -class ReadyModeRegistryTest : public testing::Test { - public: - class TimeControlledRegistryReadyModeState : public RegistryReadyModeState { - public: - TimeControlledRegistryReadyModeState( - const std::wstring& key_name, - base::TimeDelta temporary_decline_duration, - InstallationState* installation_state, - Observer* observer) - : RegistryReadyModeState(key_name, temporary_decline_duration, - installation_state, observer), - now_(base::Time::Now()) { - } - - base::Time now_; - - protected: - virtual base::Time GetNow() { - return now_; - } - }; // class TimeControlledRegistryReadyModeState - - ReadyModeRegistryTest() - : is_product_registered_(true), - is_product_installed_(false), - observer_(NULL), - installation_state_(NULL) { - } - - virtual void SetUp() { - base::win::RegKey key; - ASSERT_TRUE(key.Create(HKEY_CURRENT_USER, kRootKey, KEY_ALL_ACCESS)); - observer_ = new MockRegistryReadyModeStateObserver(); - installation_state_ = new MockInstallationState(); - - EXPECT_CALL(*installation_state_, IsProductRegistered()) - .Times(testing::AnyNumber()) - .WillRepeatedly(ReturnPointee(&is_product_registered_)); - EXPECT_CALL(*installation_state_, IsProductInstalled()) - .Times(testing::AnyNumber()) - .WillRepeatedly(ReturnPointee(&is_product_installed_)); - - ready_mode_state_.reset(new TimeControlledRegistryReadyModeState( - kRootKey, - base::TimeDelta::FromSeconds(kTemporaryDeclineDurationInSeconds), - installation_state_, - observer_)); - } - - virtual void TearDown() { - base::win::RegKey key; - EXPECT_TRUE(key.Open(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS)); - EXPECT_TRUE(key.DeleteKey(kRootKey)); - } - - protected: - void AdjustClockBySeconds(int seconds) { - ready_mode_state_->now_ += base::TimeDelta::FromSeconds(seconds); - } - - void ExpectUnregisterProductAndReturn(bool success) { - EXPECT_CALL(*installation_state_, UnregisterProduct()) - .WillOnce(testing::DoAll( - SetPointeeTo(&is_product_registered_, !success), - testing::Return(success))); - } - - void ExpectInstallProductAndReturn(bool success) { - EXPECT_CALL(*installation_state_, InstallProduct()) - .WillOnce(testing::DoAll(SetPointeeTo(&is_product_installed_, success), - testing::Return(success))); - } - - bool is_product_registered_; - bool is_product_installed_; - MockInstallationState* installation_state_; - MockRegistryReadyModeStateObserver* observer_; - - scoped_ptr<TimeControlledRegistryReadyModeState> ready_mode_state_; - base::win::RegKey config_key; - static const wchar_t kRootKey[]; - static const int kTemporaryDeclineDurationInSeconds; -}; // class ReadyModeRegistryTest - -const int ReadyModeRegistryTest::kTemporaryDeclineDurationInSeconds = 2; -const wchar_t ReadyModeRegistryTest::kRootKey[] = L"chrome_frame_unittests"; - -TEST_F(ReadyModeRegistryTest, CallNothing) { - // expect it to delete the two mocks... Google Mock fails if they are leaked. -} - -TEST_F(ReadyModeRegistryTest, NotInstalledStatus) { - ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); -} - -TEST_F(ReadyModeRegistryTest, NotRegisteredStatus) { - is_product_registered_ = false; - ASSERT_EQ(READY_MODE_PERMANENTLY_DECLINED, ready_mode_state_->GetStatus()); -} - -TEST_F(ReadyModeRegistryTest, InstalledStatus) { - is_product_installed_ = true; - ASSERT_EQ(READY_MODE_ACCEPTED, ready_mode_state_->GetStatus()); -} - -TEST_F(ReadyModeRegistryTest, TemporarilyDeclineChromeFrame) { - ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); - - EXPECT_CALL(*observer_, OnStateChange()); - ready_mode_state_->TemporarilyDeclineChromeFrame(); - - ASSERT_EQ(READY_MODE_TEMPORARILY_DECLINED, ready_mode_state_->GetStatus()); - - AdjustClockBySeconds(kTemporaryDeclineDurationInSeconds + 1); - ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); -} - -TEST_F(ReadyModeRegistryTest, TemporarilyDeclineChromeFrameSetClockBack) { - ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); - - EXPECT_CALL(*observer_, OnStateChange()); - ready_mode_state_->TemporarilyDeclineChromeFrame(); - - ASSERT_EQ(READY_MODE_TEMPORARILY_DECLINED, ready_mode_state_->GetStatus()); - - AdjustClockBySeconds(kTemporaryDeclineDurationInSeconds + 1); - ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); -} - -TEST_F(ReadyModeRegistryTest, PermanentlyDeclineChromeFrame) { - ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); - - EXPECT_CALL(*observer_, OnStateChange()); - ExpectUnregisterProductAndReturn(true); - ready_mode_state_->PermanentlyDeclineChromeFrame(); - - ASSERT_EQ(READY_MODE_PERMANENTLY_DECLINED, ready_mode_state_->GetStatus()); -} - -TEST_F(ReadyModeRegistryTest, PermanentlyDeclineChromeFrameFailUnregister) { - ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); - - EXPECT_CALL(*observer_, OnStateChange()); - ExpectUnregisterProductAndReturn(false); - ready_mode_state_->PermanentlyDeclineChromeFrame(); - - ASSERT_EQ(READY_MODE_PERMANENTLY_DECLINED, ready_mode_state_->GetStatus()); -} - -TEST_F(ReadyModeRegistryTest, AcceptChromeFrame) { - ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); - - EXPECT_CALL(*observer_, OnStateChange()); - ExpectInstallProductAndReturn(true); - ready_mode_state_->AcceptChromeFrame(); - - ASSERT_EQ(READY_MODE_ACCEPTED, ready_mode_state_->GetStatus()); -} - -// TODO(erikwright): What do we actually want to happen if the install fails? -// Stay in Ready Mode? Attempt to unregister (deactivate ready mode)? -// -// Which component is responsible for messaging the user? The installer? The -// InstallationState implementation? The ReadyModeState implementation? -TEST_F(ReadyModeRegistryTest, AcceptChromeFrameInstallFails) { - ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); - - ExpectInstallProductAndReturn(false); - ready_mode_state_->AcceptChromeFrame(); - - ASSERT_EQ(READY_MODE_ACTIVE, ready_mode_state_->GetStatus()); -} +// TODO(erikwright): test WebBrowserAdapter +// TODO(erikwright): an integration test of ReadyMode::Configure with a mock +// IWebBrowser2? |