1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/sync/profile_signin_confirmation_helper.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/string16.h"
11 #include "chrome/browser/bookmarks/bookmark_model.h"
12 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
13 #include "chrome/browser/common/cancelable_request.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/extensions/extension_system.h"
16 #include "chrome/browser/history/history_backend.h"
17 #include "chrome/browser/history/history_db_task.h"
18 #include "chrome/browser/history/history_service.h"
19 #include "chrome/browser/history/history_service_factory.h"
20 #include "chrome/browser/history/history_types.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/common/extensions/sync_helper.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_set.h"
25 #include "ui/gfx/color_utils.h"
26 #include "ui/native_theme/native_theme.h"
30 const int kHistoryEntriesBeforeNewProfilePrompt
= 10;
32 // Determines whether a profile has any typed URLs in its history.
33 class HasTypedURLsTask
: public history::HistoryDBTask
{
35 HasTypedURLsTask(const base::Callback
<void(bool)>& cb
)
36 : has_typed_urls_(false), cb_(cb
) {
39 virtual bool RunOnDBThread(history::HistoryBackend
* backend
,
40 history::HistoryDatabase
* db
) OVERRIDE
{
41 history::URLRows rows
;
42 backend
->GetAllTypedURLs(&rows
);
44 DVLOG(1) << "ProfileSigninConfirmationHelper: profile contains "
45 << rows
.size() << " typed URLs";
46 has_typed_urls_
= true;
51 virtual void DoneRunOnMainThread() OVERRIDE
{
52 cb_
.Run(has_typed_urls_
);
56 virtual ~HasTypedURLsTask() {}
58 base::Callback
<void(bool)> cb_
;
61 bool HasBookmarks(Profile
* profile
) {
62 BookmarkModel
* bookmarks
= BookmarkModelFactory::GetForProfile(profile
);
63 bool has_bookmarks
= bookmarks
&& bookmarks
->HasBookmarks();
65 DVLOG(1) << "ProfileSigninConfirmationHelper: profile contains bookmarks";
69 // Helper functions for Chrome profile signin.
70 class ProfileSigninConfirmationHelper
71 : public base::RefCounted
<ProfileSigninConfirmationHelper
> {
73 ProfileSigninConfirmationHelper(
75 const base::Callback
<void(bool)>& return_result
);
76 void CheckHasHistory(int max_entries
);
77 void CheckHasTypedURLs();
78 void set_pending_requests(int requests
);
81 friend class base::RefCounted
<ProfileSigninConfirmationHelper
>;
83 ~ProfileSigninConfirmationHelper();
85 void OnHistoryQueryResults(size_t max_entries
,
86 CancelableRequestProvider::Handle handle
,
87 history::QueryResults
* results
);
88 void ReturnResult(bool result
);
90 // Weak pointer to the profile being signed-in.
93 // Used for async tasks.
94 CancelableRequestConsumer request_consumer_
;
96 // Keep track of how many async requests are pending.
97 int pending_requests_
;
99 // Indicates whether the result has already been returned to caller.
100 bool result_returned_
;
102 // Callback to pass the result back to the caller.
103 const base::Callback
<void(bool)> return_result_
;
105 DISALLOW_COPY_AND_ASSIGN(ProfileSigninConfirmationHelper
);
108 ProfileSigninConfirmationHelper::ProfileSigninConfirmationHelper(
110 const base::Callback
<void(bool)>& return_result
)
112 pending_requests_(0),
113 result_returned_(false),
114 return_result_(return_result
) {
117 ProfileSigninConfirmationHelper::~ProfileSigninConfirmationHelper() {
120 void ProfileSigninConfirmationHelper::OnHistoryQueryResults(
122 CancelableRequestProvider::Handle handle
,
123 history::QueryResults
* results
) {
124 history::QueryResults owned_results
;
125 results
->Swap(&owned_results
);
126 bool too_much_history
= owned_results
.size() >= max_entries
;
127 if (too_much_history
) {
128 DVLOG(1) << "ProfileSigninConfirmationHelper: profile contains "
129 << owned_results
.size() << " history entries";
131 ReturnResult(too_much_history
);
134 void ProfileSigninConfirmationHelper::CheckHasHistory(int max_entries
) {
135 HistoryService
* service
=
136 HistoryServiceFactory::GetForProfileWithoutCreating(profile_
);
141 history::QueryOptions opts
;
142 opts
.max_count
= max_entries
;
143 service
->QueryHistory(
144 base::string16(), opts
, &request_consumer_
,
145 base::Bind(&ProfileSigninConfirmationHelper::OnHistoryQueryResults
,
150 void ProfileSigninConfirmationHelper::CheckHasTypedURLs() {
151 HistoryService
* service
=
152 HistoryServiceFactory::GetForProfileWithoutCreating(profile_
);
157 service
->ScheduleDBTask(
158 new HasTypedURLsTask(
160 &ProfileSigninConfirmationHelper::ReturnResult
,
165 void ProfileSigninConfirmationHelper::set_pending_requests(int requests
) {
166 pending_requests_
= requests
;
169 void ProfileSigninConfirmationHelper::ReturnResult(bool result
) {
170 // Pass |true| into the callback as soon as one of the tasks passes a
171 // result of |true|, otherwise pass the last returned result.
172 if (!result_returned_
&& (--pending_requests_
== 0 || result
)) {
173 result_returned_
= true;
174 request_consumer_
.CancelAllRequests();
175 return_result_
.Run(result
);
183 SkColor
GetSigninConfirmationPromptBarColor(SkAlpha alpha
) {
184 static const SkColor kBackgroundColor
=
185 ui::NativeTheme::instance()->GetSystemColor(
186 ui::NativeTheme::kColorId_DialogBackground
);
187 return color_utils::BlendTowardOppositeLuminance(kBackgroundColor
, alpha
);
190 bool HasBeenShutdown(Profile
* profile
) {
191 bool has_been_shutdown
= !profile
->IsNewProfile();
192 if (has_been_shutdown
)
193 DVLOG(1) << "ProfileSigninConfirmationHelper: profile is not new";
194 return has_been_shutdown
;
197 bool HasSyncedExtensions(Profile
* profile
) {
198 extensions::ExtensionSystem
* system
=
199 extensions::ExtensionSystem::Get(profile
);
200 if (system
&& system
->extension_service()) {
201 const extensions::ExtensionSet
* extensions
=
202 system
->extension_service()->extensions();
203 for (extensions::ExtensionSet::const_iterator iter
= extensions
->begin();
204 iter
!= extensions
->end(); ++iter
) {
205 // The webstore is synced so that it stays put on the new tab
206 // page, but since it's installed by default we don't want to
207 // consider it when determining if the profile is dirty.
208 if (extensions::sync_helper::IsSyncable(iter
->get()) &&
209 (*iter
)->id() != extension_misc::kWebStoreAppId
&&
210 (*iter
)->id() != extension_misc::kChromeAppId
) {
211 DVLOG(1) << "ProfileSigninConfirmationHelper: "
212 << "profile contains a synced extension: " << (*iter
)->id();
220 void CheckShouldPromptForNewProfile(
222 const base::Callback
<void(bool)>& return_result
) {
223 if (HasBeenShutdown(profile
) ||
224 HasBookmarks(profile
) ||
225 HasSyncedExtensions(profile
)) {
226 return_result
.Run(true);
229 // Fire asynchronous queries for profile data.
230 scoped_refptr
<ProfileSigninConfirmationHelper
> helper
=
231 new ProfileSigninConfirmationHelper(profile
, return_result
);
232 const int requests
= 2;
233 helper
->set_pending_requests(requests
);
234 helper
->CheckHasHistory(kHistoryEntriesBeforeNewProfilePrompt
);
235 helper
->CheckHasTypedURLs();