diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-31 19:16:18 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-31 19:16:18 +0000 |
commit | 61c13e8d5361469479e5c0bf61d0c25a5402ef15 (patch) | |
tree | 82200b6909c1397db8df8afe9ddae6910ee27336 | |
parent | 3eafbf73e409ffac6ee88ca08ff4b44600e88f85 (diff) | |
download | chromium_src-61c13e8d5361469479e5c0bf61d0c25a5402ef15.zip chromium_src-61c13e8d5361469479e5c0bf61d0c25a5402ef15.tar.gz chromium_src-61c13e8d5361469479e5c0bf61d0c25a5402ef15.tar.bz2 |
Cleanup TODOs in RemotingSetupFlow
Things done in this patch:
1. RemotingSetupMessageHandler is not leaked.
2. Logic of showing different pages is now in RemotingSetupFlow.
3. Better lifetime for RemotingSetupFlow.
4. RemotingSetupFlow doesn't need to be refcounted, instead we have a helper
class that we can detach when the dialog is closed.
BUG=52888
TEST=Run with --enable-remoting and start the remoting setup dialog
Review URL: http://codereview.chromium.org/3106036
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@58037 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/browser.cc | 2 | ||||
-rw-r--r-- | chrome/browser/remoting/remoting_setup_flow.cc | 243 | ||||
-rw-r--r-- | chrome/browser/remoting/remoting_setup_flow.h | 88 | ||||
-rw-r--r-- | chrome/browser/remoting/remoting_setup_message_handler.cc | 37 | ||||
-rw-r--r-- | chrome/browser/remoting/remoting_setup_message_handler.h | 17 |
5 files changed, 237 insertions, 150 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 85cf378..02fe3ea 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -1827,7 +1827,7 @@ void Browser::OpenSyncMyBookmarksDialog() { #if defined(ENABLE_REMOTING) void Browser::OpenRemotingSetupDialog() { - ::OpenRemotingSetupDialog(profile_); + RemotingSetupFlow::OpenDialog(profile_); } #endif diff --git a/chrome/browser/remoting/remoting_setup_flow.cc b/chrome/browser/remoting/remoting_setup_flow.cc index 9c71b9b..4a982db 100644 --- a/chrome/browser/remoting/remoting_setup_flow.cc +++ b/chrome/browser/remoting/remoting_setup_flow.cc @@ -19,8 +19,10 @@ #include "chrome/browser/profile.h" #include "chrome/browser/remoting/remoting_resources_source.h" #include "chrome/browser/remoting/remoting_setup_message_handler.h" +#include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/service/service_process_control.h" #include "chrome/browser/service/service_process_control_manager.h" +#include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/net/gaia/gaia_authenticator2.h" #include "chrome/common/net/gaia/gaia_constants.h" #include "chrome/common/net/gaia/google_service_auth_error.h" @@ -29,14 +31,75 @@ #include "gfx/font.h" #include "grit/locale_settings.h" -// Use static Run method to get an instance. +static const wchar_t kLoginIFrameXPath[] = L"//iframe[@id='login']"; +static const wchar_t kDoneIframeXPath[] = L"//iframe[@id='done']"; + +//////////////////////////////////////////////////////////////////////////////// +// RemotingServiceProcessHelper +// +// This is a helper class to perform actions when the service process +// is connected or launched. The events are sent back to RemotingSetupFlow +// when the dialog is still active. RemotingSetupFlow can detach from this +// helper class when the dialog is closed. +class RemotingServiceProcessHelper : + public base::RefCountedThreadSafe<RemotingServiceProcessHelper> { + public: + RemotingServiceProcessHelper(RemotingSetupFlow* flow) + : flow_(flow) { + } + + void Detach() { + flow_ = NULL; + } + + void OnProcessLaunched() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + // If the flow is detached then show the done page. + if (!flow_) + return; + + flow_->OnProcessLaunched(); + } + + private: + RemotingSetupFlow* flow_; + + DISALLOW_COPY_AND_ASSIGN(RemotingServiceProcessHelper); +}; + +//////////////////////////////////////////////////////////////////////////////// +// RemotingSetupFlow implementation. +// static +RemotingSetupFlow* RemotingSetupFlow::OpenDialog(Profile* profile) { + // Set the arguments for showing the gaia login page. + DictionaryValue args; + args.SetString("iframeToShow", "login"); + args.SetString("user", ""); + args.SetInteger("error", 0); + args.SetBoolean("editable_user", true); + + if (profile->GetPrefs()->GetBoolean(prefs::kRemotingHasSetupCompleted)) { + args.SetString("iframeToShow", "done"); + } + + std::string json_args; + base::JSONWriter::Write(&args, false, &json_args); + + Browser* b = BrowserList::GetLastActive(); + if (!b) + return NULL; + + RemotingSetupFlow* flow = new RemotingSetupFlow(json_args, profile); + b->BrowserShowHtmlDialog(flow, NULL); + return flow; +} + RemotingSetupFlow::RemotingSetupFlow(const std::string& args, Profile* profile) - : message_handler_(NULL), + : dom_ui_(NULL), dialog_start_args_(args), profile_(profile), process_control_(NULL) { - // TODO(hclam): We are currently leaking this objcet. Need to fix this! - message_handler_ = new RemotingSetupMessageHandler(this); + // TODO(hclam): The data source should be added once. ChromeThread::PostTask( ChromeThread::IO, FROM_HERE, NewRunnableMethod(Singleton<ChromeURLDataManager>::get(), @@ -47,6 +110,25 @@ RemotingSetupFlow::RemotingSetupFlow(const std::string& args, Profile* profile) RemotingSetupFlow::~RemotingSetupFlow() { } +void RemotingSetupFlow::Focus() { + // TODO(pranavk): implement this method. + NOTIMPLEMENTED(); +} + +/////////////////////////////////////////////////////////////////////////////// +// HtmlDialogUIDelegate implementation. +GURL RemotingSetupFlow::GetDialogContentURL() const { + return GURL("chrome://remotingresources/setup"); +} + +void RemotingSetupFlow::GetDOMMessageHandlers( + std::vector<DOMMessageHandler*>* handlers) const { + // Create the message handler only after we are asked, the caller is + // responsible for deleting the objects. + handlers->push_back( + new RemotingSetupMessageHandler(const_cast<RemotingSetupFlow*>(this))); +} + void RemotingSetupFlow::GetDialogSize(gfx::Size* size) const { PrefService* prefs = profile_->GetPrefs(); gfx::Font approximate_web_font( @@ -65,38 +147,37 @@ void RemotingSetupFlow::OnDialogClosed(const std::string& json_retval) { // If we are fetching the token then cancel the request. if (authenticator_.get()) authenticator_->CancelRequest(); + + // If the service process helper is still active then detach outself from it. + // This is because the dialog is closing and this object is going to be + // deleted but the service process launch is still in progress so we don't + // the service process helper to call us when the process is launched. + if (service_process_helper_.get()) + service_process_helper_->Detach(); delete this; } -void RemotingSetupFlow::GetDOMMessageHandlers( - std::vector<DOMMessageHandler*>* handlers) const { - // Create the message handler only after we are asked. - handlers->push_back(message_handler_); +std::string RemotingSetupFlow::GetDialogArgs() const { + return dialog_start_args_; } -void RemotingSetupFlow::Focus() { - // TODO(pranavk): implement this method. - NOTIMPLEMENTED(); +void RemotingSetupFlow::OnCloseContents(TabContents* source, + bool* out_close_dialog) { } -void RemotingSetupFlow::OnUserSubmittedAuth(const std::string& user, - const std::string& password, - const std::string& captcha) { - // Save the login name only. - login_ = user; +std::wstring RemotingSetupFlow::GetDialogTitle() const { + return l10n_util::GetString(IDS_REMOTING_SETUP_DIALOG_TITLE); +} - // Start the authenticator. - authenticator_.reset( - new GaiaAuthenticator2(this, GaiaConstants::kChromeSource, - profile_->GetRequestContext())); - authenticator_->StartClientLogin(user, password, - GaiaConstants::kRemotingService, - "", captcha); +bool RemotingSetupFlow::IsDialogModal() const { + return true; } +/////////////////////////////////////////////////////////////////////////////// +// GaiaAuthConsumer implementation. void RemotingSetupFlow::OnClientLoginFailure( const GoogleServiceAuthError& error) { - message_handler_->ShowGaiaFailed(); + ShowGaiaFailed(error); authenticator_.reset(); } @@ -114,7 +195,7 @@ void RemotingSetupFlow::OnClientLoginSuccess( void RemotingSetupFlow::OnIssueAuthTokenSuccess(const std::string& service, const std::string& auth_token) { // Show that Gaia login has succeeded. - message_handler_->ShowGaiaSuccessAndSettingUp(); + ShowGaiaSuccessAndSettingUp(); // Save the sync token. sync_token_ = auth_token; @@ -129,75 +210,105 @@ void RemotingSetupFlow::OnIssueAuthTokenSuccess(const std::string& service, kServiceProcessRemoting); if (process_control_->is_connected()) { - OnProcessLaunched(); + // TODO(hclam): Need to figure out what to do when the service process is + // already connected. } else { - // TODO(hclam): This is really messed up because I totally ignore the - // lifetime of this object. I need a master cleanup on the lifetime of - // objects. +#if defined(OS_WIN) // TODO(hclam): This call only works on Windows. I need to make it work // on other platforms. + service_process_helper_ = new RemotingServiceProcessHelper(this); process_control_->Launch( - NewRunnableMethod(this, &RemotingSetupFlow::OnProcessLaunched)); + NewRunnableMethod(service_process_helper_.get(), + &RemotingServiceProcessHelper::OnProcessLaunched)); +#else + ShowSetupDone(); +#endif } } void RemotingSetupFlow::OnIssueAuthTokenFailure(const std::string& service, const GoogleServiceAuthError& error) { - // TODO(hclam): Do something to show the error. + ShowGaiaFailed(error); authenticator_.reset(); } -void RemotingSetupFlow::OnProcessLaunched() { - if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) { - ChromeThread::PostTask( - ChromeThread::UI, - FROM_HERE, - NewRunnableMethod(this, &RemotingSetupFlow::OnProcessLaunched)); - return; - } +/////////////////////////////////////////////////////////////////////////////// +// Methods called by RemotingSetupMessageHandler +void RemotingSetupFlow::Attach(DOMUI* dom_ui) { + dom_ui_ = dom_ui; +} +void RemotingSetupFlow::OnUserSubmittedAuth(const std::string& user, + const std::string& password, + const std::string& captcha) { + // Save the login name only. + login_ = user; + + // Start the authenticator. + authenticator_.reset( + new GaiaAuthenticator2(this, GaiaConstants::kChromeSource, + profile_->GetRequestContext())); + authenticator_->StartClientLogin(user, password, + GaiaConstants::kRemotingService, + "", captcha); +} + +/////////////////////////////////////////////////////////////////////////////// +// Method called by RemotingServicePRocessHelper +void RemotingSetupFlow::OnProcessLaunched() { DCHECK(process_control_->is_connected()); + // TODO(hclam): Need to wait for an ACK to be sure that it is actually active. process_control_->EnableRemotingWithTokens(login_, remoting_token_, sync_token_); - message_handler_->ShowSetupDone(); // Save the preference that we have completed the setup of remoting. profile_->GetPrefs()->SetBoolean(prefs::kRemotingHasSetupCompleted, true); + ShowSetupDone(); } -// static -RemotingSetupFlow* RemotingSetupFlow::Run(Profile* profile) { - // Set the arguments for showing the gaia login page. +/////////////////////////////////////////////////////////////////////////////// +// Helper methods for showing contents of the DOM UI +void RemotingSetupFlow::ShowGaiaLogin(const DictionaryValue& args) { + if (dom_ui_) + dom_ui_->CallJavascriptFunction(L"showGaiaLoginIframe"); + + std::string json; + base::JSONWriter::Write(&args, false, &json); + std::wstring javascript = std::wstring(L"showGaiaLogin") + + L"(" + UTF8ToWide(json) + L");"; + ExecuteJavascriptInIFrame(kLoginIFrameXPath, javascript); +} + +void RemotingSetupFlow::ShowGaiaSuccessAndSettingUp() { + ExecuteJavascriptInIFrame(kLoginIFrameXPath, + L"showGaiaSuccessAndSettingUp();"); +} + +void RemotingSetupFlow::ShowGaiaFailed(const GoogleServiceAuthError& error) { DictionaryValue args; args.SetString("iframeToShow", "login"); args.SetString("user", ""); - args.SetInteger("error", 0); + args.SetInteger("error", error.state()); args.SetBoolean("editable_user", true); + args.SetString("captchaUrl", error.captcha().image_url.spec()); + ShowGaiaLogin(args); +} - if (profile->GetPrefs()->GetBoolean(prefs::kRemotingHasSetupCompleted)) { - args.SetString("iframeToShow", "done"); - } +void RemotingSetupFlow::ShowSetupDone() { + std::wstring javascript = L"setMessage('You are all set!');"; + ExecuteJavascriptInIFrame(kDoneIframeXPath, javascript); - std::string json_args; - base::JSONWriter::Write(&args, false, &json_args); + if (dom_ui_) + dom_ui_->CallJavascriptFunction(L"showSetupDone"); - RemotingSetupFlow* flow = new RemotingSetupFlow(json_args, profile); - Browser* b = BrowserList::GetLastActive(); - if (b) { - b->BrowserShowHtmlDialog(flow, NULL); - } else { - delete flow; - return NULL; - } - return flow; + ExecuteJavascriptInIFrame(kDoneIframeXPath, L"onPageShown();"); } -// Global function to start the remoting setup dialog. -void OpenRemotingSetupDialog(Profile* profile) { - RemotingSetupFlow::Run(profile->GetOriginalProfile()); +void RemotingSetupFlow::ExecuteJavascriptInIFrame( + const std::wstring& iframe_xpath, + const std::wstring& js) { + if (dom_ui_) { + RenderViewHost* rvh = dom_ui_->tab_contents()->render_view_host(); + rvh->ExecuteJavascriptInWebFrame(iframe_xpath, js); + } } - -// TODO(hclam): Need to refcount RemotingSetupFlow. I need to fix -// lifetime of objects. -DISABLE_RUNNABLE_METHOD_REFCOUNT(RemotingSetupFlow); -DISABLE_RUNNABLE_METHOD_REFCOUNT(RemotingSetupMessageHandler); diff --git a/chrome/browser/remoting/remoting_setup_flow.h b/chrome/browser/remoting/remoting_setup_flow.h index 1397f10..05ec5da 100644 --- a/chrome/browser/remoting/remoting_setup_flow.h +++ b/chrome/browser/remoting/remoting_setup_flow.h @@ -17,11 +17,27 @@ #include "grit/generated_resources.h" class GaiaAuthenticator2; +class RemotingServiceProcessHelper; class RemotingSetupMessageHandler; class ServiceProcessControl; class GoogleServiceAuthError; -// The state machine used by Remoting for setup wizard. +// This class is responsible for showing a remoting setup dialog and perform +// operations to fill the content of the dialog and handle user actions +// in the dialog. +// +// It is responsible for: +// 1. Showing the setup dialog. +// 2. Providing the URL for the content of the dialog. +// 3. Providing a data source to provide the content HTML files. +// 4. Providing a message handler to handle user actions in the DOM UI. +// 5. Responding to actions received in the message handler. +// +// The architecture for DOMUI is designed such that only the message handler +// can access the DOMUI. This splits the flow control across the message +// handler and this class. In order to centralize all the flow control and +// content in the DOMUI, the DOMUI object is given to this object by the +// message handler through the Attach(DOMUI*) method. class RemotingSetupFlow : public HtmlDialogUIDelegate, public GaiaAuthConsumer { public: @@ -30,44 +46,22 @@ class RemotingSetupFlow : public HtmlDialogUIDelegate, // Runs a flow from |start| to |end|, and does the work of actually showing // the HTML dialog. |container| is kept up-to-date with the lifetime of the // flow (e.g it is emptied on dialog close). - static RemotingSetupFlow* Run(Profile* service); - - // Fills |args| with "user" and "error" arguments by querying |service|. - static void GetArgsForGaiaLogin(DictionaryValue* args); + static RemotingSetupFlow* OpenDialog(Profile* service); // Focuses the dialog. This is useful in cases where the dialog has been // obscured by a browser window. void Focus(); // HtmlDialogUIDelegate implementation. - // Get the HTML file path for the content to load in the dialog. - virtual GURL GetDialogContentURL() const { - return GURL("chrome://remotingresources/setup"); - } - - // HtmlDialogUIDelegate implementation. + virtual GURL GetDialogContentURL() const; virtual void GetDOMMessageHandlers( std::vector<DOMMessageHandler*>* handlers) const; - - // HtmlDialogUIDelegate implementation. - // Get the size of the dialog. virtual void GetDialogSize(gfx::Size* size) const; - - // HtmlDialogUIDelegate implementation. - // Gets the JSON string input to use when opening the dialog. - virtual std::string GetDialogArgs() const { - return dialog_start_args_; - } - - // HtmlDialogUIDelegate implementation. + virtual std::string GetDialogArgs() const; virtual void OnDialogClosed(const std::string& json_retval); - virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) { } - virtual std::wstring GetDialogTitle() const { - return l10n_util::GetString(IDS_REMOTING_SETUP_DIALOG_TITLE); - } - virtual bool IsDialogModal() const { - return true; - } + virtual void OnCloseContents(TabContents* source, bool* out_close_dialog); + virtual std::wstring GetDialogTitle() const; + virtual bool IsDialogModal() const; // GaiaAuthConsumer implementation. virtual void OnClientLoginFailure( @@ -79,19 +73,38 @@ class RemotingSetupFlow : public HtmlDialogUIDelegate, virtual void OnIssueAuthTokenFailure(const std::string& service, const GoogleServiceAuthError& error); - // Called by RemotingSetupMessageHandler. - void OnUserSubmittedAuth(const std::string& user, - const std::string& password, - const std::string& captcha); - private: + friend class RemotingServiceProcessHelper; + friend class RemotingSetupMessageHandler; + // Use static Run method to get an instance. RemotingSetupFlow(const std::string& args, Profile* profile); + // Called RemotingSetupMessageHandler when a DOM is attached. This method + // is called when the HTML page is fully loaded. We then operate on this + // DOMUI object directly. + void Attach(DOMUI* dom_ui); + + // Called by RemotingSetupMessageHandler when user authentication is + // registered. + void OnUserSubmittedAuth(const std::string& user, + const std::string& password, + const std::string& captcha); + // Event triggered when the service process was launched. void OnProcessLaunched(); - RemotingSetupMessageHandler* message_handler_; + // The following methods control which iframe is visible. + void ShowGaiaLogin(const DictionaryValue& args); + void ShowGaiaSuccessAndSettingUp(); + void ShowGaiaFailed(const GoogleServiceAuthError& error); + void ShowSetupDone(); + void ExecuteJavascriptInIFrame(const std::wstring& iframe_xpath, + const std::wstring& js); + + // Pointer to the DOM UI. This is provided by RemotingSetupMessageHandler + // when attached. + DOMUI* dom_ui_; // The args to pass to the initial page. std::string dialog_start_args_; @@ -105,12 +118,9 @@ class RemotingSetupFlow : public HtmlDialogUIDelegate, // Handle to the ServiceProcessControl which talks to the service process. ServiceProcessControl* process_control_; + scoped_refptr<RemotingServiceProcessHelper> service_process_helper_; DISALLOW_COPY_AND_ASSIGN(RemotingSetupFlow); }; -// Open the appropriate setup dialog for the given profile (which can be -// incognito). -void OpenRemotingSetupDialog(Profile* profile); - #endif // CHROME_BROWSER_REMOTING_REMOTING_SETUP_FLOW_H_ diff --git a/chrome/browser/remoting/remoting_setup_message_handler.cc b/chrome/browser/remoting/remoting_setup_message_handler.cc index 35806df..413f901 100644 --- a/chrome/browser/remoting/remoting_setup_message_handler.cc +++ b/chrome/browser/remoting/remoting_setup_message_handler.cc @@ -9,11 +9,12 @@ #include "base/json/json_writer.h" #include "chrome/browser/dom_ui/dom_ui_util.h" #include "chrome/browser/remoting/remoting_setup_flow.h" -#include "chrome/browser/renderer_host/render_view_host.h" -#include "chrome/browser/tab_contents/tab_contents.h" -static const wchar_t kLoginIFrameXPath[] = L"//iframe[@id='login']"; -static const wchar_t kDoneIframeXPath[] = L"//iframe[@id='done']"; +DOMMessageHandler* RemotingSetupMessageHandler::Attach(DOMUI* dom_ui) { + // Pass the DOMUI object to the setup flow. + flow_->Attach(dom_ui); + return DOMMessageHandler::Attach(dom_ui); +} void RemotingSetupMessageHandler::RegisterMessages() { dom_ui_->RegisterMessageCallback("SubmitAuth", @@ -44,31 +45,3 @@ void RemotingSetupMessageHandler::HandleSubmitAuth(const ListValue* args) { if (flow_) flow_->OnUserSubmittedAuth(username, password, captcha); } - -void RemotingSetupMessageHandler::ShowGaiaSuccessAndSettingUp() { - ExecuteJavascriptInIFrame(kLoginIFrameXPath, - L"showGaiaSuccessAndSettingUp();"); -} - -void RemotingSetupMessageHandler::ShowGaiaFailed() { - // TODO(hclam): Implement this. -} - -void RemotingSetupMessageHandler::ShowSetupDone() { - std::wstring javascript = L"setMessage('You are all set!');"; - ExecuteJavascriptInIFrame(kDoneIframeXPath, javascript); - - if (dom_ui_) - dom_ui_->CallJavascriptFunction(L"showSetupDone"); - - ExecuteJavascriptInIFrame(kDoneIframeXPath, L"onPageShown();"); -} - -void RemotingSetupMessageHandler::ExecuteJavascriptInIFrame( - const std::wstring& iframe_xpath, - const std::wstring& js) { - if (dom_ui_) { - RenderViewHost* rvh = dom_ui_->tab_contents()->render_view_host(); - rvh->ExecuteJavascriptInWebFrame(iframe_xpath, js); - } -} diff --git a/chrome/browser/remoting/remoting_setup_message_handler.h b/chrome/browser/remoting/remoting_setup_message_handler.h index a01001b..f90dfce 100644 --- a/chrome/browser/remoting/remoting_setup_message_handler.h +++ b/chrome/browser/remoting/remoting_setup_message_handler.h @@ -15,27 +15,20 @@ class RemotingSetupFlow; // This class is used to handle DOM messages from the setup dialog. class RemotingSetupMessageHandler : public DOMMessageHandler { public: - RemotingSetupMessageHandler(RemotingSetupFlow* flow) : flow_(flow) {} + explicit RemotingSetupMessageHandler(RemotingSetupFlow* flow) : flow_(flow) {} virtual ~RemotingSetupMessageHandler() {} // DOMMessageHandler implementation. + virtual DOMMessageHandler* Attach(DOMUI* dom_ui); + + protected: + // DOMMessageHandler implementation. virtual void RegisterMessages(); // Callbacks from the page. void HandleSubmitAuth(const ListValue* args); - // These functions control which part of the HTML is visible. - // TODO(hclam): I really don't feel right about exposing these as public - // methods. It will be better that we notify RemotingSetupFlow and then get - // a return value for state transition inside this class, or better we merge - // this class into RemotingSetupFlow. - void ShowGaiaSuccessAndSettingUp(); - void ShowGaiaFailed(); - void ShowSetupDone(); - private: - void ExecuteJavascriptInIFrame(const std::wstring& iframe_xpath, - const std::wstring& js); RemotingSetupFlow* flow_; DISALLOW_COPY_AND_ASSIGN(RemotingSetupMessageHandler); |