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 |