diff options
author | zelidrag@chromium.org <zelidrag@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-16 02:14:21 +0000 |
---|---|---|
committer | zelidrag@chromium.org <zelidrag@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-16 02:14:21 +0000 |
commit | 64f784cc21f9ad3bae2f2245219e7152514f0ac6 (patch) | |
tree | f168f943f67897dce41268497b7d46d0766e914f | |
parent | c8270f52314cb8cf1b20f96630e62dd150403e76 (diff) | |
download | chromium_src-64f784cc21f9ad3bae2f2245219e7152514f0ac6.zip chromium_src-64f784cc21f9ad3bae2f2245219e7152514f0ac6.tar.gz chromium_src-64f784cc21f9ad3bae2f2245219e7152514f0ac6.tar.bz2 |
Added interstitial page for merge session. This page will let us delay loading of Google properties during ChromeOS cookie session restore at login (aka /MergeSession).
The interstitial page will show 3 seconds of no UI (white tab) followed with up to 7 seconds of UI with only "Loading..." message showing in tabs. For huge majority of cases, that secondary UI won't show since merge session will probably complete by then.
BUG=171980
TEST=added merge_session_load_page_unittest.cc
TBR=sky
Review URL: https://codereview.chromium.org/12256046
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182894 0039d316-1c4b-4281-b951-d872f2087c98
17 files changed, 653 insertions, 6 deletions
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index b364ba3..5450283 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd @@ -283,6 +283,7 @@ <include name="IDR_NOTIFICATION_ICON_LINK_HTML" file="resources\chromeos\notification_icon_link.html" type="BINDATA" /> <include name="IDR_ECHO_MANIFEST" file="resources\chromeos\echo\manifest.json" type="BINDATA" /> <include name="IDR_OFFLINE_LOAD_HTML" file="resources\chromeos\offline_load.html" flattenhtml="true" type="BINDATA" /> + <include name="IDR_MERGE_SESSION_LOAD_HTML" file="resources\chromeos\merge_session_load.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_OS_CREDITS_HTML" file="resources\chromeos\about_os_credits.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_PROXY_SETTINGS_HTML" file="resources\chromeos\proxy_settings.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_BLUETOOTH_PAIR_DEVICE_HTML" file="resources\chromeos\bluetooth_pair_device.html" flattenhtml="true" type="BINDATA" /> diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc index e1874f9..482174c 100644 --- a/chrome/browser/chromeos/login/login_utils.cc +++ b/chrome/browser/chromeos/login/login_utils.cc @@ -229,6 +229,7 @@ class LoginUtilsImpl virtual void InitRlzDelayed(Profile* user_profile) OVERRIDE; // OAuthLoginManager::Delegate overrides. + virtual void OnCompletedMergeSession() OVERRIDE; virtual void OnCompletedAuthentication(Profile* user_profile) OVERRIDE; virtual void OnFoundStoredTokens() OVERRIDE; @@ -561,6 +562,8 @@ void LoginUtilsImpl::RestoreAuthSession(Profile* user_profile, if (!login_manager_.get()) return; + UserManager::Get()->SetMergeSessionState( + UserManager::MERGE_STATUS_IN_PROCESS); // Remove legacy OAuth1 token if we have one. If it's valid, we should already // have OAuth2 refresh token in TokenService that could be used to retrieve // all other tokens and credentials. @@ -997,6 +1000,10 @@ void LoginUtilsImpl::OnCompletedAuthentication(Profile* user_profile) { StartSignedInServices(user_profile); } +void LoginUtilsImpl::OnCompletedMergeSession() { + UserManager::Get()->SetMergeSessionState(UserManager::MERGE_STATUS_DONE); +} + void LoginUtilsImpl::OnFoundStoredTokens() { // We don't need authenticator instance any more since its cookie jar // is not going to needed to mint OAuth tokens. Reset it so that diff --git a/chrome/browser/chromeos/login/merge_session_load_page.cc b/chrome/browser/chromeos/login/merge_session_load_page.cc new file mode 100644 index 0000000..c1c8c60 --- /dev/null +++ b/chrome/browser/chromeos/login/merge_session_load_page.cc @@ -0,0 +1,150 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/login/merge_session_load_page.h" + +#include "ash/shell.h" +#include "ash/shell_delegate.h" +#include "ash/system/tray/system_tray_delegate.h" +#include "base/i18n/rtl.h" +#include "base/metrics/histogram.h" +#include "base/string_piece.h" +#include "base/stringprintf.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros/network_library.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_system.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/renderer_preferences_util.h" +#include "chrome/browser/tab_contents/tab_util.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_constants.h" +#include "chrome/common/extensions/extension_icon_set.h" +#include "chrome/common/url_constants.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/interstitial_page.h" +#include "content/public/browser/notification_types.h" +#include "content/public/browser/web_contents.h" +#include "grit/browser_resources.h" +#include "grit/generated_resources.h" +#include "net/base/escape.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/webui/jstemplate_builder.h" + +using content::BrowserThread; +using content::InterstitialPage; +using content::WebContents; + +namespace { + +// Delay time for showing interstitial page. +const int kShowDelayTimeMS = 1000; + +// Maximum time for showing interstitial page. +const int kTotalWaitTimeMS = 10000; + +} // namespace + +namespace chromeos { + +MergeSessionLoadPage::MergeSessionLoadPage(WebContents* web_contents, + const GURL& url, + const CompletionCallback& callback) + : callback_(callback), + proceeded_(false), + web_contents_(web_contents), + url_(url) { + UserManager::Get()->AddObserver(this); + interstitial_page_ = InterstitialPage::Create(web_contents, true, url, this); +} + +MergeSessionLoadPage::~MergeSessionLoadPage() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + UserManager::Get()->RemoveObserver(this); +} + +void MergeSessionLoadPage::Show() { + interstitial_page_->Show(); +} + +std::string MergeSessionLoadPage::GetHTMLContents() { + DictionaryValue strings; + strings.SetString("title", web_contents_->GetTitle()); + // Set the timeout to show the page. + strings.SetInteger("show_delay_time", kShowDelayTimeMS); + strings.SetInteger("total_wait_time", kTotalWaitTimeMS); + // TODO(zelidrag): Flip the message to IDS_MERGE_SESSION_LOAD_HEADLINE + // after merge. + strings.SetString("heading", + l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE)); + + bool rtl = base::i18n::IsRTL(); + strings.SetString("textdirection", rtl ? "rtl" : "ltr"); + + base::StringPiece html( + ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_MERGE_SESSION_LOAD_HTML)); + return webui::GetI18nTemplateHtml(html, &strings); +} + +void MergeSessionLoadPage::OverrideRendererPrefs( + content::RendererPreferences* prefs) { + Profile* profile = Profile::FromBrowserContext( + web_contents_->GetBrowserContext()); + renderer_preferences_util::UpdateFromSystemSettings(prefs, profile); +} + +void MergeSessionLoadPage::OnProceed() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + proceeded_ = true; + NotifyBlockingPageComplete(); +} + +void MergeSessionLoadPage::OnDontProceed() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + // Ignore if it's already proceeded. + if (proceeded_) + return; + NotifyBlockingPageComplete(); +} + +void MergeSessionLoadPage::CommandReceived(const std::string& cmd) { + std::string command(cmd); + // The Jasonified response has quotes, remove them. + if (command.length() > 1 && command[0] == '"') + command = command.substr(1, command.length() - 2); + + if (command == "proceed") { + interstitial_page_->Proceed(); + } else { + DVLOG(1) << "Unknown command:" << cmd; + } +} + +void MergeSessionLoadPage::NotifyBlockingPageComplete() { + if (!callback_.is_null()) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, callback_); + } +} + +void MergeSessionLoadPage::MergeSessionStateChanged( + UserManager::MergeSessionState state) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DVLOG(1) << "Merge session is " + << (state != UserManager:: MERGE_STATUS_IN_PROCESS ? + " NOT " : "") + << " in progress, " + << state; + if (state != UserManager:: MERGE_STATUS_IN_PROCESS) { + UserManager::Get()->RemoveObserver(this); + interstitial_page_->Proceed(); + } +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/login/merge_session_load_page.h b/chrome/browser/chromeos/login/merge_session_load_page.h new file mode 100644 index 0000000..39fba94 --- /dev/null +++ b/chrome/browser/chromeos/login/merge_session_load_page.h @@ -0,0 +1,86 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_MERGE_SESSION_LOAD_PAGE_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_MERGE_SESSION_LOAD_PAGE_H_ + +#include <string> + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "chrome/browser/chromeos/login/user_manager.h" +#include "content/public/browser/interstitial_page_delegate.h" +#include "googleurl/src/gurl.h" + +namespace base { +class DictionaryValue; +} + +namespace content { +class InterstitialPage; +class WebContents; +} + +namespace extensions { +class Extension; +} + +namespace chromeos { + +// MergeSessionLoadPage class shows the interstitial page that is shown +// while we are trying to restore session containing tabs with Google properties +// during the process of exchanging OAuth2 refresh token for user cookies. +// It deletes itself when the interstitial page is closed. +class MergeSessionLoadPage + : public content::InterstitialPageDelegate, + public UserManager::Observer { + public: + // Passed a boolean indicating whether or not it is OK to proceed with the + // page load. + typedef base::Closure CompletionCallback; + + // Create a merge session load delay page for the |web_contents|. + // The |callback| will be run on the IO thread. + MergeSessionLoadPage(content::WebContents* web_contents, + const GURL& url, + const CompletionCallback& callback); + + void Show(); + + protected: + virtual ~MergeSessionLoadPage(); + + private: + friend class TestMergeSessionLoadPage; + + // InterstitialPageDelegate implementation. + virtual std::string GetHTMLContents() OVERRIDE; + virtual void CommandReceived(const std::string& command) OVERRIDE; + virtual void OverrideRendererPrefs( + content::RendererPreferences* prefs) OVERRIDE; + virtual void OnProceed() OVERRIDE; + virtual void OnDontProceed() OVERRIDE; + + // UserManager::Observer overrides. + virtual void MergeSessionStateChanged( + UserManager::MergeSessionState state) OVERRIDE; + virtual void LocalStateChanged(UserManager* user_manager) OVERRIDE {} + + void NotifyBlockingPageComplete(); + + CompletionCallback callback_; + + // True if the proceed is chosen. + bool proceeded_; + + content::WebContents* web_contents_; + GURL url_; + content::InterstitialPage* interstitial_page_; // Owns us. + + DISALLOW_COPY_AND_ASSIGN(MergeSessionLoadPage); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_MERGE_SESSION_LOAD_PAGE_H_ diff --git a/chrome/browser/chromeos/login/merge_session_load_page_unittest.cc b/chrome/browser/chromeos/login/merge_session_load_page_unittest.cc new file mode 100644 index 0000000..c9c7225 --- /dev/null +++ b/chrome/browser/chromeos/login/merge_session_load_page_unittest.cc @@ -0,0 +1,127 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/login/merge_session_load_page.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "content/public/browser/interstitial_page.h" +#include "content/public/browser/navigation_controller.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/test_browser_thread.h" +#include "content/public/test/web_contents_tester.h" + +using content::BrowserThread; +using content::InterstitialPage; +using content::WebContents; +using content::WebContentsTester; + +namespace { + +const char kURL1[] = "http://www.google.com/"; +const char kURL2[] = "http://mail.google.com/"; + +} // namespace + +namespace chromeos { + +class MergeSessionLoadPageTest; + +// An MergeSessionLoadPage class that does not create windows. +class TestMergeSessionLoadPage : public MergeSessionLoadPage { + public: + TestMergeSessionLoadPage(WebContents* web_contents, + const GURL& url, + MergeSessionLoadPageTest* test_page) + : MergeSessionLoadPage(web_contents, url, CompletionCallback()), + test_page_(test_page) { + interstitial_page_->DontCreateViewForTesting(); + } + + private: + MergeSessionLoadPageTest* test_page_; + + DISALLOW_COPY_AND_ASSIGN(TestMergeSessionLoadPage); +}; + +class MergeSessionLoadPageTest : public ChromeRenderViewHostTestHarness { + public: + MergeSessionLoadPageTest() + : ui_thread_(BrowserThread::UI, MessageLoop::current()), + file_user_blocking_thread_( + BrowserThread::FILE_USER_BLOCKING, MessageLoop::current()), + io_thread_(BrowserThread::IO, MessageLoop::current()) { + } + + void Navigate(const char* url, int page_id) { + WebContentsTester::For(web_contents())->TestDidNavigate( + web_contents()->GetRenderViewHost(), page_id, GURL(url), + content::PAGE_TRANSITION_TYPED); + } + + void ShowInterstitial(const char* url) { + (new TestMergeSessionLoadPage(web_contents(), GURL(url), this))->Show(); + } + + // Returns the MergeSessionLoadPage currently showing or NULL if none is + // showing. + InterstitialPage* GetMergeSessionLoadPage() { + return InterstitialPage::GetInterstitialPage(web_contents()); + } + + private: + content::TestBrowserThread ui_thread_; + content::TestBrowserThread file_user_blocking_thread_; + content::TestBrowserThread io_thread_; + + // Initializes / shuts down a stub CrosLibrary. + chromeos::ScopedStubCrosEnabler stub_cros_enabler_; + + DISALLOW_COPY_AND_ASSIGN(MergeSessionLoadPageTest); +}; + +TEST_F(MergeSessionLoadPageTest, MergeSessionPageNotShown) { + UserManager::Get()->SetMergeSessionState( + UserManager::MERGE_STATUS_DONE); + // Start a load. + Navigate(kURL1, 1); + // Load next page. + controller().LoadURL(GURL(kURL2), content::Referrer(), + content::PAGE_TRANSITION_TYPED, std::string()); + + // Simulate the load causing an merge session interstitial page + // to be shown. + InterstitialPage* interstitial = GetMergeSessionLoadPage(); + EXPECT_FALSE(interstitial); +} + +TEST_F(MergeSessionLoadPageTest, MergeSessionPageShown) { + UserManager::Get()->SetMergeSessionState( + UserManager::MERGE_STATUS_IN_PROCESS); + // Start a load. + Navigate(kURL1, 1); + // Load next page. + controller().LoadURL(GURL(kURL2), content::Referrer(), + content::PAGE_TRANSITION_TYPED, std::string()); + + // Simulate the load causing an merge session interstitial page + // to be shown. + ShowInterstitial(kURL2); + InterstitialPage* interstitial = GetMergeSessionLoadPage(); + ASSERT_TRUE(interstitial); + MessageLoop::current()->RunUntilIdle(); + + // Simulate merge session completion. + UserManager::Get()->SetMergeSessionState( + UserManager::MERGE_STATUS_DONE); + MessageLoop::current()->RunUntilIdle(); + + // The URL remains to be URL2. + EXPECT_EQ(kURL2, web_contents()->GetURL().spec()); + + // Commit navigation and the interstitial page is gone. + Navigate(kURL2, 2); + EXPECT_FALSE(GetMergeSessionLoadPage()); +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/login/merge_session_throttle.cc b/chrome/browser/chromeos/login/merge_session_throttle.cc new file mode 100644 index 0000000..0fe3416 --- /dev/null +++ b/chrome/browser/chromeos/login/merge_session_throttle.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/login/merge_session_throttle.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/memory/singleton.h" +#include "base/metrics/histogram.h" +#include "base/string_util.h" +#include "chrome/browser/chromeos/login/login_utils.h" +#include "chrome/browser/google/google_util.h" +#include "chrome/browser/net/chrome_url_request_context.h" +#include "chrome/common/url_constants.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/resource_controller.h" +#include "content/public/browser/web_contents.h" +#include "net/base/net_errors.h" +#include "net/base/net_util.h" +#include "net/base/network_change_notifier.h" +#include "net/url_request/url_request.h" +#include "net/url_request/url_request_context.h" + +using content::BrowserThread; +using content::RenderViewHost; +using content::WebContents; + +namespace { + +void ShowDeleayedLoadingPage( + int render_process_id, + int render_view_id, + const GURL& url, + const chromeos::MergeSessionLoadPage::CompletionCallback& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // Check again on UI thread and proceed if it's connected. + if (chromeos::UserManager::Get()->GetMergeSessionState() != + chromeos::UserManager::MERGE_STATUS_IN_PROCESS) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, callback); + } else { + RenderViewHost* render_view_host = + RenderViewHost::FromID(render_process_id, render_view_id); + WebContents* web_contents = render_view_host ? + WebContents::FromRenderViewHost(render_view_host) : NULL; + // There is a chance that the tab closed after we decided to show + // the offline page on the IO thread and before we actually show the + // offline page here on the UI thread. + if (web_contents) + (new chromeos::MergeSessionLoadPage(web_contents, url, callback))->Show(); + } +} + +} // namespace + +MergeSessionThrottle::MergeSessionThrottle(int render_process_id, + int render_view_id, + net::URLRequest* request) + : render_process_id_(render_process_id), + render_view_id_(render_view_id), + request_(request) { +} + +MergeSessionThrottle::~MergeSessionThrottle() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); +} + +void MergeSessionThrottle::WillStartRequest(bool* defer) { + if (!ShouldShowMergeSessionPage(request_->url())) + return; + + DVLOG(1) << "WillStartRequest: url=" << request_->url(); + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind( + &ShowDeleayedLoadingPage, + render_process_id_, + render_view_id_, + request_->url(), + base::Bind( + &MergeSessionThrottle::OnBlockingPageComplete, + AsWeakPtr()))); + *defer = true; +} + +void MergeSessionThrottle::OnBlockingPageComplete() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + controller()->Resume(); +} + +bool MergeSessionThrottle::ShouldShowMergeSessionPage(const GURL& url) const { + // If we are loading google properties while merge session is in progress, + // we will show delayed loading page instead. + return !net::NetworkChangeNotifier::IsOffline() && + google_util::IsGoogleHostname(url.host(), + google_util::ALLOW_SUBDOMAIN) && + chromeos::UserManager::Get()->GetMergeSessionState() == + chromeos::UserManager::MERGE_STATUS_IN_PROCESS; +} diff --git a/chrome/browser/chromeos/login/merge_session_throttle.h b/chrome/browser/chromeos/login/merge_session_throttle.h new file mode 100644 index 0000000..ad1b258 --- /dev/null +++ b/chrome/browser/chromeos/login/merge_session_throttle.h @@ -0,0 +1,51 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_MERGE_SESSION_THROTTLE_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_MERGE_SESSION_THROTTLE_H_ + +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/login/merge_session_load_page.h" +#include "content/public/browser/resource_throttle.h" +#include "net/base/completion_callback.h" + +namespace net { +class URLRequest; +} + +// Used to show an interstitial page while merge session process (cookie +// reconstruction from OAuth2 refresh token in ChromeOS login) is still in +// progress while we are attempting to load a google property. +class MergeSessionThrottle + : public content::ResourceThrottle, + public base::SupportsWeakPtr<MergeSessionThrottle> { + public: + MergeSessionThrottle(int render_process_id, + int render_view_id, + net::URLRequest* request); + virtual ~MergeSessionThrottle(); + + // content::ResourceThrottle implementation: + virtual void WillStartRequest(bool* defer) OVERRIDE; + + private: + // MergeSessionLoadPage callback. + void OnBlockingPageComplete(); + + // Erase the state associated with a deferred load request. + void ClearRequestInfo(); + bool IsRemote(const GURL& url) const; + + // True if we should show the merge session in progress page. + bool ShouldShowMergeSessionPage(const GURL& url) const; + + int render_process_id_; + int render_view_id_; + net::URLRequest* request_; + + DISALLOW_COPY_AND_ASSIGN(MergeSessionThrottle); +}; + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_MERGE_SESSION_THROTTLE_H_ diff --git a/chrome/browser/chromeos/login/mock_user_manager.h b/chrome/browser/chromeos/login/mock_user_manager.h index a7e7153..ab4a35b 100644 --- a/chrome/browser/chromeos/login/mock_user_manager.h +++ b/chrome/browser/chromeos/login/mock_user_manager.h @@ -66,6 +66,8 @@ class MockUserManager : public UserManager { MOCK_METHOD1(RemoveObserver, void(UserManager::Observer*)); MOCK_METHOD0(NotifyLocalStateChanged, void(void)); MOCK_METHOD0(CreateLocallyManagedUserRecord, void(void)); + MOCK_CONST_METHOD0(GetMergeSessionState, MergeSessionState(void)); + MOCK_METHOD1(SetMergeSessionState, void(MergeSessionState)); // You can't mock this function easily because nobody can create User objects // but the UserManagerImpl and us. diff --git a/chrome/browser/chromeos/login/oauth2_login_manager.cc b/chrome/browser/chromeos/login/oauth2_login_manager.cc index 2497fb5..c719a28b 100644 --- a/chrome/browser/chromeos/login/oauth2_login_manager.cc +++ b/chrome/browser/chromeos/login/oauth2_login_manager.cc @@ -242,6 +242,7 @@ void OAuth2LoginManager::OnSessionMergeSuccess() { UMA_HISTOGRAM_ENUMERATION("OAuth2Login.SessionRestore", SESSION_RESTORE_SUCCESS, SESSION_RESTORE_COUNT); + delegate_->OnCompletedMergeSession(); } void OAuth2LoginManager::OnSessionMergeFailure() { @@ -253,6 +254,7 @@ void OAuth2LoginManager::OnSessionMergeFailure() { UMA_HISTOGRAM_ENUMERATION("OAuth2Login.SessionRestore", SESSION_RESTORE_MERGE_SESSION_FAILED, SESSION_RESTORE_COUNT); + delegate_->OnCompletedMergeSession(); } void OAuth2LoginManager::StartTokenService( diff --git a/chrome/browser/chromeos/login/oauth_login_manager.h b/chrome/browser/chromeos/login/oauth_login_manager.h index bb55f5d..211d615 100644 --- a/chrome/browser/chromeos/login/oauth_login_manager.h +++ b/chrome/browser/chromeos/login/oauth_login_manager.h @@ -5,8 +5,6 @@ #ifndef CHROME_BROWSER_CHROMEOS_LOGIN_OAUTH_LOGIN_MANAGER_H_ #define CHROME_BROWSER_CHROMEOS_LOGIN_OAUTH_LOGIN_MANAGER_H_ -#include <string> - #include "base/memory/ref_counted.h" #include "net/url_request/url_request_context_getter.h" @@ -32,6 +30,9 @@ class OAuthLoginManager { public: virtual ~Delegate() {} + // Raised when merge session is completed. + virtual void OnCompletedMergeSession() = 0; + // Raised when cookie jar authentication is successfully completed. virtual void OnCompletedAuthentication(Profile* user_profile) = 0; diff --git a/chrome/browser/chromeos/login/user_manager.h b/chrome/browser/chromeos/login/user_manager.h index 13a95dd..168ea81 100644 --- a/chrome/browser/chromeos/login/user_manager.h +++ b/chrome/browser/chromeos/login/user_manager.h @@ -21,13 +21,27 @@ class UserImageManager; // who have logged into this Chrome OS device before and updating that list. class UserManager { public: + // Status of merge sessions process which is responsible for exchanging + // user OAuth2 refresh token for GAIA cookies. + enum MergeSessionState { + // Session merge hasn't started yet. + MERGE_STATUS_NOT_STARTED, + // Session merge is in process. + MERGE_STATUS_IN_PROCESS, + // Session merge is completed. + MERGE_STATUS_DONE, + }; + // Interface that observers of UserManager must implement in order // to receive notification when local state preferences is changed class Observer { public: - // Called when the local state preferences is changed + // Called when the local state preferences is changed. virtual void LocalStateChanged(UserManager* user_manager) = 0; + // Called when merge session state is changed. + virtual void MergeSessionStateChanged(MergeSessionState state) {} + protected: virtual ~Observer() {} }; @@ -211,6 +225,12 @@ class UserManager { // or restart after crash. virtual bool IsSessionStarted() const = 0; + // Returns merge session status. + virtual MergeSessionState GetMergeSessionState() const = 0; + + // Changes merge session status. + virtual void SetMergeSessionState(MergeSessionState status) = 0; + // Returns true when the browser has crashed and restarted during the current // user's session. virtual bool HasBrowserRestarted() const = 0; diff --git a/chrome/browser/chromeos/login/user_manager_impl.cc b/chrome/browser/chromeos/login/user_manager_impl.cc index 8c4450c..d56aa50 100644 --- a/chrome/browser/chromeos/login/user_manager_impl.cc +++ b/chrome/browser/chromeos/login/user_manager_impl.cc @@ -181,6 +181,7 @@ UserManagerImpl::UserManagerImpl() is_current_user_new_(false), is_current_user_ephemeral_regular_user_(false), ephemeral_users_enabled_(false), + merge_session_state_(MERGE_STATUS_NOT_STARTED), observed_sync_service_(NULL), user_image_manager_(new UserImageManagerImpl) { // UserManager instance should be used only on UI thread. @@ -725,6 +726,19 @@ bool UserManagerImpl::IsSessionStarted() const { return session_started_; } +UserManager::MergeSessionState UserManagerImpl::GetMergeSessionState() const { + return merge_session_state_; +} + +void UserManagerImpl::SetMergeSessionState( + UserManager::MergeSessionState state) { + if (merge_session_state_ == state) + return; + + merge_session_state_ = state; + NotifyMergeSessionStateChanged(); +} + bool UserManagerImpl::HasBrowserRestarted() const { CommandLine* command_line = CommandLine::ForCurrentProcess(); return base::chromeos::IsRunningOnChromeOS() && @@ -1087,4 +1101,10 @@ void UserManagerImpl::NotifyUserListChanged() { content::NotificationService::NoDetails()); } +void UserManagerImpl::NotifyMergeSessionStateChanged() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + FOR_EACH_OBSERVER(UserManager::Observer, observer_list_, + MergeSessionStateChanged(merge_session_state_)); +} + } // namespace chromeos diff --git a/chrome/browser/chromeos/login/user_manager_impl.h b/chrome/browser/chromeos/login/user_manager_impl.h index 9e0af15..1594d18 100644 --- a/chrome/browser/chromeos/login/user_manager_impl.h +++ b/chrome/browser/chromeos/login/user_manager_impl.h @@ -90,6 +90,8 @@ class UserManagerImpl virtual bool IsLoggedInAsLocallyManagedUser() const OVERRIDE; virtual bool IsLoggedInAsStub() const OVERRIDE; virtual bool IsSessionStarted() const OVERRIDE; + virtual MergeSessionState GetMergeSessionState() const OVERRIDE; + virtual void SetMergeSessionState(MergeSessionState status) OVERRIDE; virtual bool HasBrowserRestarted() const OVERRIDE; virtual bool IsUserNonCryptohomeDataEphemeral( const std::string& email) const OVERRIDE; @@ -171,6 +173,9 @@ class UserManagerImpl // Notifies the UI about a change to the user list. void NotifyUserListChanged(); + // Notifies observers that merge session state had changed. + void NotifyMergeSessionStateChanged(); + // Interface to the signed settings store. CrosSettings* cros_settings_; @@ -214,8 +219,8 @@ class UserManagerImpl // policy yet. bool ephemeral_users_enabled_; - // True if user pod row is showed at login screen. - bool show_users_; + // Merge session state (cookie restore process state). + MergeSessionState merge_session_state_; // Cached name of device owner. Defaults to empty string if the value has not // been read from trusted device policy yet. diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc index bf74c49..d35292b 100644 --- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc +++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc @@ -60,6 +60,7 @@ #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/extensions/file_browser_resource_throttle.h" +#include "chrome/browser/chromeos/login/merge_session_throttle.h" // TODO(oshima): Enable this for other platforms. #include "chrome/browser/renderer_host/offline_resource_throttle.h" #endif @@ -162,6 +163,11 @@ void ChromeResourceDispatcherHostDelegate::RequestBeginning( // block unsafe site after we remove offline page. throttles->push_back(new OfflineResourceThrottle( child_id, route_id, request, appcache_service)); + // Add interstitial page while merge session process (cookie + // reconstruction from OAuth2 refresh token in ChromeOS login) is still in + // progress while we are attempting to load a google property. + throttles->push_back(new MergeSessionThrottle( + child_id, route_id, request)); } #endif diff --git a/chrome/browser/resources/chromeos/merge_session_load.html b/chrome/browser/resources/chromeos/merge_session_load.html new file mode 100644 index 0000000..54bb0ec5 --- /dev/null +++ b/chrome/browser/resources/chromeos/merge_session_load.html @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<html i18n-values="dir:textdirection"> +<head> +<title i18n-content="title"> +</title> +<style> +html { + height: 100%; +} +body { + -webkit-user-select: none; + background: white; + color: #000; + display: -webkit-box; + font-family: arial, sans-serif; + height: 100%; + margin: 0; + padding: 0; + visibility: hidden; + width: 100%; +} + +.header { + font-family: Sans-serif; + padding: 3px; + width: 80%; +} +</style> +<script src="../../../../ui/webui/resources/js/local_strings.js"></script> + +<script> +var localStrings = new LocalStrings(); + +function sendCommand(cmd) { + window.domAutomationController.setAutomationId(1); + window.domAutomationController.send(cmd); +} + +// Show the interstitial page. +function showPage() { + document.body.style.visibility = 'visible'; +} + +// Show the interstitial page. +function forceLoad() { + sendCommand('proceed'); +} + +document.addEventListener('DOMContentLoaded', function() { + var show_delay_time = localStrings.getString('show_delay_time'); + var total_wait_time = localStrings.getString('total_wait_time'); + window.setTimeout(showPage, show_delay_time); + window.setTimeout(forceLoad, total_wait_time); +}); +</script> + +<body oncontextmenu="return false;"> + <div class="header" i18n-content="heading"> + </div> +</body> +</html> diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi index 5af5f91..e62642f 100644 --- a/chrome/chrome_browser_chromeos.gypi +++ b/chrome/chrome_browser_chromeos.gypi @@ -410,6 +410,10 @@ 'browser/chromeos/login/login_wizard.h', 'browser/chromeos/login/message_bubble.cc', 'browser/chromeos/login/message_bubble.h', + 'browser/chromeos/login/merge_session_load_page.cc', + 'browser/chromeos/login/merge_session_load_page.h', + 'browser/chromeos/login/merge_session_throttle.cc', + 'browser/chromeos/login/merge_session_throttle.h', 'browser/chromeos/login/network_screen.cc', 'browser/chromeos/login/network_screen.h', 'browser/chromeos/login/network_screen_actor.h', diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 47f0ba7..4fa85a4 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -624,8 +624,9 @@ 'browser/chromeos/kiosk_mode/kiosk_mode_idle_logout_unittest.cc', 'browser/chromeos/kiosk_mode/kiosk_mode_settings_unittest.cc', 'browser/chromeos/language_preferences_unittest.cc', - 'browser/chromeos/login/mock_auth_attempt_state_resolver.cc', 'browser/chromeos/login/hwid_checker_unittest.cc', + 'browser/chromeos/login/merge_session_load_page_unittest.cc', + 'browser/chromeos/login/mock_auth_attempt_state_resolver.cc', 'browser/chromeos/login/mock_auth_attempt_state_resolver.h', 'browser/chromeos/login/online_attempt_unittest.cc', 'browser/chromeos/login/parallel_authenticator_unittest.cc', |