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_factory.h"
12 #include "chrome/browser/common/cancelable_request.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/history/history_backend.h"
15 #include "chrome/browser/history/history_db_task.h"
16 #include "chrome/browser/history/history_service.h"
17 #include "chrome/browser/history/history_service_factory.h"
18 #include "chrome/browser/history/history_types.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/common/extensions/extension_constants.h"
21 #include "chrome/common/extensions/sync_helper.h"
22 #include "components/bookmarks/browser/bookmark_model.h"
23 #include "extensions/browser/extension_system.h"
24 #include "extensions/common/extension.h"
25 #include "extensions/common/extension_set.h"
26 #include "ui/gfx/color_utils.h"
27 #include "ui/native_theme/native_theme.h"
31 const int kHistoryEntriesBeforeNewProfilePrompt
= 10;
33 // Determines whether a profile has any typed URLs in its history.
34 class HasTypedURLsTask
: public history::HistoryDBTask
{
36 HasTypedURLsTask(const base::Callback
<void(bool)>& cb
)
37 : has_typed_urls_(false), cb_(cb
) {
40 virtual bool RunOnDBThread(history::HistoryBackend
* backend
,
41 history::HistoryDatabase
* db
) OVERRIDE
{
42 history::URLRows rows
;
43 backend
->GetAllTypedURLs(&rows
);
45 DVLOG(1) << "ProfileSigninConfirmationHelper: profile contains "
46 << rows
.size() << " typed URLs";
47 has_typed_urls_
= true;
52 virtual void DoneRunOnMainThread() OVERRIDE
{
53 cb_
.Run(has_typed_urls_
);
57 virtual ~HasTypedURLsTask() {}
59 base::Callback
<void(bool)> cb_
;
62 bool HasBookmarks(Profile
* profile
) {
63 BookmarkModel
* bookmarks
= BookmarkModelFactory::GetForProfile(profile
);
64 bool has_bookmarks
= bookmarks
&& bookmarks
->HasBookmarks();
66 DVLOG(1) << "ProfileSigninConfirmationHelper: profile contains bookmarks";
70 // Helper functions for Chrome profile signin.
71 class ProfileSigninConfirmationHelper
72 : public base::RefCounted
<ProfileSigninConfirmationHelper
> {
74 ProfileSigninConfirmationHelper(
76 const base::Callback
<void(bool)>& return_result
);
77 void CheckHasHistory(int max_entries
);
78 void CheckHasTypedURLs();
79 void set_pending_requests(int requests
);
82 friend class base::RefCounted
<ProfileSigninConfirmationHelper
>;
84 ~ProfileSigninConfirmationHelper();
86 void OnHistoryQueryResults(size_t max_entries
,
87 CancelableRequestProvider::Handle handle
,
88 history::QueryResults
* results
);
89 void ReturnResult(bool result
);
91 // Weak pointer to the profile being signed-in.
94 // Used for async tasks.
95 CancelableRequestConsumer request_consumer_
;
97 // Keep track of how many async requests are pending.
98 int pending_requests_
;
100 // Indicates whether the result has already been returned to caller.
101 bool result_returned_
;
103 // Callback to pass the result back to the caller.
104 const base::Callback
<void(bool)> return_result_
;
106 DISALLOW_COPY_AND_ASSIGN(ProfileSigninConfirmationHelper
);
109 ProfileSigninConfirmationHelper::ProfileSigninConfirmationHelper(
111 const base::Callback
<void(bool)>& return_result
)
113 pending_requests_(0),
114 result_returned_(false),
115 return_result_(return_result
) {
118 ProfileSigninConfirmationHelper::~ProfileSigninConfirmationHelper() {
121 void ProfileSigninConfirmationHelper::OnHistoryQueryResults(
123 CancelableRequestProvider::Handle handle
,
124 history::QueryResults
* results
) {
125 history::QueryResults owned_results
;
126 results
->Swap(&owned_results
);
127 bool too_much_history
= owned_results
.size() >= max_entries
;
128 if (too_much_history
) {
129 DVLOG(1) << "ProfileSigninConfirmationHelper: profile contains "
130 << owned_results
.size() << " history entries";
132 ReturnResult(too_much_history
);
135 void ProfileSigninConfirmationHelper::CheckHasHistory(int max_entries
) {
136 HistoryService
* service
=
137 HistoryServiceFactory::GetForProfileWithoutCreating(profile_
);
142 history::QueryOptions opts
;
143 opts
.max_count
= max_entries
;
144 service
->QueryHistory(
145 base::string16(), opts
, &request_consumer_
,
146 base::Bind(&ProfileSigninConfirmationHelper::OnHistoryQueryResults
,
151 void ProfileSigninConfirmationHelper::CheckHasTypedURLs() {
152 HistoryService
* service
=
153 HistoryServiceFactory::GetForProfileWithoutCreating(profile_
);
158 service
->ScheduleDBTask(
159 new HasTypedURLsTask(
161 &ProfileSigninConfirmationHelper::ReturnResult
,
166 void ProfileSigninConfirmationHelper::set_pending_requests(int requests
) {
167 pending_requests_
= requests
;
170 void ProfileSigninConfirmationHelper::ReturnResult(bool result
) {
171 // Pass |true| into the callback as soon as one of the tasks passes a
172 // result of |true|, otherwise pass the last returned result.
173 if (!result_returned_
&& (--pending_requests_
== 0 || result
)) {
174 result_returned_
= true;
175 request_consumer_
.CancelAllRequests();
176 return_result_
.Run(result
);
184 SkColor
GetSigninConfirmationPromptBarColor(SkAlpha alpha
) {
185 static const SkColor kBackgroundColor
=
186 ui::NativeTheme::instance()->GetSystemColor(
187 ui::NativeTheme::kColorId_DialogBackground
);
188 return color_utils::BlendTowardOppositeLuminance(kBackgroundColor
, alpha
);
191 bool HasBeenShutdown(Profile
* profile
) {
192 bool has_been_shutdown
= !profile
->IsNewProfile();
193 if (has_been_shutdown
)
194 DVLOG(1) << "ProfileSigninConfirmationHelper: profile is not new";
195 return has_been_shutdown
;
198 bool HasSyncedExtensions(Profile
* profile
) {
199 extensions::ExtensionSystem
* system
=
200 extensions::ExtensionSystem::Get(profile
);
201 if (system
&& system
->extension_service()) {
202 const extensions::ExtensionSet
* extensions
=
203 system
->extension_service()->extensions();
204 for (extensions::ExtensionSet::const_iterator iter
= extensions
->begin();
205 iter
!= extensions
->end(); ++iter
) {
206 // The webstore is synced so that it stays put on the new tab
207 // page, but since it's installed by default we don't want to
208 // consider it when determining if the profile is dirty.
209 if (extensions::sync_helper::IsSyncable(iter
->get()) &&
210 (*iter
)->id() != extension_misc::kWebStoreAppId
&&
211 (*iter
)->id() != extension_misc::kChromeAppId
) {
212 DVLOG(1) << "ProfileSigninConfirmationHelper: "
213 << "profile contains a synced extension: " << (*iter
)->id();
221 void CheckShouldPromptForNewProfile(
223 const base::Callback
<void(bool)>& return_result
) {
224 if (HasBeenShutdown(profile
) ||
225 HasBookmarks(profile
) ||
226 HasSyncedExtensions(profile
)) {
227 return_result
.Run(true);
230 // Fire asynchronous queries for profile data.
231 scoped_refptr
<ProfileSigninConfirmationHelper
> helper
=
232 new ProfileSigninConfirmationHelper(profile
, return_result
);
233 const int requests
= 2;
234 helper
->set_pending_requests(requests
);
235 helper
->CheckHasHistory(kHistoryEntriesBeforeNewProfilePrompt
);
236 helper
->CheckHasTypedURLs();