summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzelidrag@chromium.org <zelidrag@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-16 02:14:21 +0000
committerzelidrag@chromium.org <zelidrag@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-16 02:14:21 +0000
commit64f784cc21f9ad3bae2f2245219e7152514f0ac6 (patch)
treef168f943f67897dce41268497b7d46d0766e914f
parentc8270f52314cb8cf1b20f96630e62dd150403e76 (diff)
downloadchromium_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
-rw-r--r--chrome/browser/browser_resources.grd1
-rw-r--r--chrome/browser/chromeos/login/login_utils.cc7
-rw-r--r--chrome/browser/chromeos/login/merge_session_load_page.cc150
-rw-r--r--chrome/browser/chromeos/login/merge_session_load_page.h86
-rw-r--r--chrome/browser/chromeos/login/merge_session_load_page_unittest.cc127
-rw-r--r--chrome/browser/chromeos/login/merge_session_throttle.cc103
-rw-r--r--chrome/browser/chromeos/login/merge_session_throttle.h51
-rw-r--r--chrome/browser/chromeos/login/mock_user_manager.h2
-rw-r--r--chrome/browser/chromeos/login/oauth2_login_manager.cc2
-rw-r--r--chrome/browser/chromeos/login/oauth_login_manager.h5
-rw-r--r--chrome/browser/chromeos/login/user_manager.h22
-rw-r--r--chrome/browser/chromeos/login/user_manager_impl.cc20
-rw-r--r--chrome/browser/chromeos/login/user_manager_impl.h9
-rw-r--r--chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc6
-rw-r--r--chrome/browser/resources/chromeos/merge_session_load.html61
-rw-r--r--chrome/chrome_browser_chromeos.gypi4
-rw-r--r--chrome/chrome_tests_unit.gypi3
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',