Chromium Code Reviews| 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 |