OLD | NEW |
---|---|
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/win/jumplist.h" | 5 #include "chrome/browser/win/jumplist.h" |
6 | 6 |
7 #include "base/base_paths.h" | 7 #include "base/base_paths.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
46 #include "ui/gfx/codec/png_codec.h" | 46 #include "ui/gfx/codec/png_codec.h" |
47 #include "ui/gfx/favicon_size.h" | 47 #include "ui/gfx/favicon_size.h" |
48 #include "ui/gfx/icon_util.h" | 48 #include "ui/gfx/icon_util.h" |
49 #include "ui/gfx/image/image.h" | 49 #include "ui/gfx/image/image.h" |
50 #include "ui/gfx/image/image_family.h" | 50 #include "ui/gfx/image/image_family.h" |
51 #include "ui/gfx/image/image_skia.h" | 51 #include "ui/gfx/image/image_skia.h" |
52 #include "ui/gfx/image/image_skia_rep.h" | 52 #include "ui/gfx/image/image_skia_rep.h" |
53 #include "url/gurl.h" | 53 #include "url/gurl.h" |
54 | 54 |
55 using content::BrowserThread; | 55 using content::BrowserThread; |
56 using JumpListData = JumpList::JumpListData; | |
57 | 56 |
58 namespace { | 57 namespace { |
59 | 58 |
60 // The default maximum number of items to display in JumpList is 10. | 59 // The default maximum number of items to display in JumpList is 10. |
61 // https://msdn.microsoft.com/library/windows/desktop/dd378398.aspx | 60 // https://msdn.microsoft.com/library/windows/desktop/dd378398.aspx |
62 // The "Most visited" and "Recently closed" category titles always take 2 slots. | 61 // The "Most visited" and "Recently closed" category titles always take 2 slots. |
63 // For the remaining 8 slots, we allocate 5 slots to "most-visited" items and 3 | 62 // For the remaining 8 slots, we allocate 5 slots to "most-visited" items and 3 |
64 // slots to "recently-closed" items, respectively. | 63 // slots to "recently-closed" items, respectively. |
65 constexpr size_t kMostVisitedItems = 5; | 64 constexpr size_t kMostVisitedItems = 5; |
66 constexpr size_t kRecentlyClosedItems = 3; | 65 constexpr size_t kRecentlyClosedItems = 3; |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
189 base::FilePath GenerateJumplistIconDirName( | 188 base::FilePath GenerateJumplistIconDirName( |
190 const base::FilePath& profile_dir, | 189 const base::FilePath& profile_dir, |
191 const base::FilePath::StringPieceType& suffix) { | 190 const base::FilePath::StringPieceType& suffix) { |
192 base::FilePath::StringType dir_name(chrome::kJumpListIconDirname); | 191 base::FilePath::StringType dir_name(chrome::kJumpListIconDirname); |
193 suffix.AppendToString(&dir_name); | 192 suffix.AppendToString(&dir_name); |
194 return profile_dir.Append(dir_name); | 193 return profile_dir.Append(dir_name); |
195 } | 194 } |
196 | 195 |
197 } // namespace | 196 } // namespace |
198 | 197 |
199 JumpList::JumpListData::JumpListData() {} | 198 JumpList::JumpListUpdateResults::JumpListUpdateResults() {} |
200 | 199 |
201 JumpList::JumpListData::~JumpListData() {} | 200 JumpList::JumpListUpdateResults::~JumpListUpdateResults() {} |
202 | 201 |
203 JumpList::JumpList(Profile* profile) | 202 JumpList::JumpList(Profile* profile) |
204 : RefcountedKeyedService(content::BrowserThread::GetTaskRunnerForThread( | 203 : RefcountedKeyedService(content::BrowserThread::GetTaskRunnerForThread( |
205 content::BrowserThread::UI)), | 204 content::BrowserThread::UI)), |
206 profile_(profile), | 205 profile_(profile), |
207 jumplist_data_(new base::RefCountedData<JumpListData>), | |
208 task_id_(base::CancelableTaskTracker::kBadTaskId), | 206 task_id_(base::CancelableTaskTracker::kBadTaskId), |
209 update_jumplist_task_runner_(base::CreateCOMSTATaskRunnerWithTraits( | 207 update_jumplist_task_runner_(base::CreateCOMSTATaskRunnerWithTraits( |
210 {base::MayBlock(), base::TaskPriority::USER_VISIBLE, | 208 {base::MayBlock(), base::TaskPriority::USER_VISIBLE, |
211 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})), | 209 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})), |
212 delete_jumplisticons_task_runner_( | 210 delete_jumplisticons_task_runner_( |
213 base::CreateSequencedTaskRunnerWithTraits( | 211 base::CreateSequencedTaskRunnerWithTraits( |
214 {base::MayBlock(), base::TaskPriority::BACKGROUND, | 212 {base::MayBlock(), base::TaskPriority::BACKGROUND, |
215 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})), | 213 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})), |
216 weak_ptr_factory_(this) { | 214 weak_ptr_factory_(this) { |
217 DCHECK(Enabled()); | 215 DCHECK(Enabled()); |
218 // To update JumpList when a tab is added or removed, we add this object to | 216 // To update JumpList when a tab is added or removed, we add this object to |
219 // the observer list of the TabRestoreService class. | 217 // the observer list of the TabRestoreService class. |
220 // When we add this object to the observer list, we save the pointer to this | 218 // When we add this object to the observer list, we save the pointer to this |
221 // TabRestoreService object. This pointer is used when we remove this object | 219 // TabRestoreService object. This pointer is used when we remove this object |
222 // from the observer list. | 220 // from the observer list. |
223 sessions::TabRestoreService* tab_restore_service = | 221 sessions::TabRestoreService* tab_restore_service = |
224 TabRestoreServiceFactory::GetForProfile(profile_); | 222 TabRestoreServiceFactory::GetForProfile(profile_); |
225 if (!tab_restore_service) | 223 if (!tab_restore_service) |
226 return; | 224 return; |
227 | 225 |
228 app_id_ = | 226 app_id_ = |
229 shell_integration::win::GetChromiumModelIdForProfile(profile_->GetPath()); | 227 shell_integration::win::GetChromiumModelIdForProfile(profile_->GetPath()); |
230 | 228 |
231 scoped_refptr<history::TopSites> top_sites = | 229 scoped_refptr<history::TopSites> top_sites = |
grt (UTC plus 2)
2017/06/09 10:42:57
nit: move this down just after the comment below w
chengx
2017/06/10 05:56:17
Done.
| |
232 TopSitesFactory::GetForProfile(profile_); | 230 TopSitesFactory::GetForProfile(profile_); |
233 if (top_sites) { | 231 |
234 // Register as TopSitesObserver so that we can update ourselves when the | 232 // Register as TopSitesObserver so that we can update ourselves when the |
235 // TopSites changes. TopSites updates itself after a delay. This is | 233 // TopSites changes. TopSites updates itself after a delay. This is especially |
236 // especially noticable when your profile is empty. | 234 // noticable when your profile is empty. |
235 if (top_sites) | |
237 top_sites->AddObserver(this); | 236 top_sites->AddObserver(this); |
238 } | 237 |
239 tab_restore_service->AddObserver(this); | 238 tab_restore_service->AddObserver(this); |
grt (UTC plus 2)
2017/06/09 10:42:57
please add a doc comment explaining why the TRS is
chengx
2017/06/10 05:56:17
Done.
| |
240 pref_change_registrar_.reset(new PrefChangeRegistrar); | 239 pref_change_registrar_.reset(new PrefChangeRegistrar); |
grt (UTC plus 2)
2017/06/09 10:42:56
please add a doc comment explaining why kIncognito
chengx
2017/06/10 05:56:17
Done.
| |
241 pref_change_registrar_->Init(profile_->GetPrefs()); | 240 pref_change_registrar_->Init(profile_->GetPrefs()); |
242 pref_change_registrar_->Add( | 241 pref_change_registrar_->Add( |
243 prefs::kIncognitoModeAvailability, | 242 prefs::kIncognitoModeAvailability, |
244 base::Bind(&JumpList::OnIncognitoAvailabilityChanged, this)); | 243 base::Bind(&JumpList::OnIncognitoAvailabilityChanged, this)); |
grt (UTC plus 2)
2017/06/09 10:42:56
base::Unretained(this) since you're guaranteed tha
chengx
2017/06/10 05:56:17
Changed to base::Unretained(this) and comments add
| |
245 } | 244 } |
246 | 245 |
247 JumpList::~JumpList() { | 246 JumpList::~JumpList() { |
248 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 247 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
249 Terminate(); | 248 Terminate(); |
250 } | 249 } |
251 | 250 |
252 // static | 251 // static |
253 bool JumpList::Enabled() { | 252 bool JumpList::Enabled() { |
254 return JumpListUpdater::IsEnabled(); | 253 return JumpListUpdater::IsEnabled(); |
255 } | 254 } |
256 | 255 |
257 void JumpList::CancelPendingUpdate() { | 256 void JumpList::CancelPendingUpdate() { |
grt (UTC plus 2)
2017/06/09 10:42:57
i think this should also cancel a pending MostVisi
chengx
2017/06/10 05:56:18
Thanks for the reminder! I've updated code to inva
| |
258 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 257 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
259 if (task_id_ != base::CancelableTaskTracker::kBadTaskId) { | 258 if (task_id_ != base::CancelableTaskTracker::kBadTaskId) { |
260 cancelable_task_tracker_.TryCancel(task_id_); | 259 cancelable_task_tracker_.TryCancel(task_id_); |
261 task_id_ = base::CancelableTaskTracker::kBadTaskId; | 260 task_id_ = base::CancelableTaskTracker::kBadTaskId; |
262 } | 261 } |
263 } | 262 } |
264 | 263 |
265 void JumpList::Terminate() { | 264 void JumpList::Terminate() { |
266 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 265 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
267 timer_most_visited_.Stop(); | 266 timer_.Stop(); |
268 timer_recently_closed_.Stop(); | |
269 CancelPendingUpdate(); | 267 CancelPendingUpdate(); |
270 if (profile_) { | 268 if (profile_) { |
grt (UTC plus 2)
2017/06/09 10:42:56
update_in_progress_ = false;
just before this line
chengx
2017/06/10 05:56:16
Done.
| |
271 sessions::TabRestoreService* tab_restore_service = | 269 sessions::TabRestoreService* tab_restore_service = |
272 TabRestoreServiceFactory::GetForProfile(profile_); | 270 TabRestoreServiceFactory::GetForProfile(profile_); |
273 if (tab_restore_service) | 271 if (tab_restore_service) |
274 tab_restore_service->RemoveObserver(this); | 272 tab_restore_service->RemoveObserver(this); |
275 scoped_refptr<history::TopSites> top_sites = | 273 scoped_refptr<history::TopSites> top_sites = |
276 TopSitesFactory::GetForProfile(profile_); | 274 TopSitesFactory::GetForProfile(profile_); |
277 if (top_sites) | 275 if (top_sites) |
278 top_sites->RemoveObserver(this); | 276 top_sites->RemoveObserver(this); |
279 pref_change_registrar_.reset(); | 277 pref_change_registrar_.reset(); |
280 } | 278 } |
281 profile_ = NULL; | 279 profile_ = NULL; |
grt (UTC plus 2)
2017/06/09 10:42:56
nit: nullptr throughout
chengx
2017/06/10 05:56:17
Done.
| |
282 } | 280 } |
283 | 281 |
284 void JumpList::ShutdownOnUIThread() { | 282 void JumpList::ShutdownOnUIThread() { |
285 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 283 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
286 Terminate(); | 284 Terminate(); |
287 } | 285 } |
288 | 286 |
289 void JumpList::OnMostVisitedURLsAvailable( | 287 void JumpList::OnMostVisitedURLsAvailable( |
290 const history::MostVisitedURLList& urls) { | 288 const history::MostVisitedURLList& urls) { |
291 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 289 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
292 | 290 |
293 { | 291 // There is no need to update the JumpList if the top most visited sites in |
294 JumpListData* data = &jumplist_data_->data; | 292 // display have not changed. |
295 base::AutoLock auto_lock(data->list_lock_); | 293 if (MostVisitedItemsUnchanged(most_visited_pages_, urls, kMostVisitedItems)) |
294 return; | |
296 | 295 |
297 // There is no need to update the JumpList if the top most visited sites in | 296 most_visited_pages_.clear(); |
298 // display have not changed. | |
299 if (MostVisitedItemsUnchanged(data->most_visited_pages_, urls, | |
300 kMostVisitedItems)) { | |
301 return; | |
302 } | |
303 | 297 |
grt (UTC plus 2)
2017/06/09 10:42:56
const size_t num_items = std::min(urls.size(), kMo
chengx
2017/06/10 05:56:17
I introduced num_items to avoid duplicated value c
grt (UTC plus 2)
2017/06/12 07:15:32
:-)
chengx
2017/06/12 22:05:28
Acknowledged.
| |
304 data->most_visited_pages_.clear(); | 298 for (size_t i = 0; i < urls.size() && i < kMostVisitedItems; i++) { |
grt (UTC plus 2)
2017/06/09 10:42:56
...; i < num_items; ++i) {
(note: always prefer p
chengx
2017/06/10 05:56:17
Done.
| |
299 const history::MostVisitedURL& url = urls[i]; | |
300 scoped_refptr<ShellLinkItem> link = CreateShellLink(); | |
301 std::string url_string = url.url.spec(); | |
302 base::string16 url_string_wide = base::UTF8ToUTF16(url_string); | |
303 link->GetCommandLine()->AppendArgNative(url_string_wide); | |
304 link->GetCommandLine()->AppendSwitchASCII(switches::kWinJumplistAction, | |
305 jumplist::kMostVisitedCategory); | |
306 link->set_title(!url.title.empty() ? url.title : url_string_wide); | |
307 link->set_url(url_string); | |
308 most_visited_pages_.push_back(link); | |
309 icon_urls_.push_back(std::make_pair(url_string, link)); | |
grt (UTC plus 2)
2017/06/09 10:42:57
icon_urls_.emplace_back(std::move(url_string), std
chengx
2017/06/10 05:56:17
Done.
| |
310 } | |
305 | 311 |
306 for (size_t i = 0; i < urls.size() && i < kMostVisitedItems; i++) { | 312 most_visited_pages_have_updates_ = true; |
307 const history::MostVisitedURL& url = urls[i]; | |
308 scoped_refptr<ShellLinkItem> link = CreateShellLink(); | |
309 std::string url_string = url.url.spec(); | |
310 base::string16 url_string_wide = base::UTF8ToUTF16(url_string); | |
311 link->GetCommandLine()->AppendArgNative(url_string_wide); | |
312 link->GetCommandLine()->AppendSwitchASCII( | |
313 switches::kWinJumplistAction, jumplist::kMostVisitedCategory); | |
314 link->set_title(!url.title.empty() ? url.title : url_string_wide); | |
315 link->set_url(url_string); | |
316 data->most_visited_pages_.push_back(link); | |
317 data->icon_urls_.push_back(std::make_pair(url_string, link)); | |
318 } | |
319 data->most_visited_pages_have_updates_ = true; | |
320 } | |
321 | 313 |
322 // Send a query that retrieves the first favicon. | 314 // Send a query that retrieves the first favicon. |
323 StartLoadingFavicon(); | 315 StartLoadingFavicon(); |
324 } | 316 } |
325 | 317 |
326 void JumpList::TabRestoreServiceChanged(sessions::TabRestoreService* service) { | 318 void JumpList::TabRestoreServiceChanged(sessions::TabRestoreService* service) { |
327 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 319 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
328 | 320 |
329 // if we have a pending favicon request, cancel it here (it is out of date). | 321 recently_closed_has_pending_notification_ = true; |
322 | |
323 if (update_in_progress_) | |
grt (UTC plus 2)
2017/06/09 10:42:56
please document this. for example:
// Postpone h
chengx
2017/06/10 05:56:16
Done.
| |
324 return; | |
325 | |
326 // if we have a pending favicon request, cancel it here as it's out of date. | |
330 CancelPendingUpdate(); | 327 CancelPendingUpdate(); |
331 | 328 |
332 // Initialize the one-shot timer to update the the "Recently Closed" category | 329 // Initialize the one-shot timer to update the JumpList in a while. If there |
333 // in a while. If there is already a request queued then cancel it and post | 330 // is already a request queued then cancel it and post the new request. This |
334 // the new request. This ensures that JumpList update of the "Recently Closed" | 331 // ensures that JumpList update won't happen until there has been a brief |
335 // category won't happen until there has been a brief quiet period, thus | 332 // quiet period, thus avoiding update storms. |
336 // avoiding update storms. | 333 if (timer_.IsRunning()) { |
grt (UTC plus 2)
2017/06/09 10:42:57
this block is repeated three times. please pull it
chengx
2017/06/10 05:56:18
I have added a new InitializeTimerForUpdate method
| |
337 if (timer_recently_closed_.IsRunning()) { | 334 timer_.Reset(); |
338 timer_recently_closed_.Reset(); | |
339 } else { | 335 } else { |
340 timer_recently_closed_.Start( | 336 timer_.Start( |
341 FROM_HERE, kDelayForJumplistUpdate, | 337 FROM_HERE, kDelayForJumplistUpdate, |
342 base::Bind(&JumpList::DeferredTabRestoreServiceChanged, | 338 base::Bind(&JumpList::DeferredChanged, base::Unretained(this))); |
grt (UTC plus 2)
2017/06/09 10:42:57
please add a comment such as:
// base::Unretaine
chengx
2017/06/10 05:56:17
Done.
| |
343 base::Unretained(this))); | |
344 } | 339 } |
345 } | 340 } |
346 | 341 |
347 void JumpList::TabRestoreServiceDestroyed( | 342 void JumpList::TabRestoreServiceDestroyed( |
348 sessions::TabRestoreService* service) {} | 343 sessions::TabRestoreService* service) {} |
349 | 344 |
350 bool JumpList::AddTab(const sessions::TabRestoreService::Tab& tab, | 345 bool JumpList::AddTab(const sessions::TabRestoreService::Tab& tab, |
351 size_t max_items, | 346 size_t max_items) { |
352 JumpListData* data) { | |
353 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 347 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
354 data->list_lock_.AssertAcquired(); | |
355 | 348 |
356 // This code adds the URL and the title strings of the given tab to |data|. | 349 // This code adds the URL and the title strings of the given tab to the |
357 if (data->recently_closed_pages_.size() >= max_items) | 350 // JumpList variables. |
351 if (recently_closed_pages_.size() >= max_items) | |
358 return false; | 352 return false; |
359 | 353 |
360 scoped_refptr<ShellLinkItem> link = CreateShellLink(); | 354 scoped_refptr<ShellLinkItem> link = CreateShellLink(); |
361 const sessions::SerializedNavigationEntry& current_navigation = | 355 const sessions::SerializedNavigationEntry& current_navigation = |
362 tab.navigations.at(tab.current_navigation_index); | 356 tab.navigations.at(tab.current_navigation_index); |
363 std::string url = current_navigation.virtual_url().spec(); | 357 std::string url = current_navigation.virtual_url().spec(); |
364 link->GetCommandLine()->AppendArgNative(base::UTF8ToUTF16(url)); | 358 link->GetCommandLine()->AppendArgNative(base::UTF8ToUTF16(url)); |
365 link->GetCommandLine()->AppendSwitchASCII(switches::kWinJumplistAction, | 359 link->GetCommandLine()->AppendSwitchASCII(switches::kWinJumplistAction, |
366 jumplist::kRecentlyClosedCategory); | 360 jumplist::kRecentlyClosedCategory); |
367 link->set_title(current_navigation.title()); | 361 link->set_title(current_navigation.title()); |
368 link->set_url(url); | 362 link->set_url(url); |
369 data->recently_closed_pages_.push_back(link); | 363 recently_closed_pages_.push_back(link); |
370 data->icon_urls_.push_back(std::make_pair(std::move(url), std::move(link))); | 364 icon_urls_.push_back(std::make_pair(std::move(url), std::move(link))); |
grt (UTC plus 2)
2017/06/09 10:42:56
icon_urls_.emplace_back(std::move(url), std::move(
chengx
2017/06/10 05:56:17
Done.
| |
371 | 365 |
372 return true; | 366 return true; |
373 } | 367 } |
374 | 368 |
375 void JumpList::AddWindow(const sessions::TabRestoreService::Window& window, | 369 void JumpList::AddWindow(const sessions::TabRestoreService::Window& window, |
376 size_t max_items, | 370 size_t max_items) { |
377 JumpListData* data) { | |
378 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 371 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
379 data->list_lock_.AssertAcquired(); | |
380 | 372 |
381 // This code enumerates all the tabs in the given window object and add their | 373 // This code enumerates all the tabs in the given window object and add their |
grt (UTC plus 2)
2017/06/09 10:42:57
this comment adds nothing over the doc comment in
chengx
2017/06/10 05:56:17
Done.
| |
382 // URLs and titles to |data|. | 374 // URLs and titles to the JumpList variables. |
383 DCHECK(!window.tabs.empty()); | 375 DCHECK(!window.tabs.empty()); |
384 | 376 |
385 for (const auto& tab : window.tabs) { | 377 for (const auto& tab : window.tabs) { |
386 if (!AddTab(*tab, max_items, data)) | 378 if (!AddTab(*tab, max_items)) |
387 return; | 379 return; |
388 } | 380 } |
389 } | 381 } |
390 | 382 |
391 void JumpList::StartLoadingFavicon() { | 383 void JumpList::StartLoadingFavicon() { |
392 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 384 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
393 | 385 |
394 base::ElapsedTimer timer; | 386 base::ElapsedTimer timer; |
grt (UTC plus 2)
2017/06/09 10:42:57
do the early return before this line:
if (icon_
chengx
2017/06/10 05:56:18
Done.
| |
395 | 387 |
396 GURL url; | 388 GURL url; |
397 bool waiting_for_icons = true; | 389 |
398 { | 390 bool waiting_for_icons = !icon_urls_.empty(); |
399 JumpListData* data = &jumplist_data_->data; | 391 if (waiting_for_icons) { |
400 base::AutoLock auto_lock(data->list_lock_); | 392 // Ask FaviconService if it has a favicon of a URL. |
401 waiting_for_icons = !data->icon_urls_.empty(); | 393 // When FaviconService has one, it will call OnFaviconDataAvailable(). |
402 if (waiting_for_icons) { | 394 url = GURL(icon_urls_.front().first); |
403 // Ask FaviconService if it has a favicon of a URL. | |
404 // When FaviconService has one, it will call OnFaviconDataAvailable(). | |
405 url = GURL(data->icon_urls_.front().first); | |
406 } | |
407 } | 395 } |
408 | 396 |
409 if (!waiting_for_icons) { | 397 if (!waiting_for_icons) { |
410 // No more favicons are needed by the application JumpList. Schedule a | 398 // No more favicons are needed by the application JumpList. Schedule a |
411 // RunUpdateJumpList call. | 399 // RunUpdateJumpList call. |
412 PostRunUpdate(); | 400 PostRunUpdate(); |
413 return; | 401 return; |
414 } | 402 } |
415 | 403 |
416 favicon::FaviconService* favicon_service = | 404 favicon::FaviconService* favicon_service = |
417 FaviconServiceFactory::GetForProfile(profile_, | 405 FaviconServiceFactory::GetForProfile(profile_, |
418 ServiceAccessType::EXPLICIT_ACCESS); | 406 ServiceAccessType::EXPLICIT_ACCESS); |
419 task_id_ = favicon_service->GetFaviconImageForPageURL( | 407 task_id_ = favicon_service->GetFaviconImageForPageURL( |
420 url, | 408 url, |
421 base::Bind(&JumpList::OnFaviconDataAvailable, base::Unretained(this)), | 409 base::Bind(&JumpList::OnFaviconDataAvailable, base::Unretained(this)), |
grt (UTC plus 2)
2017/06/09 10:42:56
please add a comment such as:
// base::Unretaine
chengx
2017/06/10 05:56:18
Done.
| |
422 &cancelable_task_tracker_); | 410 &cancelable_task_tracker_); |
423 | 411 |
424 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/717236 | 412 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/717236 |
425 UMA_HISTOGRAM_TIMES("WinJumplist.StartLoadingFaviconDuration", | 413 UMA_HISTOGRAM_TIMES("WinJumplist.StartLoadingFaviconDuration", |
426 timer.Elapsed()); | 414 timer.Elapsed()); |
427 } | 415 } |
428 | 416 |
429 void JumpList::OnFaviconDataAvailable( | 417 void JumpList::OnFaviconDataAvailable( |
430 const favicon_base::FaviconImageResult& image_result) { | 418 const favicon_base::FaviconImageResult& image_result) { |
431 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 419 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
432 | 420 |
433 base::ElapsedTimer timer; | 421 base::ElapsedTimer timer; |
434 | 422 |
435 // If there is currently a favicon request in progress, it is now outdated, | 423 // If there is currently a favicon request in progress, it is now outdated, |
436 // as we have received another, so nullify the handle from the old request. | 424 // as we have received another, so nullify the handle from the old request. |
437 task_id_ = base::CancelableTaskTracker::kBadTaskId; | 425 task_id_ = base::CancelableTaskTracker::kBadTaskId; |
438 // Lock the list to set icon data and pop the url. | |
439 { | |
440 JumpListData* data = &jumplist_data_->data; | |
441 base::AutoLock auto_lock(data->list_lock_); | |
442 // Attach the received data to the ShellLinkItem object. | |
443 // This data will be decoded by the RunUpdateJumpList | |
444 // method. | |
445 if (!image_result.image.IsEmpty() && !data->icon_urls_.empty() && | |
446 data->icon_urls_.front().second.get()) { | |
447 gfx::ImageSkia image_skia = image_result.image.AsImageSkia(); | |
448 image_skia.EnsureRepsForSupportedScales(); | |
449 std::unique_ptr<gfx::ImageSkia> deep_copy(image_skia.DeepCopy()); | |
450 data->icon_urls_.front().second->set_icon_image(*deep_copy); | |
451 } | |
452 | 426 |
453 if (!data->icon_urls_.empty()) | 427 // Attach the received data to the ShellLinkItem object. This data will be |
454 data->icon_urls_.pop_front(); | 428 // decoded by the RunUpdateJumpList method. |
429 if (!image_result.image.IsEmpty() && !icon_urls_.empty() && | |
430 icon_urls_.front().second.get()) { | |
431 gfx::ImageSkia image_skia = image_result.image.AsImageSkia(); | |
432 image_skia.EnsureRepsForSupportedScales(); | |
433 std::unique_ptr<gfx::ImageSkia> deep_copy(image_skia.DeepCopy()); | |
434 icon_urls_.front().second->set_icon_image(*deep_copy); | |
455 } | 435 } |
456 | 436 |
437 if (!icon_urls_.empty()) | |
grt (UTC plus 2)
2017/06/09 10:42:55
this condition is checked twice. how about:
if (
chengx
2017/06/10 05:56:17
Agreed this is the right thing to do. Done.
| |
438 icon_urls_.pop_front(); | |
439 | |
457 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/717236 | 440 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/717236 |
458 UMA_HISTOGRAM_TIMES("WinJumplist.OnFaviconDataAvailableDuration", | 441 UMA_HISTOGRAM_TIMES("WinJumplist.OnFaviconDataAvailableDuration", |
459 timer.Elapsed()); | 442 timer.Elapsed()); |
460 | 443 |
461 // Check whether we need to load more favicons. | 444 // Check whether we need to load more favicons. |
462 StartLoadingFavicon(); | 445 StartLoadingFavicon(); |
463 } | 446 } |
464 | 447 |
465 void JumpList::OnIncognitoAvailabilityChanged() { | 448 void JumpList::OnIncognitoAvailabilityChanged() { |
466 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 449 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
467 | 450 |
468 bool waiting_for_icons = true; | 451 bool waiting_for_icons = !icon_urls_.empty(); |
469 { | |
470 JumpListData* data = &jumplist_data_->data; | |
471 base::AutoLock auto_lock(data->list_lock_); | |
472 waiting_for_icons = !data->icon_urls_.empty(); | |
473 } | |
474 | 452 |
475 // Since neither the "Most Visited" category nor the "Recently Closed" | 453 // Since neither the "Most Visited" category nor the "Recently Closed" |
476 // category changes, mark the flags so that icon files for those categories | 454 // category changes, mark the flags so that icon files for those categories |
477 // won't be updated later on. | 455 // won't be updated later on. |
478 if (!waiting_for_icons) | 456 if (!waiting_for_icons) |
grt (UTC plus 2)
2017/06/09 10:42:56
if (icon_urls_.empty()))
chengx
2017/06/10 05:56:16
Done.
| |
479 PostRunUpdate(); | 457 PostRunUpdate(); |
480 } | 458 } |
481 | 459 |
482 void JumpList::PostRunUpdate() { | 460 void JumpList::PostRunUpdate() { |
483 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 461 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
484 | 462 |
485 TRACE_EVENT0("browser", "JumpList::PostRunUpdate"); | 463 TRACE_EVENT0("browser", "JumpList::PostRunUpdate"); |
486 if (!profile_) | 464 if (!profile_) |
grt (UTC plus 2)
2017/06/09 10:42:55
can this ever be true? as long as Terminate() real
chengx
2017/06/10 05:56:17
I've removed it.
| |
487 return; | 465 return; |
488 | 466 |
467 update_in_progress_ = true; | |
468 | |
489 base::FilePath profile_dir = profile_->GetPath(); | 469 base::FilePath profile_dir = profile_->GetPath(); |
490 | 470 |
491 // Check if incognito windows (or normal windows) are disabled by policy. | 471 // Check if incognito windows (or normal windows) are disabled by policy. |
492 IncognitoModePrefs::Availability incognito_availability = | 472 IncognitoModePrefs::Availability incognito_availability = |
493 IncognitoModePrefs::GetAvailability(profile_->GetPrefs()); | 473 IncognitoModePrefs::GetAvailability(profile_->GetPrefs()); |
494 | 474 |
495 // Post a task to update the JumpList, which consists of 1) delete old icons, | 475 // Make local copies of JumpList member variables and use them for an update. |
496 // 2) create new icons, 3) notify the OS. | 476 ShellLinkItemList local_most_visited_pages = most_visited_pages_; |
497 update_jumplist_task_runner_->PostTask( | 477 ShellLinkItemList local_recently_closed_pages = recently_closed_pages_; |
478 | |
479 bool most_visited_pages_have_updates = most_visited_pages_have_updates_; | |
480 bool recently_closed_pages_have_updates = recently_closed_pages_have_updates_; | |
481 | |
482 JumpListUpdateResults* update_results = new JumpListUpdateResults(); | |
grt (UTC plus 2)
2017/06/09 10:42:56
auto update_results = base::MakeUnique<JumpListUpd
chengx
2017/06/10 05:56:17
Done.
| |
483 update_results->most_visited_icons_in_update_ = most_visited_icons_; | |
484 update_results->recently_closed_icons_in_update = recently_closed_icons_; | |
485 | |
486 // Post a task to update the JumpList, which consists of 1) create new icons, | |
487 // 2) delete old icons, 3) notify the OS. | |
488 update_jumplist_task_runner_->PostTaskAndReply( | |
grt (UTC plus 2)
2017/06/09 10:42:56
PTAR returns a bool indicating whether or not the
chengx
2017/06/10 05:56:16
Thanks for the reminder! This is cool!
| |
498 FROM_HERE, | 489 FROM_HERE, |
499 base::Bind(&JumpList::RunUpdateJumpList, this, incognito_availability, | 490 base::Bind(&JumpList::RunUpdateJumpList, app_id_, profile_dir, |
500 app_id_, profile_dir, base::RetainedRef(jumplist_data_))); | 491 local_most_visited_pages, local_recently_closed_pages, |
492 most_visited_pages_have_updates, | |
493 recently_closed_pages_have_updates, incognito_availability, | |
494 update_results), | |
495 base::Bind(&JumpList::OnRunUpdateCompletion, base::Unretained(this), | |
grt (UTC plus 2)
2017/06/09 10:42:56
base::Unretained -> weak_ptr_factory_.GetWeakPtr()
chengx
2017/06/10 05:56:17
Done.
| |
496 base::Passed(base::WrapUnique(update_results)))); | |
501 | 497 |
502 // Post a task to delete JumpListIcons folder as it's no longer needed. | 498 // Post a task to delete folders JumpListIcons and JumpListIconsOld as they |
grt (UTC plus 2)
2017/06/09 10:42:56
wdyt of moving this stuff down into OnRunUpdateCom
grt (UTC plus 2)
2017/06/09 10:42:57
nit: "...to delete the Foo and Bar folders as they
chengx
2017/06/10 05:56:17
Comments updated.
chengx
2017/06/10 05:56:17
SGTM. Done.
| |
503 // Now we have JumpListIconsMostVisited folder and JumpListIconsRecentClosed | 499 // are no longer needed. Now we have folders JumpListIcons{MostVisited, |
504 // folder instead. | 500 // RecentClosed} instead. |
501 | |
505 base::FilePath icon_dir = | 502 base::FilePath icon_dir = |
506 GenerateJumplistIconDirName(profile_dir, FILE_PATH_LITERAL("")); | 503 GenerateJumplistIconDirName(profile_dir, FILE_PATH_LITERAL("")); |
507 | |
508 delete_jumplisticons_task_runner_->PostTask( | 504 delete_jumplisticons_task_runner_->PostTask( |
509 FROM_HERE, | 505 FROM_HERE, |
510 base::Bind(&DeleteDirectory, std::move(icon_dir), kFileDeleteLimit)); | 506 base::Bind(&DeleteDirectory, std::move(icon_dir), kFileDeleteLimit)); |
511 | 507 |
512 // Post a task to delete JumpListIconsOld folder as it's no longer needed. | |
513 base::FilePath icon_dir_old = | 508 base::FilePath icon_dir_old = |
514 GenerateJumplistIconDirName(profile_dir, FILE_PATH_LITERAL("Old")); | 509 GenerateJumplistIconDirName(profile_dir, FILE_PATH_LITERAL("Old")); |
515 | |
516 delete_jumplisticons_task_runner_->PostTask( | 510 delete_jumplisticons_task_runner_->PostTask( |
517 FROM_HERE, | 511 FROM_HERE, |
518 base::Bind(&DeleteDirectory, std::move(icon_dir_old), kFileDeleteLimit)); | 512 base::Bind(&DeleteDirectory, std::move(icon_dir_old), kFileDeleteLimit)); |
519 } | 513 } |
520 | 514 |
521 void JumpList::TopSitesLoaded(history::TopSites* top_sites) { | 515 void JumpList::TopSitesLoaded(history::TopSites* top_sites) { |
522 } | 516 } |
523 | 517 |
524 void JumpList::TopSitesChanged(history::TopSites* top_sites, | 518 void JumpList::TopSitesChanged(history::TopSites* top_sites, |
525 ChangeReason change_reason) { | 519 ChangeReason change_reason) { |
526 // If we have a pending favicon request, cancel it here (it is out of date). | 520 most_visited_has_pending_notification_ = true; |
grt (UTC plus 2)
2017/06/09 10:42:56
"Most Visited" is the name of the jumplist section
grt (UTC plus 2)
2017/06/09 10:42:56
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_)
chengx
2017/06/10 05:56:17
Thanks for the suggestion. I prefer top_sites_has_
chengx
2017/06/10 05:56:18
DCHECK added.
| |
521 | |
522 if (update_in_progress_) | |
523 return; | |
524 | |
525 // If we have a pending favicon request, cancel it here as it's out of date. | |
527 CancelPendingUpdate(); | 526 CancelPendingUpdate(); |
528 | 527 |
529 // Initialize the one-shot timer to update the the "Most visited" category in | 528 // Initialize the one-shot timer to update the JumpList in a while. If there |
530 // a while. If there is already a request queued then cancel it and post the | 529 // is already a request queued then cancel it and post the new request. This |
531 // new request. This ensures that JumpList update of the "Most visited" | 530 // ensures that JumpList update won't happen until there has been a brief |
532 // category won't happen until there has been a brief quiet period, thus | 531 // quiet period, thus avoiding update storms. |
533 // avoiding update storms. | 532 if (timer_.IsRunning()) { |
534 if (timer_most_visited_.IsRunning()) { | 533 timer_.Reset(); |
535 timer_most_visited_.Reset(); | |
536 } else { | 534 } else { |
537 timer_most_visited_.Start( | 535 timer_.Start( |
538 FROM_HERE, kDelayForJumplistUpdate, | 536 FROM_HERE, kDelayForJumplistUpdate, |
539 base::Bind(&JumpList::DeferredTopSitesChanged, base::Unretained(this))); | 537 base::Bind(&JumpList::DeferredChanged, base::Unretained(this))); |
538 } | |
539 } | |
540 | |
541 void JumpList::DeferredChanged() { | |
542 if (updates_to_skip_ > 0) { | |
grt (UTC plus 2)
2017/06/09 10:42:57
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_)
chengx
2017/06/10 05:56:16
Done.
| |
543 --updates_to_skip_; | |
544 return; | |
545 } | |
546 | |
547 // Retrieve the recently closed URLs synchronously. | |
548 if (recently_closed_has_pending_notification_) { | |
549 recently_closed_has_pending_notification_ = false; | |
550 DeferredTabRestoreServiceChanged(); | |
551 } | |
552 | |
553 // If TopSites has updates, retrieve the URLs asynchronously, and on its | |
554 // completion, trigger favicon loading. | |
555 // Otherwise, call StartLoadingFavicon directly to start favicon loading. | |
556 if (most_visited_has_pending_notification_) { | |
557 most_visited_has_pending_notification_ = false; | |
558 DeferredTopSitesChanged(); | |
559 } else { | |
560 StartLoadingFavicon(); | |
540 } | 561 } |
541 } | 562 } |
542 | 563 |
543 void JumpList::DeferredTopSitesChanged() { | 564 void JumpList::DeferredTopSitesChanged() { |
544 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 565 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
545 | 566 |
546 if (updates_to_skip_ > 0) { | |
547 --updates_to_skip_; | |
548 return; | |
549 } | |
550 | |
551 // Opening the first tab in one session triggers a TopSite history sync. | 567 // Opening the first tab in one session triggers a TopSite history sync. |
552 // Delay this sync till the first tab is closed to allow the "recently closed" | 568 // Delay this sync till the first tab is closed to allow the "recently closed" |
553 // category from last session to stay longer. | 569 // category from last session to stay longer. |
554 if (!has_tab_closed_) | 570 if (!has_tab_closed_) |
555 return; | 571 return; |
556 | 572 |
557 scoped_refptr<history::TopSites> top_sites = | 573 scoped_refptr<history::TopSites> top_sites = |
558 TopSitesFactory::GetForProfile(profile_); | 574 TopSitesFactory::GetForProfile(profile_); |
559 if (top_sites) { | 575 if (top_sites) { |
560 top_sites->GetMostVisitedURLs( | 576 top_sites->GetMostVisitedURLs( |
grt (UTC plus 2)
2017/06/09 10:42:57
i think you need to do something to deal with an o
chengx
2017/06/10 05:56:18
Thanks for the detailed suggestions! I'll go with
| |
561 base::Bind(&JumpList::OnMostVisitedURLsAvailable, | 577 base::Bind(&JumpList::OnMostVisitedURLsAvailable, |
562 weak_ptr_factory_.GetWeakPtr()), | 578 weak_ptr_factory_.GetWeakPtr()), |
563 false); | 579 false); |
564 } | 580 } |
565 } | 581 } |
566 | 582 |
567 void JumpList::DeferredTabRestoreServiceChanged() { | 583 void JumpList::DeferredTabRestoreServiceChanged() { |
568 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | 584 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
569 | 585 |
570 if (updates_to_skip_ > 0) { | |
571 --updates_to_skip_; | |
572 return; | |
573 } | |
574 | |
575 // Force a TopSite history sync when closing a first tab in one session. | |
576 if (!has_tab_closed_) { | |
577 has_tab_closed_ = true; | |
578 scoped_refptr<history::TopSites> top_sites = | |
579 TopSitesFactory::GetForProfile(profile_); | |
580 if (top_sites) | |
581 top_sites->SyncWithHistory(); | |
582 } | |
583 | |
584 // Create a list of ShellLinkItems from the "Recently Closed" pages. | 586 // Create a list of ShellLinkItems from the "Recently Closed" pages. |
585 // As noted above, we create a ShellLinkItem objects with the following | 587 // As noted above, we create a ShellLinkItem objects with the following |
586 // parameters. | 588 // parameters. |
587 // * arguments | 589 // * arguments |
588 // The last URL of the tab object. | 590 // The last URL of the tab object. |
589 // * title | 591 // * title |
590 // The title of the last URL. | 592 // The title of the last URL. |
591 // * icon | 593 // * icon |
592 // An empty string. This value is to be updated in OnFaviconDataAvailable(). | 594 // An empty string. This value is to be updated in OnFaviconDataAvailable(). |
593 | 595 |
594 sessions::TabRestoreService* tab_restore_service = | 596 sessions::TabRestoreService* tab_restore_service = |
595 TabRestoreServiceFactory::GetForProfile(profile_); | 597 TabRestoreServiceFactory::GetForProfile(profile_); |
596 | 598 |
597 { | 599 recently_closed_pages_.clear(); |
598 JumpListData* data = &jumplist_data_->data; | |
599 base::AutoLock auto_lock(data->list_lock_); | |
600 data->recently_closed_pages_.clear(); | |
601 | 600 |
602 for (const auto& entry : tab_restore_service->entries()) { | 601 for (const auto& entry : tab_restore_service->entries()) { |
603 if (data->recently_closed_pages_.size() >= kRecentlyClosedItems) | 602 if (recently_closed_pages_.size() >= kRecentlyClosedItems) |
603 break; | |
604 switch (entry->type) { | |
605 case sessions::TabRestoreService::TAB: | |
606 AddTab(static_cast<const sessions::TabRestoreService::Tab&>(*entry), | |
607 kRecentlyClosedItems); | |
604 break; | 608 break; |
605 switch (entry->type) { | 609 case sessions::TabRestoreService::WINDOW: |
606 case sessions::TabRestoreService::TAB: | 610 AddWindow( |
607 AddTab(static_cast<const sessions::TabRestoreService::Tab&>(*entry), | 611 static_cast<const sessions::TabRestoreService::Window&>(*entry), |
608 kRecentlyClosedItems, data); | 612 kRecentlyClosedItems); |
609 break; | 613 break; |
610 case sessions::TabRestoreService::WINDOW: | |
611 AddWindow( | |
612 static_cast<const sessions::TabRestoreService::Window&>(*entry), | |
613 kRecentlyClosedItems, data); | |
614 break; | |
615 } | |
616 } | 614 } |
617 | |
618 data->recently_closed_pages_have_updates_ = true; | |
619 } | 615 } |
620 | 616 |
621 // Send a query that retrieves the first favicon. | 617 recently_closed_pages_have_updates_ = true; |
622 StartLoadingFavicon(); | 618 |
619 // Force a TopSite history sync when closing a first tab in one session. | |
620 if (!has_tab_closed_) { | |
621 has_tab_closed_ = true; | |
622 scoped_refptr<history::TopSites> top_sites = | |
623 TopSitesFactory::GetForProfile(profile_); | |
624 if (top_sites) | |
625 top_sites->SyncWithHistory(); | |
626 } | |
623 } | 627 } |
624 | 628 |
629 // static | |
625 void JumpList::DeleteIconFiles(const base::FilePath& icon_dir, | 630 void JumpList::DeleteIconFiles(const base::FilePath& icon_dir, |
626 JumpListCategory category) { | 631 URLIconCache* icon_cache) { |
627 base::flat_map<std::string, base::FilePath>* source_map = nullptr; | |
628 switch (category) { | |
629 case JumpListCategory::kMostVisited: | |
630 source_map = &most_visited_icons_; | |
631 break; | |
632 case JumpListCategory::kRecentlyClosed: | |
633 source_map = &recently_closed_icons_; | |
634 break; | |
635 } | |
636 | |
637 // Put all cached icon file paths into a set. | 632 // Put all cached icon file paths into a set. |
638 base::flat_set<base::FilePath> cached_files; | 633 base::flat_set<base::FilePath> cached_files; |
639 cached_files.reserve(source_map->size()); | 634 cached_files.reserve(icon_cache->size()); |
640 | 635 |
641 for (const auto& url_path_pair : *source_map) | 636 for (const auto& url_path_pair : *icon_cache) |
642 cached_files.insert(url_path_pair.second); | 637 cached_files.insert(url_path_pair.second); |
643 | 638 |
644 DeleteNonCachedFiles(icon_dir, cached_files); | 639 DeleteNonCachedFiles(icon_dir, cached_files); |
645 } | 640 } |
646 | 641 |
642 // static | |
647 int JumpList::CreateIconFiles(const base::FilePath& icon_dir, | 643 int JumpList::CreateIconFiles(const base::FilePath& icon_dir, |
648 const ShellLinkItemList& item_list, | 644 const ShellLinkItemList& item_list, |
649 size_t max_items, | 645 size_t max_items, |
650 JumpListCategory category) { | 646 URLIconCache* icon_cache) { |
651 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | 647 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
652 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration"); | 648 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration"); |
653 | 649 |
654 int icons_created = 0; | 650 int icons_created = 0; |
655 | 651 |
656 // Reuse icons for urls that were already present in the jumplist for this | 652 // Reuse icons for urls that already present in the current JumpList. |
657 // category. | 653 URLIconCache updated_map; |
658 | |
659 base::flat_map<std::string, base::FilePath>* source_map = nullptr; | |
660 switch (category) { | |
661 case JumpListCategory::kMostVisited: | |
662 source_map = &most_visited_icons_; | |
663 break; | |
664 case JumpListCategory::kRecentlyClosed: | |
665 source_map = &recently_closed_icons_; | |
666 break; | |
667 } | |
668 | |
669 base::flat_map<std::string, base::FilePath> updated_map; | |
670 | |
671 for (ShellLinkItemList::const_iterator iter = item_list.begin(); | 654 for (ShellLinkItemList::const_iterator iter = item_list.begin(); |
672 iter != item_list.end() && max_items > 0; ++iter, --max_items) { | 655 iter != item_list.end() && max_items > 0; ++iter, --max_items) { |
673 ShellLinkItem* item = iter->get(); | 656 ShellLinkItem* item = iter->get(); |
674 auto cache_iter = source_map->find(item->url()); | 657 auto cache_iter = icon_cache->find(item->url()); |
675 if (cache_iter != source_map->end()) { | 658 if (cache_iter != icon_cache->end()) { |
676 item->set_icon(cache_iter->second.value(), 0); | 659 item->set_icon(cache_iter->second.value(), 0); |
677 updated_map[item->url()] = cache_iter->second; | 660 updated_map[item->url()] = cache_iter->second; |
678 } else { | 661 } else { |
679 base::FilePath icon_path; | 662 base::FilePath icon_path; |
680 if (CreateIconFile(item->icon_image(), icon_dir, &icon_path)) { | 663 if (CreateIconFile(item->icon_image(), icon_dir, &icon_path)) { |
681 ++icons_created; | 664 ++icons_created; |
682 item->set_icon(icon_path.value(), 0); | 665 item->set_icon(icon_path.value(), 0); |
683 updated_map[item->url()] = icon_path; | 666 updated_map[item->url()] = icon_path; |
684 } | 667 } |
685 } | 668 } |
686 } | 669 } |
687 source_map->swap(updated_map); | 670 icon_cache->swap(updated_map); |
688 | 671 |
689 return icons_created; | 672 return icons_created; |
690 } | 673 } |
691 | 674 |
675 // static | |
692 int JumpList::UpdateIconFiles(const base::FilePath& icon_dir, | 676 int JumpList::UpdateIconFiles(const base::FilePath& icon_dir, |
693 const ShellLinkItemList& page_list, | 677 const ShellLinkItemList& page_list, |
694 size_t slot_limit, | 678 size_t slot_limit, |
695 JumpListCategory category) { | 679 URLIconCache* icon_cache) { |
696 int icons_created = 0; | 680 int icons_created = 0; |
697 | 681 |
698 // Maximum number of icon files that each JumpList icon folder may hold, which | |
699 // is set to 2 times the normal amount. | |
700 size_t icon_limit = | |
701 2 * ((category == JumpListCategory::kMostVisited) ? kMostVisitedItems | |
702 : kRecentlyClosedItems); | |
703 | |
704 // Clear the JumpList icon folder at |icon_dir| and the cache when | 682 // Clear the JumpList icon folder at |icon_dir| and the cache when |
705 // 1) "Most visited" category updates for the 1st time after Chrome is | 683 // 1) |icon_cache| is empty. This happens when "Most visited" or "Recently |
706 // launched. This actually happens right after Chrome is launched. | 684 // closed" category updates for the 1st time after Chrome is launched. |
707 // 2) "Recently closed" category updates for the 1st time after Chrome is | 685 // 2) The number of icons in |icon_dir| has exceeded the limit. |
708 // launched. | 686 if (icon_cache->empty() || FilesExceedLimitInDir(icon_dir, slot_limit * 2)) { |
709 // 3) The number of icons in |icon_dir| has exceeded the limit. | |
710 if ((category == JumpListCategory::kMostVisited && | |
711 most_visited_icons_.empty()) || | |
712 (category == JumpListCategory::kRecentlyClosed && | |
713 recently_closed_icons_.empty()) || | |
714 FilesExceedLimitInDir(icon_dir, icon_limit)) { | |
715 DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit); | 687 DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit); |
716 most_visited_icons_.clear(); | 688 icon_cache->clear(); |
717 recently_closed_icons_.clear(); | |
718 // Create new icons only when the directory exists and is empty. | 689 // Create new icons only when the directory exists and is empty. |
719 if (base::CreateDirectory(icon_dir) && base::IsDirectoryEmpty(icon_dir)) | 690 if (base::CreateDirectory(icon_dir) && base::IsDirectoryEmpty(icon_dir)) |
720 icons_created += | 691 icons_created += |
721 CreateIconFiles(icon_dir, page_list, slot_limit, category); | 692 CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache); |
722 } else if (base::CreateDirectory(icon_dir)) { | 693 } else if (base::CreateDirectory(icon_dir)) { |
723 icons_created += CreateIconFiles(icon_dir, page_list, slot_limit, category); | 694 icons_created += |
724 DeleteIconFiles(icon_dir, category); | 695 CreateIconFiles(icon_dir, page_list, slot_limit, icon_cache); |
696 DeleteIconFiles(icon_dir, icon_cache); | |
725 } | 697 } |
726 | 698 |
727 return icons_created; | 699 return icons_created; |
728 } | 700 } |
729 | 701 |
730 bool JumpList::UpdateJumpList( | 702 // static |
703 void JumpList::RunUpdateJumpList( | |
731 const base::string16& app_id, | 704 const base::string16& app_id, |
732 const base::FilePath& profile_dir, | 705 const base::FilePath& profile_dir, |
733 const ShellLinkItemList& most_visited_pages, | 706 const ShellLinkItemList& most_visited_pages, |
734 const ShellLinkItemList& recently_closed_pages, | 707 const ShellLinkItemList& recently_closed_pages, |
735 bool most_visited_pages_have_updates, | 708 bool most_visited_pages_have_updates, |
736 bool recently_closed_pages_have_updates, | 709 bool recently_closed_pages_have_updates, |
737 IncognitoModePrefs::Availability incognito_availability) { | 710 IncognitoModePrefs::Availability incognito_availability, |
711 JumpListUpdateResults* update_results) { | |
738 if (!JumpListUpdater::IsEnabled()) | 712 if (!JumpListUpdater::IsEnabled()) |
739 return true; | 713 return; |
714 | |
715 DCHECK(update_results); | |
740 | 716 |
741 JumpListUpdater jumplist_updater(app_id); | 717 JumpListUpdater jumplist_updater(app_id); |
742 | 718 |
743 base::ElapsedTimer begin_update_timer; | 719 base::ElapsedTimer begin_update_timer; |
744 | 720 |
745 if (!jumplist_updater.BeginUpdate()) | 721 if (!jumplist_updater.BeginUpdate()) { |
746 return false; | 722 update_results->update_success_ = false; |
723 return; | |
724 } | |
747 | 725 |
748 // Discard this JumpList update if JumpListUpdater::BeginUpdate takes longer | 726 // Discard this JumpList update if JumpListUpdater::BeginUpdate takes longer |
749 // than the maximum allowed time, as it's very likely the following update | 727 // than the maximum allowed time, as it's very likely the following update |
750 // steps will also take a long time. As we've not updated the icons on the | 728 // steps will also take a long time. As we've not updated the icons on the |
751 // disk, discarding this update wont't affect the current JumpList used by OS. | 729 // disk, discarding this update wont't affect the current JumpList used by OS. |
752 if (begin_update_timer.Elapsed() >= kTimeOutForJumplistBeginUpdate) { | 730 if (begin_update_timer.Elapsed() >= kTimeOutForJumplistBeginUpdate) { |
753 updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad; | 731 update_results->update_success_ = false; |
754 return false; | 732 update_results->update_timeout_ = true; |
733 return; | |
755 } | 734 } |
756 | 735 |
757 // Record the desired number of icons created in this JumpList update. | 736 // Record the desired number of icons created in this JumpList update. |
758 int icons_created = 0; | 737 int icons_created = 0; |
759 | 738 |
760 // Update the icons for "Most Visisted" category of the JumpList if needed. | 739 // Update the icons for "Most Visisted" category of the JumpList if needed. |
761 if (most_visited_pages_have_updates) { | 740 if (most_visited_pages_have_updates) { |
762 base::FilePath icon_dir_most_visited = GenerateJumplistIconDirName( | 741 base::FilePath icon_dir_most_visited = GenerateJumplistIconDirName( |
763 profile_dir, FILE_PATH_LITERAL("MostVisited")); | 742 profile_dir, FILE_PATH_LITERAL("MostVisited")); |
764 | 743 |
765 icons_created += | 744 icons_created += UpdateIconFiles( |
766 UpdateIconFiles(icon_dir_most_visited, most_visited_pages, | 745 icon_dir_most_visited, most_visited_pages, kMostVisitedItems, |
767 kMostVisitedItems, JumpListCategory::kMostVisited); | 746 &update_results->most_visited_icons_in_update_); |
768 } | 747 } |
769 | 748 |
770 // Update the icons for "Recently Closed" category of the JumpList if needed. | 749 // Update the icons for "Recently Closed" category of the JumpList if needed. |
771 if (recently_closed_pages_have_updates) { | 750 if (recently_closed_pages_have_updates) { |
772 base::FilePath icon_dir_recent_closed = GenerateJumplistIconDirName( | 751 base::FilePath icon_dir_recent_closed = GenerateJumplistIconDirName( |
773 profile_dir, FILE_PATH_LITERAL("RecentClosed")); | 752 profile_dir, FILE_PATH_LITERAL("RecentClosed")); |
774 | 753 |
775 icons_created += UpdateIconFiles( | 754 icons_created += UpdateIconFiles( |
776 icon_dir_recent_closed, recently_closed_pages, kRecentlyClosedItems, | 755 icon_dir_recent_closed, recently_closed_pages, kRecentlyClosedItems, |
777 JumpListCategory::kRecentlyClosed); | 756 &update_results->recently_closed_icons_in_update); |
778 } | 757 } |
779 | 758 |
780 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | 759 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
781 UMA_HISTOGRAM_COUNTS_100("WinJumplist.CreateIconFilesCount", icons_created); | 760 UMA_HISTOGRAM_COUNTS_100("WinJumplist.CreateIconFilesCount", icons_created); |
782 | 761 |
783 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | 762 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
784 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.UpdateJumpListDuration"); | 763 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.UpdateJumpListDuration"); |
785 | 764 |
786 base::ElapsedTimer add_custom_category_timer; | 765 base::ElapsedTimer add_custom_category_timer; |
787 | 766 |
788 // Update the "Most Visited" category of the JumpList if it exists. | 767 // Update the "Most Visited" category of the JumpList if it exists. |
789 // This update request is applied into the JumpList when we commit this | 768 // This update request is applied into the JumpList when we commit this |
790 // transaction. | 769 // transaction. |
791 if (!jumplist_updater.AddCustomCategory( | 770 if (!jumplist_updater.AddCustomCategory( |
792 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED), | 771 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED), |
793 most_visited_pages, kMostVisitedItems)) { | 772 most_visited_pages, kMostVisitedItems)) { |
794 return false; | 773 update_results->update_success_ = false; |
774 return; | |
795 } | 775 } |
796 | 776 |
797 // Update the "Recently Closed" category of the JumpList. | 777 // Update the "Recently Closed" category of the JumpList. |
798 if (!jumplist_updater.AddCustomCategory( | 778 if (!jumplist_updater.AddCustomCategory( |
799 l10n_util::GetStringUTF16(IDS_RECENTLY_CLOSED), recently_closed_pages, | 779 l10n_util::GetStringUTF16(IDS_RECENTLY_CLOSED), recently_closed_pages, |
800 kRecentlyClosedItems)) { | 780 kRecentlyClosedItems)) { |
801 return false; | 781 update_results->update_success_ = false; |
782 return; | |
802 } | 783 } |
803 | 784 |
804 // If JumpListUpdater::AddCustomCategory or JumpListUpdater::CommitUpdate | 785 // If JumpListUpdater::AddCustomCategory or JumpListUpdater::CommitUpdate |
805 // takes longer than the maximum allowed time, skip the next | 786 // takes longer than the maximum allowed time, skip the next |
806 // |kUpdatesToSkipUnderHeavyLoad| updates. This update should be finished | 787 // |kUpdatesToSkipUnderHeavyLoad| updates. This update should be finished |
807 // because we've already updated the icons on the disk. If discarding this | 788 // because we've already updated the icons on the disk. If discarding this |
808 // update from here, some items in the current JumpList may not have icons | 789 // update from here, some items in the current JumpList may not have icons |
809 // as they've been delete from the disk. In this case, the background color of | 790 // as they've been delete from the disk. In this case, the background color of |
810 // the JumpList panel is used instead, which doesn't look nice. | 791 // the JumpList panel is used instead, which doesn't look nice. |
811 | 792 |
812 if (add_custom_category_timer.Elapsed() >= kTimeOutForAddCustomCategory) | 793 if (add_custom_category_timer.Elapsed() >= kTimeOutForAddCustomCategory) |
813 updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad; | 794 update_results->update_timeout_ = true; |
814 | 795 |
815 // Update the "Tasks" category of the JumpList. | 796 // Update the "Tasks" category of the JumpList. |
816 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) | 797 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) { |
817 return false; | 798 update_results->update_success_ = false; |
799 return; | |
800 } | |
818 | 801 |
819 base::ElapsedTimer commit_update_timer; | 802 base::ElapsedTimer commit_update_timer; |
820 | 803 |
821 // Commit this transaction and send the updated JumpList to Windows. | 804 // Commit this transaction and send the updated JumpList to Windows. |
822 bool commit_result = jumplist_updater.CommitUpdate(); | 805 if (!jumplist_updater.CommitUpdate()) |
806 update_results->update_success_ = false; | |
823 | 807 |
824 if (commit_update_timer.Elapsed() >= kTimeOutForJumplistCommitUpdate) | 808 if (commit_update_timer.Elapsed() >= kTimeOutForJumplistCommitUpdate) |
809 update_results->update_timeout_ = true; | |
810 | |
811 return; | |
grt (UTC plus 2)
2017/06/09 10:42:57
omit
chengx
2017/06/10 05:56:17
Done.
| |
812 } | |
813 | |
814 void JumpList::OnRunUpdateCompletion( | |
815 std::unique_ptr<JumpListUpdateResults> update_results) { | |
816 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
817 | |
818 // Update JumpList member variables based on the results from the update run | |
819 // just finished. | |
820 if (update_results->update_timeout_) | |
825 updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad; | 821 updates_to_skip_ = kUpdatesToSkipUnderHeavyLoad; |
826 | 822 |
827 return commit_result; | 823 if (update_results->update_success_) { |
828 } | 824 most_visited_icons_.swap(update_results->most_visited_icons_in_update_); |
829 | 825 recently_closed_icons_.swap( |
830 void JumpList::RunUpdateJumpList( | 826 update_results->recently_closed_icons_in_update); |
831 IncognitoModePrefs::Availability incognito_availability, | 827 most_visited_pages_have_updates_ = false; |
832 const base::string16& app_id, | 828 recently_closed_pages_have_updates_ = false; |
833 const base::FilePath& profile_dir, | |
834 base::RefCountedData<JumpListData>* ref_counted_data) { | |
835 JumpListData* data = &ref_counted_data->data; | |
836 ShellLinkItemList local_most_visited_pages; | |
837 ShellLinkItemList local_recently_closed_pages; | |
838 bool most_visited_pages_have_updates; | |
839 bool recently_closed_pages_have_updates; | |
840 | |
841 { | |
842 base::AutoLock auto_lock(data->list_lock_); | |
843 // Make sure we are not out of date: if icon_urls_ is not empty, then | |
844 // another notification has been received since we processed this one | |
845 if (!data->icon_urls_.empty()) | |
846 return; | |
847 | |
848 // Make local copies of lists and flags so we can release the lock. | |
849 local_most_visited_pages = data->most_visited_pages_; | |
850 local_recently_closed_pages = data->recently_closed_pages_; | |
851 | |
852 most_visited_pages_have_updates = data->most_visited_pages_have_updates_; | |
853 recently_closed_pages_have_updates = | |
854 data->recently_closed_pages_have_updates_; | |
855 | |
856 // Clear the flags to reflect that we'll take actions on these updates. | |
857 data->most_visited_pages_have_updates_ = false; | |
858 data->recently_closed_pages_have_updates_ = false; | |
859 } | 829 } |
860 | 830 |
861 if (!most_visited_pages_have_updates && !recently_closed_pages_have_updates) | 831 update_in_progress_ = false; |
862 return; | |
863 | 832 |
864 // Update the application JumpList. If it fails, reset the flags to true if | 833 // Start another JumpList update if there is any new notification during the |
865 // they were so that the corresponding JumpList categories will be tried to | 834 // update run just finished. |
866 // update again in the next run. | 835 if (most_visited_has_pending_notification_ || |
867 if (!UpdateJumpList( | 836 recently_closed_has_pending_notification_) { |
868 app_id, profile_dir, local_most_visited_pages, | 837 if (timer_.IsRunning()) { |
869 local_recently_closed_pages, most_visited_pages_have_updates, | 838 timer_.Reset(); |
870 recently_closed_pages_have_updates, incognito_availability)) { | 839 } else { |
871 base::AutoLock auto_lock(data->list_lock_); | 840 timer_.Start( |
872 if (most_visited_pages_have_updates) | 841 FROM_HERE, kDelayForJumplistUpdate, |
873 data->most_visited_pages_have_updates_ = true; | 842 base::Bind(&JumpList::DeferredChanged, base::Unretained(this))); |
874 if (recently_closed_pages_have_updates) | 843 } |
875 data->recently_closed_pages_have_updates_ = true; | |
876 } | 844 } |
845 | |
846 return; | |
877 } | 847 } |
OLD | NEW |