| 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 <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 #include "ui/gfx/image/image_family.h" | 57 #include "ui/gfx/image/image_family.h" |
| 58 #include "ui/gfx/image/image_skia.h" | 58 #include "ui/gfx/image/image_skia.h" |
| 59 #include "ui/gfx/image/image_skia_rep.h" | 59 #include "ui/gfx/image/image_skia_rep.h" |
| 60 #include "url/gurl.h" | 60 #include "url/gurl.h" |
| 61 | 61 |
| 62 using content::BrowserThread; | 62 using content::BrowserThread; |
| 63 using JumpListData = JumpList::JumpListData; | 63 using JumpListData = JumpList::JumpListData; |
| 64 | 64 |
| 65 namespace { | 65 namespace { |
| 66 | 66 |
| 67 // Delay jumplist updates to allow collapsing of redundant update requests. | 67 // The delay before updating the JumpList to prevent update storms. |
| 68 constexpr base::TimeDelta kDelayForJumplistUpdate = | 68 constexpr base::TimeDelta kDelayForJumplistUpdate = |
| 69 base::TimeDelta::FromMilliseconds(3500); | 69 base::TimeDelta::FromMilliseconds(3500); |
| 70 | 70 |
| 71 // Timeout jumplist updates for users with extremely slow OS. | 71 // The maximum allowed time for JumpListUpdater::BeginUpdate. Updates taking |
| 72 // longer than this are discarded to prevent bogging down slow machines. |
| 72 constexpr base::TimeDelta kTimeOutForJumplistUpdate = | 73 constexpr base::TimeDelta kTimeOutForJumplistUpdate = |
| 73 base::TimeDelta::FromMilliseconds(500); | 74 base::TimeDelta::FromMilliseconds(500); |
| 74 | 75 |
| 75 // Append the common switches to each shell link. | 76 // Append the common switches to each shell link. |
| 76 void AppendCommonSwitches(ShellLinkItem* shell_link) { | 77 void AppendCommonSwitches(ShellLinkItem* shell_link) { |
| 77 const char* kSwitchNames[] = { switches::kUserDataDir }; | 78 const char* kSwitchNames[] = { switches::kUserDataDir }; |
| 78 const base::CommandLine& command_line = | 79 const base::CommandLine& command_line = |
| 79 *base::CommandLine::ForCurrentProcess(); | 80 *base::CommandLine::ForCurrentProcess(); |
| 80 shell_link->GetCommandLine()->CopySwitchesFrom(command_line, | 81 shell_link->GetCommandLine()->CopySwitchesFrom(command_line, |
| 81 kSwitchNames, | 82 kSwitchNames, |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 119 base::DeleteFile(path, false); | 120 base::DeleteFile(path, false); |
| 120 return false; | 121 return false; |
| 121 } | 122 } |
| 122 | 123 |
| 123 // Add this icon file to the list and return its absolute path. | 124 // Add this icon file to the list and return its absolute path. |
| 124 // The IShellLink::SetIcon() function needs the absolute path to an icon. | 125 // The IShellLink::SetIcon() function needs the absolute path to an icon. |
| 125 *icon_path = path; | 126 *icon_path = path; |
| 126 return true; | 127 return true; |
| 127 } | 128 } |
| 128 | 129 |
| 129 // Helper method for RunUpdate to create icon files for the asynchrounously | 130 // Creates icon files for the asynchrounously loaded icons. |
| 130 // loaded icons. | |
| 131 void CreateIconFiles(const base::FilePath& icon_dir, | 131 void CreateIconFiles(const base::FilePath& icon_dir, |
| 132 const ShellLinkItemList& item_list, | 132 const ShellLinkItemList& item_list, |
| 133 size_t max_items) { | 133 size_t max_items) { |
| 134 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | 134 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
| 135 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration"); | 135 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.CreateIconFilesDuration"); |
| 136 | 136 |
| 137 for (ShellLinkItemList::const_iterator item = item_list.begin(); | 137 for (ShellLinkItemList::const_iterator item = item_list.begin(); |
| 138 item != item_list.end() && max_items > 0; ++item, --max_items) { | 138 item != item_list.end() && max_items > 0; ++item, --max_items) { |
| 139 base::FilePath icon_path; | 139 base::FilePath icon_path; |
| 140 if (CreateIconFile((*item)->icon_image(), icon_dir, &icon_path)) | 140 if (CreateIconFile((*item)->icon_image(), icon_dir, &icon_path)) |
| 141 (*item)->set_icon(icon_path.value(), 0); | 141 (*item)->set_icon(icon_path.value(), 0); |
| 142 } | 142 } |
| 143 } | 143 } |
| 144 | 144 |
| 145 // Updates icon files in |icon_dir|, which includes deleting old icons and |
| 146 // creating at most |slot_limit| new icons for |page_list|. |
| 147 void UpdateIconFiles(const base::FilePath& icon_dir, |
| 148 const ShellLinkItemList& page_list, |
| 149 size_t slot_limit) { |
| 150 DeleteDirectoryContentAndLogRuntime(icon_dir, kFileDeleteLimit); |
| 151 |
| 152 // Create new icons only when the directory exists and is empty. |
| 153 if (base::CreateDirectory(icon_dir) && base::IsDirectoryEmpty(icon_dir)) |
| 154 CreateIconFiles(icon_dir, page_list, slot_limit); |
| 155 } |
| 156 |
| 145 // Updates the "Tasks" category of the JumpList. | 157 // Updates the "Tasks" category of the JumpList. |
| 146 bool UpdateTaskCategory( | 158 bool UpdateTaskCategory( |
| 147 JumpListUpdater* jumplist_updater, | 159 JumpListUpdater* jumplist_updater, |
| 148 IncognitoModePrefs::Availability incognito_availability) { | 160 IncognitoModePrefs::Availability incognito_availability) { |
| 149 base::FilePath chrome_path; | 161 base::FilePath chrome_path; |
| 150 if (!PathService::Get(base::FILE_EXE, &chrome_path)) | 162 if (!PathService::Get(base::FILE_EXE, &chrome_path)) |
| 151 return false; | 163 return false; |
| 152 | 164 |
| 153 int icon_index = install_static::GetIconResourceIndex(); | 165 int icon_index = install_static::GetIconResourceIndex(); |
| 154 | 166 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 bool UpdateJumpList(const wchar_t* app_id, | 205 bool UpdateJumpList(const wchar_t* app_id, |
| 194 const base::FilePath& icon_dir, | 206 const base::FilePath& icon_dir, |
| 195 const ShellLinkItemList& most_visited_pages, | 207 const ShellLinkItemList& most_visited_pages, |
| 196 const ShellLinkItemList& recently_closed_pages, | 208 const ShellLinkItemList& recently_closed_pages, |
| 197 bool most_visited_pages_have_updates, | 209 bool most_visited_pages_have_updates, |
| 198 bool recently_closed_pages_have_updates, | 210 bool recently_closed_pages_have_updates, |
| 199 IncognitoModePrefs::Availability incognito_availability) { | 211 IncognitoModePrefs::Availability incognito_availability) { |
| 200 if (!JumpListUpdater::IsEnabled()) | 212 if (!JumpListUpdater::IsEnabled()) |
| 201 return true; | 213 return true; |
| 202 | 214 |
| 203 // Records the time cost of starting a JumpListUpdater. | 215 JumpListUpdater jumplist_updater(app_id); |
| 216 |
| 204 base::ElapsedTimer begin_update_timer; | 217 base::ElapsedTimer begin_update_timer; |
| 205 | 218 |
| 206 JumpListUpdater jumplist_updater(app_id); | |
| 207 if (!jumplist_updater.BeginUpdate()) | 219 if (!jumplist_updater.BeginUpdate()) |
| 208 return false; | 220 return false; |
| 209 | 221 |
| 210 // Stops jumplist update if JumpListUpdater's start times out, as it's very | 222 // Discard this JumpList update if JumpListUpdater::BeginUpdate takes longer |
| 211 // likely the following update steps will also take a long time. | 223 // than the maximum allowed time, as it's very likely the following update |
| 224 // steps will also take a long time. |
| 212 if (begin_update_timer.Elapsed() >= kTimeOutForJumplistUpdate) | 225 if (begin_update_timer.Elapsed() >= kTimeOutForJumplistUpdate) |
| 213 return false; | 226 return false; |
| 214 | 227 |
| 215 // The default maximum number of items to display in JumpList is 10. | 228 // The default maximum number of items to display in JumpList is 10. |
| 216 // https://msdn.microsoft.com/library/windows/desktop/dd378398.aspx | 229 // https://msdn.microsoft.com/library/windows/desktop/dd378398.aspx |
| 217 // The "Most visited" category title always takes 1 of the JumpList slots if | 230 // The "Most visited" category title always takes 1 of the JumpList slots if |
| 218 // |most_visited_pages| isn't empty. | 231 // |most_visited_pages| isn't empty. |
| 219 // The "Recently closed" category title will also take 1 if | 232 // The "Recently closed" category title will also take 1 if |
| 220 // |recently_closed_pages| isn't empty. | 233 // |recently_closed_pages| isn't empty. |
| 221 // For the remaining slots, we allocate 5/8 (i.e., 5 slots if both categories | 234 // For the remaining slots, we allocate 5/8 (i.e., 5 slots if both categories |
| (...skipping 17 matching lines...) Expand all Loading... |
| 239 MulDiv(user_max_items_adjusted, kMostVisited, kTotal); | 252 MulDiv(user_max_items_adjusted, kMostVisited, kTotal); |
| 240 size_t recently_closed_items = user_max_items_adjusted - most_visited_items; | 253 size_t recently_closed_items = user_max_items_adjusted - most_visited_items; |
| 241 if (recently_closed_pages.size() < recently_closed_items) { | 254 if (recently_closed_pages.size() < recently_closed_items) { |
| 242 most_visited_items += recently_closed_items - recently_closed_pages.size(); | 255 most_visited_items += recently_closed_items - recently_closed_pages.size(); |
| 243 recently_closed_items = recently_closed_pages.size(); | 256 recently_closed_items = recently_closed_pages.size(); |
| 244 } | 257 } |
| 245 | 258 |
| 246 // Record the desired number of icons to create in this JumpList update. | 259 // Record the desired number of icons to create in this JumpList update. |
| 247 int icons_to_create = 0; | 260 int icons_to_create = 0; |
| 248 | 261 |
| 262 // Update the icons for "Most Visisted" category of the JumpList if needed. |
| 249 if (most_visited_pages_have_updates) { | 263 if (most_visited_pages_have_updates) { |
| 250 // Delete the content in JumpListIconsMostVisited folder and log the results | |
| 251 // to UMA. | |
| 252 base::FilePath icon_dir_most_visited = icon_dir.DirName().Append( | 264 base::FilePath icon_dir_most_visited = icon_dir.DirName().Append( |
| 253 icon_dir.BaseName().value() + FILE_PATH_LITERAL("MostVisited")); | 265 icon_dir.BaseName().value() + FILE_PATH_LITERAL("MostVisited")); |
| 254 | 266 |
| 255 DeleteDirectoryContentAndLogResults(icon_dir_most_visited, | 267 UpdateIconFiles(icon_dir_most_visited, most_visited_pages, |
| 256 kFileDeleteLimit); | 268 most_visited_items); |
| 257 | 269 |
| 258 // If the directory doesn't exist (we have tried to create it in | 270 icons_to_create += std::min(most_visited_pages.size(), most_visited_items); |
| 259 // DeleteDirectoryContentAndLogResults) or is not empty, skip updating the | |
| 260 // jumplist icons. The jumplist links should be updated anyway, as it | |
| 261 // doesn't involve disk IO. In this case, Chrome's icon will be used for the | |
| 262 // new links. | |
| 263 if (base::DirectoryExists(icon_dir_most_visited) && | |
| 264 base::IsDirectoryEmpty(icon_dir_most_visited)) { | |
| 265 // Create icon files for shortcuts in the "Most Visited" category. | |
| 266 CreateIconFiles(icon_dir_most_visited, most_visited_pages, | |
| 267 most_visited_items); | |
| 268 | |
| 269 icons_to_create += | |
| 270 std::min(most_visited_pages.size(), most_visited_items); | |
| 271 } | |
| 272 } | 271 } |
| 273 | 272 |
| 273 // Update the icons for "Recently Closed" category of the JumpList if needed. |
| 274 if (recently_closed_pages_have_updates) { | 274 if (recently_closed_pages_have_updates) { |
| 275 // Delete the content in JumpListIconsRecentClosed folder and log the | |
| 276 // results to UMA. | |
| 277 base::FilePath icon_dir_recent_closed = icon_dir.DirName().Append( | 275 base::FilePath icon_dir_recent_closed = icon_dir.DirName().Append( |
| 278 icon_dir.BaseName().value() + FILE_PATH_LITERAL("RecentClosed")); | 276 icon_dir.BaseName().value() + FILE_PATH_LITERAL("RecentClosed")); |
| 279 | 277 |
| 280 DeleteDirectoryContentAndLogResults(icon_dir_recent_closed, | 278 UpdateIconFiles(icon_dir_recent_closed, recently_closed_pages, |
| 281 kFileDeleteLimit); | 279 recently_closed_items); |
| 282 | 280 |
| 283 if (base::DirectoryExists(icon_dir_recent_closed) && | 281 icons_to_create += |
| 284 base::IsDirectoryEmpty(icon_dir_recent_closed)) { | 282 std::min(recently_closed_pages.size(), recently_closed_items); |
| 285 // Create icon files for shortcuts in the "Recently Closed" category. | |
| 286 CreateIconFiles(icon_dir_recent_closed, recently_closed_pages, | |
| 287 recently_closed_items); | |
| 288 | |
| 289 icons_to_create += | |
| 290 std::min(recently_closed_pages.size(), recently_closed_items); | |
| 291 } | |
| 292 } | 283 } |
| 293 | 284 |
| 294 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | 285 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
| 295 UMA_HISTOGRAM_COUNTS_100("WinJumplist.CreateIconFilesCount", icons_to_create); | 286 UMA_HISTOGRAM_COUNTS_100("WinJumplist.CreateIconFilesCount", icons_to_create); |
| 296 | 287 |
| 297 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. | 288 // TODO(chengx): Remove the UMA histogram after fixing http://crbug.com/40407. |
| 298 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.UpdateJumpListDuration"); | 289 SCOPED_UMA_HISTOGRAM_TIMER("WinJumplist.UpdateJumpListDuration"); |
| 299 | 290 |
| 300 // Update the "Most Visited" category of the JumpList if it exists. | 291 // Update the "Most Visited" category of the JumpList if it exists. |
| 301 // This update request is applied into the JumpList when we commit this | 292 // This update request is applied into the JumpList when we commit this |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 data->recently_closed_pages_have_updates_; | 339 data->recently_closed_pages_have_updates_; |
| 349 | 340 |
| 350 // Clear the flags to reflect that we'll take actions on these updates. | 341 // Clear the flags to reflect that we'll take actions on these updates. |
| 351 data->most_visited_pages_have_updates_ = false; | 342 data->most_visited_pages_have_updates_ = false; |
| 352 data->recently_closed_pages_have_updates_ = false; | 343 data->recently_closed_pages_have_updates_ = false; |
| 353 } | 344 } |
| 354 | 345 |
| 355 if (!most_visited_pages_have_updates && !recently_closed_pages_have_updates) | 346 if (!most_visited_pages_have_updates && !recently_closed_pages_have_updates) |
| 356 return; | 347 return; |
| 357 | 348 |
| 358 // Updates the application JumpList. If it fails, reset the flags to true if | 349 // Update the application JumpList. If it fails, reset the flags to true if |
| 359 // they were so that the corresponding JumpList categories will be tried to | 350 // they were so that the corresponding JumpList categories will be tried to |
| 360 // update again in the next run. | 351 // update again in the next run. |
| 361 if (!UpdateJumpList( | 352 if (!UpdateJumpList( |
| 362 app_id.c_str(), icon_dir, local_most_visited_pages, | 353 app_id.c_str(), icon_dir, local_most_visited_pages, |
| 363 local_recently_closed_pages, most_visited_pages_have_updates, | 354 local_recently_closed_pages, most_visited_pages_have_updates, |
| 364 recently_closed_pages_have_updates, incognito_availability)) { | 355 recently_closed_pages_have_updates, incognito_availability)) { |
| 365 base::AutoLock auto_lock(data->list_lock_); | 356 base::AutoLock auto_lock(data->list_lock_); |
| 366 if (most_visited_pages_have_updates) | 357 if (most_visited_pages_have_updates) |
| 367 data->most_visited_pages_have_updates_ = true; | 358 data->most_visited_pages_have_updates_ = true; |
| 368 if (recently_closed_pages_have_updates) | 359 if (recently_closed_pages_have_updates) |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 694 // Post a task to update the JumpList, which consists of 1) delete old icons, | 685 // Post a task to update the JumpList, which consists of 1) delete old icons, |
| 695 // 2) create new icons, 3) notify the OS. | 686 // 2) create new icons, 3) notify the OS. |
| 696 update_jumplist_task_runner_->PostTask( | 687 update_jumplist_task_runner_->PostTask( |
| 697 FROM_HERE, base::Bind(&RunUpdateJumpList, incognito_availability, app_id_, | 688 FROM_HERE, base::Bind(&RunUpdateJumpList, incognito_availability, app_id_, |
| 698 icon_dir_, base::RetainedRef(jumplist_data_))); | 689 icon_dir_, base::RetainedRef(jumplist_data_))); |
| 699 | 690 |
| 700 // Post a task to delete JumpListIcons folder as it's no longer needed. | 691 // Post a task to delete JumpListIcons folder as it's no longer needed. |
| 701 // Now we have JumpListIconsMostVisited folder and JumpListIconsRecentClosed | 692 // Now we have JumpListIconsMostVisited folder and JumpListIconsRecentClosed |
| 702 // folder instead. | 693 // folder instead. |
| 703 delete_jumplisticons_task_runner_->PostTask( | 694 delete_jumplisticons_task_runner_->PostTask( |
| 704 FROM_HERE, | 695 FROM_HERE, base::Bind(&DeleteDirectory, icon_dir_, kFileDeleteLimit)); |
| 705 base::Bind(&DeleteDirectoryAndLogResults, icon_dir_, kFileDeleteLimit)); | |
| 706 | 696 |
| 707 // Post a task to delete JumpListIconsOld folder as it's no longer needed. | 697 // Post a task to delete JumpListIconsOld folder as it's no longer needed. |
| 708 base::FilePath icon_dir_old = icon_dir_.DirName().Append( | 698 base::FilePath icon_dir_old = icon_dir_.DirName().Append( |
| 709 icon_dir_.BaseName().value() + FILE_PATH_LITERAL("Old")); | 699 icon_dir_.BaseName().value() + FILE_PATH_LITERAL("Old")); |
| 710 | 700 |
| 711 delete_jumplisticons_task_runner_->PostTask( | 701 delete_jumplisticons_task_runner_->PostTask( |
| 712 FROM_HERE, base::Bind(&DeleteDirectoryAndLogResults, | 702 FROM_HERE, |
| 713 std::move(icon_dir_old), kFileDeleteLimit)); | 703 base::Bind(&DeleteDirectory, std::move(icon_dir_old), kFileDeleteLimit)); |
| 714 } | 704 } |
| 715 | 705 |
| 716 void JumpList::TopSitesLoaded(history::TopSites* top_sites) { | 706 void JumpList::TopSitesLoaded(history::TopSites* top_sites) { |
| 717 } | 707 } |
| 718 | 708 |
| 719 void JumpList::TopSitesChanged(history::TopSites* top_sites, | 709 void JumpList::TopSitesChanged(history::TopSites* top_sites, |
| 720 ChangeReason change_reason) { | 710 ChangeReason change_reason) { |
| 721 top_sites->GetMostVisitedURLs( | 711 top_sites->GetMostVisitedURLs( |
| 722 base::Bind(&JumpList::OnMostVisitedURLsAvailable, | 712 base::Bind(&JumpList::OnMostVisitedURLsAvailable, |
| 723 weak_ptr_factory_.GetWeakPtr()), | 713 weak_ptr_factory_.GetWeakPtr()), |
| 724 false); | 714 false); |
| 725 } | 715 } |
| OLD | NEW |