Index: chrome/browser/ui/sync/one_click_signin_sync_observer.cc |
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_observer.cc b/chrome/browser/ui/sync/one_click_signin_sync_observer.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..685e39bb5eb31c9265e4a8c59ca00158ae036853 |
--- /dev/null |
+++ b/chrome/browser/ui/sync/one_click_signin_sync_observer.cc |
@@ -0,0 +1,117 @@ |
+// Copyright 2014 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/ui/sync/one_click_signin_sync_observer.h" |
+ |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/signin/signin_promo.h" |
+#include "chrome/browser/sync/profile_sync_service.h" |
+#include "chrome/browser/sync/profile_sync_service_factory.h" |
+#include "content/public/browser/web_contents.h" |
+#include "content/public/browser/web_contents_delegate.h" |
+ |
+namespace { |
+ |
+void CloseTab(content::WebContents* tab) { |
+ content::WebContentsDelegate* tab_delegate = tab->GetDelegate(); |
+ if (tab_delegate) |
+ tab_delegate->CloseContents(tab); |
+} |
+ |
+} // namespace |
+ |
+ |
+OneClickSigninSyncObserver::OneClickSigninSyncObserver( |
+ content::WebContents* web_contents, |
+ const GURL& continue_url) |
+ : content::WebContentsObserver(web_contents), |
+ continue_url_(continue_url) { |
+ DCHECK(!continue_url_.is_empty()); |
+ |
+ ProfileSyncService* sync_service = GetSyncService(web_contents); |
+ if (sync_service) |
+ sync_service->AddObserver(this); |
+ else |
+ delete this; |
+ |
+ // TODO(isherman): What's the appropriate behavior if there is no sync |
+ // service? Never redirect? |
Ilya Sherman
2014/03/20 08:41:45
^^^
guohui
2014/03/21 19:04:15
PSS is null in incognito mode or if sync is disabl
Ilya Sherman
2014/03/22 00:06:28
Done.
|
+} |
+ |
+OneClickSigninSyncObserver::~OneClickSigninSyncObserver() {} |
+ |
+void OneClickSigninSyncObserver::WebContentsDestroyed( |
+ content::WebContents* web_contents) { |
+ ProfileSyncService* sync_service = GetSyncService(web_contents); |
+ if (sync_service) |
+ sync_service->RemoveObserver(this); |
+ |
+ delete this; |
+} |
+ |
+void OneClickSigninSyncObserver::OnStateChanged() { |
+ ProfileSyncService* sync_service = GetSyncService(web_contents()); |
+ |
+ // At this point, the sign-in process is complete, and control has been handed |
+ // back to the sync engine. Close the gaia sign in tab if the |continue_url_| |
+ // contains the |auto_close| parameter. Otherwise, wait for sync setup to |
+ // complete and then navigate to the |continue_url_|. |
+ if (signin::IsAutoCloseEnabledInURL(continue_url_)) { |
+ // Close the Gaia sign-in tab via a task to make sure we aren't in the |
+ // middle of any WebUI handler code. |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&CloseTab, base::Unretained(web_contents()))); |
+ } else { |
+ if (sync_service->FirstSetupInProgress()) { |
+ // Sync setup has not completed yet. Wait for it to complete. |
+ return; |
+ } |
+ |
+ if (sync_service->sync_initialized() && |
+ signin::GetSourceForPromoURL(continue_url_) |
+ != signin::SOURCE_SETTINGS) { |
+ // TODO(isherman): I'm seeing this case reached with the following STR: |
+ // 0. Open a tab pointed to chrome://settings. |
+ // 1. In a new tab, navigate to the Chrome Webstore. |
+ // 2. Trigger the private API to sign in to Chrome. |
+ // 3. Check the box to "Choose what to syc". |
+ // 4. Enter username and password to sign in. |
+ // 5. Wait for the current tab to be redirected to |
+ // chrome://settings/syncSetup |
+ // 6. Close the original chrome://settings tab. |
+ // 7. At this point, the current tab will redirect back to the Chrome |
+ // Webstore, even though the user hasn't actually configured Sync. |
+ // I don't really understand why closing the first chrome://settings tab |
+ // triggers an OnStateChanged() call. Interestingly, the behavior is |
+ // different from the case where the user clicks "Cancel" in the current |
+ // tab that's showing the "Configure sync" dialog. Also, this code |
+ // doesn't seem to handle the case where the user opts to choose something |
+ // other than "Sync everything". Again, I don't know why -- it works fine |
+ // for the "Sync everything" case, and it's unchanged from the |
+ // pre-existing OneClickSigninHelper logic. This is admittedly all a pile |
+ // of edge-cases, but I'm worried that there might be a lot of these edge |
+ // cases that add up to a bad user experience vs. opening a new tab that |
+ // houses the "Configure sync" settings dialog. WDYT? |
Ilya Sherman
2014/03/20 08:41:45
^^^
guohui
2014/03/21 19:04:15
these sounds like existing bugs in sync code. I su
Ilya Sherman
2014/03/21 19:30:18
I don't actually know how to trigger a similar flo
guohui
2014/03/21 20:00:21
you can trigger inline sign-in flow from the signi
Ilya Sherman
2014/03/21 23:53:32
I tried triggering the sign-in flow from the wrenc
guohui
2014/03/24 21:31:52
i don't think settings page is always a singleton.
|
+ web_contents()->GetController().LoadURL( |
+ continue_url_, |
+ content::Referrer(), |
+ content::PAGE_TRANSITION_AUTO_TOPLEVEL, |
+ std::string()); |
+ } |
+ |
+ // TODO(isherman): What's the appropriate behavior if the user presses |
+ // "Cancel" after opting to "Choose what to sync"? |
Ilya Sherman
2014/03/20 08:41:45
^^^
guohui
2014/03/21 19:04:15
If user presses 'cancel', Chrome would sign out. I
Ilya Sherman
2014/03/21 19:30:18
Actually, the behavior that I observed was that Ch
guohui
2014/03/24 21:31:52
this is actually a known bug, and roger is working
|
+ } |
+ |
+ sync_service->RemoveObserver(this); |
+ delete this; |
+} |
+ |
+ProfileSyncService* OneClickSigninSyncObserver::GetSyncService( |
+ content::WebContents* web_contents) { |
+ Profile* profile = |
+ Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
+ return ProfileSyncServiceFactory::GetForProfile(profile); |
+} |