Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / ui / sync / profile_signin_confirmation_helper.cc
blob5d6debdb6ad1dd294aabda9b48ec83517bbc2c44
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"
7 #include "base/bind.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/string16.h"
11 #include "base/task/cancelable_task_tracker.h"
12 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
13 #include "chrome/browser/history/history_backend.h"
14 #include "chrome/browser/history/history_db_task.h"
15 #include "chrome/browser/history/history_service.h"
16 #include "chrome/browser/history/history_service_factory.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "components/bookmarks/browser/bookmark_model.h"
19 #include "components/history/core/browser/history_types.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "ui/gfx/color_utils.h"
22 #include "ui/native_theme/native_theme.h"
24 #if defined(ENABLE_EXTENSIONS)
25 #include "chrome/browser/extensions/extension_service.h"
26 #include "chrome/common/extensions/extension_constants.h"
27 #include "chrome/common/extensions/sync_helper.h"
28 #include "extensions/browser/extension_system.h"
29 #include "extensions/common/constants.h"
30 #include "extensions/common/extension.h"
31 #include "extensions/common/extension_set.h"
32 #endif
34 namespace {
36 const int kHistoryEntriesBeforeNewProfilePrompt = 10;
38 // Determines whether a profile has any typed URLs in its history.
39 class HasTypedURLsTask : public history::HistoryDBTask {
40 public:
41 explicit HasTypedURLsTask(const base::Callback<void(bool)>& cb)
42 : has_typed_urls_(false), cb_(cb) {
45 virtual bool RunOnDBThread(history::HistoryBackend* backend,
46 history::HistoryDatabase* db) override {
47 history::URLRows rows;
48 backend->GetAllTypedURLs(&rows);
49 if (!rows.empty()) {
50 DVLOG(1) << "ProfileSigninConfirmationHelper: profile contains "
51 << rows.size() << " typed URLs";
52 has_typed_urls_ = true;
54 return true;
57 virtual void DoneRunOnMainThread() override {
58 cb_.Run(has_typed_urls_);
61 private:
62 virtual ~HasTypedURLsTask() {}
64 bool has_typed_urls_;
65 base::Callback<void(bool)> cb_;
68 bool HasBookmarks(Profile* profile) {
69 BookmarkModel* bookmarks = BookmarkModelFactory::GetForProfile(profile);
70 bool has_bookmarks = bookmarks && bookmarks->HasBookmarks();
71 if (has_bookmarks)
72 DVLOG(1) << "ProfileSigninConfirmationHelper: profile contains bookmarks";
73 return has_bookmarks;
76 // Helper functions for Chrome profile signin.
77 class ProfileSigninConfirmationHelper {
78 public:
79 ProfileSigninConfirmationHelper(
80 Profile* profile,
81 const base::Callback<void(bool)>& return_result);
82 void CheckHasHistory(int max_entries);
83 void CheckHasTypedURLs();
85 private:
86 // Deletes itself.
87 ~ProfileSigninConfirmationHelper();
89 void OnHistoryQueryResults(size_t max_entries,
90 history::QueryResults* results);
91 void ReturnResult(bool result);
93 // Weak pointer to the profile being signed-in.
94 Profile* profile_;
96 // Used for async tasks.
97 base::CancelableTaskTracker task_tracker_;
99 // Keep track of how many async requests are pending.
100 int pending_requests_;
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(
109 Profile* profile,
110 const base::Callback<void(bool)>& return_result)
111 : profile_(profile),
112 pending_requests_(0),
113 return_result_(return_result) {
116 ProfileSigninConfirmationHelper::~ProfileSigninConfirmationHelper() {
117 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
120 void ProfileSigninConfirmationHelper::OnHistoryQueryResults(
121 size_t max_entries,
122 history::QueryResults* results) {
123 history::QueryResults owned_results;
124 results->Swap(&owned_results);
125 bool too_much_history = owned_results.size() >= max_entries;
126 if (too_much_history) {
127 DVLOG(1) << "ProfileSigninConfirmationHelper: profile contains "
128 << owned_results.size() << " history entries";
130 ReturnResult(too_much_history);
133 void ProfileSigninConfirmationHelper::CheckHasHistory(int max_entries) {
134 HistoryService* service =
135 HistoryServiceFactory::GetForProfileWithoutCreating(profile_);
136 pending_requests_++;
137 if (!service) {
138 ReturnResult(false);
139 return;
141 history::QueryOptions opts;
142 opts.max_count = max_entries;
143 service->QueryHistory(
144 base::string16(),
145 opts,
146 base::Bind(&ProfileSigninConfirmationHelper::OnHistoryQueryResults,
147 base::Unretained(this),
148 max_entries),
149 &task_tracker_);
152 void ProfileSigninConfirmationHelper::CheckHasTypedURLs() {
153 HistoryService* service =
154 HistoryServiceFactory::GetForProfileWithoutCreating(profile_);
155 pending_requests_++;
156 if (!service) {
157 ReturnResult(false);
158 return;
160 service->ScheduleDBTask(
161 scoped_ptr<history::HistoryDBTask>(new HasTypedURLsTask(
162 base::Bind(&ProfileSigninConfirmationHelper::ReturnResult,
163 base::Unretained(this)))),
164 &task_tracker_);
167 void ProfileSigninConfirmationHelper::ReturnResult(bool result) {
168 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
169 // Pass |true| into the callback as soon as one of the tasks passes a
170 // result of |true|, otherwise pass the last returned result.
171 if (--pending_requests_ == 0 || result) {
172 return_result_.Run(result);
174 // This leaks at shutdown if the HistoryService is destroyed, but
175 // the process is going to die anyway.
176 delete this;
180 } // namespace
182 namespace ui {
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 #if defined(OS_IOS)
193 // This check is not useful on iOS: the browser can be shut down without
194 // explicit user action (for example, in response to memory pressure), and
195 // this should be invisible to the user. The desktop assumption that the
196 // profile going through a restart indicates something about user intention
197 // does not hold. We rely on the other profile dirtiness checks.
198 return false;
199 #else
200 bool has_been_shutdown = !profile->IsNewProfile();
201 if (has_been_shutdown)
202 DVLOG(1) << "ProfileSigninConfirmationHelper: profile is not new";
203 return has_been_shutdown;
204 #endif
207 bool HasSyncedExtensions(Profile* profile) {
208 #if defined(ENABLE_EXTENSIONS)
209 extensions::ExtensionSystem* system =
210 extensions::ExtensionSystem::Get(profile);
211 if (system && system->extension_service()) {
212 const extensions::ExtensionSet* extensions =
213 system->extension_service()->extensions();
214 for (extensions::ExtensionSet::const_iterator iter = extensions->begin();
215 iter != extensions->end(); ++iter) {
216 // The webstore is synced so that it stays put on the new tab
217 // page, but since it's installed by default we don't want to
218 // consider it when determining if the profile is dirty.
219 if (extensions::sync_helper::IsSyncable(iter->get()) &&
220 (*iter)->id() != extensions::kWebStoreAppId &&
221 (*iter)->id() != extension_misc::kChromeAppId) {
222 DVLOG(1) << "ProfileSigninConfirmationHelper: "
223 << "profile contains a synced extension: " << (*iter)->id();
224 return true;
228 #endif
229 return false;
232 void CheckShouldPromptForNewProfile(
233 Profile* profile,
234 const base::Callback<void(bool)>& return_result) {
235 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
237 if (HasBeenShutdown(profile) ||
238 HasBookmarks(profile) ||
239 HasSyncedExtensions(profile)) {
240 return_result.Run(true);
241 return;
243 // Fire asynchronous queries for profile data.
244 ProfileSigninConfirmationHelper* helper =
245 new ProfileSigninConfirmationHelper(profile, return_result);
246 helper->CheckHasHistory(kHistoryEntriesBeforeNewProfilePrompt);
247 helper->CheckHasTypedURLs();
250 } // namespace ui