Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(199)

Side by Side Diff: chrome/browser/media_galleries/media_folder_finder.cc

Issue 166353002: Media Galleries: Refactor media scan worker function into a worker class. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix clang Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/media_galleries/media_folder_finder.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/media_galleries/media_folder_finder.h" 5 #include "chrome/browser/media_galleries/media_folder_finder.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 9
10 #include "base/files/file_enumerator.h" 10 #include "base/files/file_enumerator.h"
11 #include "base/path_service.h" 11 #include "base/path_service.h"
12 #include "base/sequence_checker.h"
12 #include "base/stl_util.h" 13 #include "base/stl_util.h"
13 #include "base/strings/string_util.h" 14 #include "base/strings/string_util.h"
14 #include "base/task_runner_util.h" 15 #include "base/task_runner_util.h"
15 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h" 16 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
16 #include "chrome/browser/storage_monitor/storage_monitor.h" 17 #include "chrome/browser/storage_monitor/storage_monitor.h"
17 #include "content/public/browser/browser_thread.h" 18 #include "content/public/browser/browser_thread.h"
18 19
19 #if defined(OS_CHROMEOS) 20 #if defined(OS_CHROMEOS)
20 #include "chrome/common/chrome_paths.h" 21 #include "chrome/common/chrome_paths.h"
21 #include "chromeos/dbus/cros_disks_client.h" 22 #include "chromeos/dbus/cros_disks_client.h"
22 #endif 23 #endif
23 24
24 typedef base::Callback<void(const std::vector<base::FilePath>& /*roots*/)> 25 typedef base::Callback<void(const std::vector<base::FilePath>& /*roots*/)>
25 DefaultScanRootsCallback; 26 DefaultScanRootsCallback;
26 using content::BrowserThread; 27 using content::BrowserThread;
27 28
28 namespace { 29 namespace {
29 30
30 const int64 kMinimumImageSize = 200 * 1024; // 200 KB 31 const int64 kMinimumImageSize = 200 * 1024; // 200 KB
31 const int64 kMinimumAudioSize = 500 * 1024; // 500 KB 32 const int64 kMinimumAudioSize = 500 * 1024; // 500 KB
32 const int64 kMinimumVideoSize = 1024 * 1024; // 1 MB 33 const int64 kMinimumVideoSize = 1024 * 1024; // 1 MB
33 34
34 bool IsValidScanPath(const base::FilePath& path) { 35 bool IsValidScanPath(const base::FilePath& path) {
35 return !path.empty() && path.IsAbsolute(); 36 return !path.empty() && path.IsAbsolute();
36 } 37 }
37 38
38 MediaGalleryScanFileType FilterPath(MediaPathFilter* filter, 39 void CountScanResult(MediaGalleryScanFileType type,
39 const base::FilePath& path) { 40 MediaGalleryScanResult* scan_result) {
40 DCHECK(IsValidScanPath(path)); 41 if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE)
41 return filter->GetType(path); 42 scan_result->image_count += 1;
43 if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO)
44 scan_result->audio_count += 1;
45 if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO)
46 scan_result->video_count += 1;
42 } 47 }
43 48
44 bool FileMeetsSizeRequirement(bool requirement_met, 49 bool FileMeetsSizeRequirement(MediaGalleryScanFileType type, int64 size) {
45 MediaGalleryScanFileType type,
46 int64 size) {
47 if (requirement_met)
48 return true;
49
50 if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE) 50 if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE)
51 if (size >= kMinimumImageSize) 51 if (size >= kMinimumImageSize)
52 return true; 52 return true;
53 if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO) 53 if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO)
54 if (size >= kMinimumAudioSize) 54 if (size >= kMinimumAudioSize)
55 return true; 55 return true;
56 if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO) 56 if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO)
57 if (size >= kMinimumVideoSize) 57 if (size >= kMinimumVideoSize)
58 return true; 58 return true;
59 return false; 59 return false;
60 } 60 }
61 61
62 void ScanFolderOnBlockingPool(
63 const base::FilePath& path,
64 const MediaFolderFinder::FilterCallback& filter_callback_,
65 MediaGalleryScanResult* scan_result,
66 std::vector<base::FilePath>* new_folders) {
67 CHECK(IsValidScanPath(path));
68 DCHECK(scan_result);
69 DCHECK(new_folders);
70 DCHECK(IsEmptyScanResult(*scan_result));
71
72 bool folder_meets_size_requirement = false;
73 base::FileEnumerator enumerator(
74 path,
75 false, /* recursive? */
76 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES
77 #if defined(OS_POSIX)
78 | base::FileEnumerator::SHOW_SYM_LINKS // show symlinks, not follow.
79 #endif
80 );
81 while (!enumerator.Next().empty()) {
82 base::FileEnumerator::FileInfo file_info = enumerator.GetInfo();
83 base::FilePath full_path = path.Append(file_info.GetName());
84 if (MediaPathFilter::ShouldSkip(full_path))
85 continue;
86
87 if (file_info.IsDirectory()) {
88 new_folders->push_back(full_path);
89 continue;
90 }
91 MediaGalleryScanFileType type = filter_callback_.Run(full_path);
92 if (type == MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN)
93 continue;
94
95 // Make sure there is at least 1 file above a size threshold.
96 if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE)
97 scan_result->image_count += 1;
98 if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO)
99 scan_result->audio_count += 1;
100 if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO)
101 scan_result->video_count += 1;
102 folder_meets_size_requirement =
103 FileMeetsSizeRequirement(folder_meets_size_requirement,
104 type,
105 file_info.GetSize());
106 }
107 if (!folder_meets_size_requirement) {
108 scan_result->image_count = 0;
109 scan_result->audio_count = 0;
110 scan_result->video_count = 0;
111 }
112 }
113
114 // Return true if |path| should not be considered as the starting point for a 62 // Return true if |path| should not be considered as the starting point for a
115 // media scan. 63 // media scan.
116 bool ShouldIgnoreScanRoot(const base::FilePath& path) { 64 bool ShouldIgnoreScanRoot(const base::FilePath& path) {
117 #if defined(OS_MACOSX) 65 #if defined(OS_MACOSX)
118 // Scanning root is of little value. 66 // Scanning root is of little value.
119 return (path.value() == "/"); 67 return (path.value() == "/");
120 #elif defined(OS_CHROMEOS) 68 #elif defined(OS_CHROMEOS)
121 // Sanity check to make sure mount points are where they should be. 69 // Sanity check to make sure mount points are where they should be.
122 base::FilePath mount_point = 70 base::FilePath mount_point =
123 chromeos::CrosDisksClient::GetRemovableDiskMountPoint(); 71 chromeos::CrosDisksClient::GetRemovableDiskMountPoint();
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 } 130 }
183 131
184 base::FilePath platform_root = GetPlatformSpecificDefaultScanRoot(); 132 base::FilePath platform_root = GetPlatformSpecificDefaultScanRoot();
185 if (!platform_root.empty()) 133 if (!platform_root.empty())
186 roots.push_back(platform_root); 134 roots.push_back(platform_root);
187 callback.Run(roots); 135 callback.Run(roots);
188 } 136 }
189 137
190 } // namespace 138 } // namespace
191 139
140 MediaFolderFinder::WorkerReply::WorkerReply() {}
141
142 MediaFolderFinder::WorkerReply::~WorkerReply() {}
143
144 // The Worker is created on the UI thread, but does all its work on a blocking
145 // SequencedTaskRunner.
146 class MediaFolderFinder::Worker {
147 public:
148 Worker();
149 ~Worker();
150
151 // Scans |path| and return the results.
152 WorkerReply ScanFolder(const base::FilePath& path);
153
154 private:
155 scoped_ptr<MediaPathFilter> filter_;
156
157 base::SequenceChecker sequence_checker_;
158
159 DISALLOW_COPY_AND_ASSIGN(Worker);
160 };
161
162 MediaFolderFinder::Worker::Worker() {
163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
164 filter_.reset(new MediaPathFilter);
165 sequence_checker_.DetachFromSequence();
166 }
167
168 MediaFolderFinder::Worker::~Worker() {
169 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
170 }
171
172 MediaFolderFinder::WorkerReply MediaFolderFinder::Worker::ScanFolder(
173 const base::FilePath& path) {
174 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
175 CHECK(IsValidScanPath(path));
176
177 WorkerReply reply;
178 bool folder_meets_size_requirement = false;
179 base::FileEnumerator enumerator(
180 path,
181 false, /* recursive? */
182 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES
183 #if defined(OS_POSIX)
184 | base::FileEnumerator::SHOW_SYM_LINKS // show symlinks, not follow.
185 #endif
186 );
187 while (!enumerator.Next().empty()) {
188 base::FileEnumerator::FileInfo file_info = enumerator.GetInfo();
189 base::FilePath full_path = path.Append(file_info.GetName());
190 if (MediaPathFilter::ShouldSkip(full_path))
191 continue;
192
193 if (file_info.IsDirectory()) {
194 reply.new_folders.push_back(full_path);
195 continue;
196 }
197 MediaGalleryScanFileType type = filter_->GetType(full_path);
198 if (type == MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN)
199 continue;
200
201 CountScanResult(type, &reply.scan_result);
202 if (!folder_meets_size_requirement) {
203 folder_meets_size_requirement =
204 FileMeetsSizeRequirement(type, file_info.GetSize());
205 }
206 }
207 // Make sure there is at least 1 file above a size threshold.
208 if (!folder_meets_size_requirement)
209 reply.scan_result = MediaGalleryScanResult();
210 return reply;
211 }
212
192 MediaFolderFinder::MediaFolderFinder( 213 MediaFolderFinder::MediaFolderFinder(
193 const MediaFolderFinderResultsCallback& callback) 214 const MediaFolderFinderResultsCallback& callback)
194 : results_callback_(callback), 215 : results_callback_(callback),
195 scan_state_(SCAN_STATE_NOT_STARTED), 216 scan_state_(SCAN_STATE_NOT_STARTED),
217 worker_(new Worker()),
196 has_roots_for_testing_(false), 218 has_roots_for_testing_(false),
197 weak_factory_(this) { 219 weak_factory_(this) {
198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
221
222 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
223 worker_task_runner_ = pool->GetSequencedTaskRunner(pool->GetSequenceToken());
199 } 224 }
200 225
201 MediaFolderFinder::~MediaFolderFinder() { 226 MediaFolderFinder::~MediaFolderFinder() {
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
228
229 worker_task_runner_->DeleteSoon(FROM_HERE, worker_);
230
203 if (scan_state_ == SCAN_STATE_FINISHED) 231 if (scan_state_ == SCAN_STATE_FINISHED)
204 return; 232 return;
205 233
206 MediaFolderFinderResults empty_results; 234 MediaFolderFinderResults empty_results;
207 results_callback_.Run(false /* success? */, empty_results); 235 results_callback_.Run(false /* success? */, empty_results);
208 } 236 }
209 237
210 void MediaFolderFinder::StartScan() { 238 void MediaFolderFinder::StartScan() {
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
212 240
(...skipping 12 matching lines...) Expand all
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 253 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
226 DCHECK_EQ(SCAN_STATE_NOT_STARTED, scan_state_); 254 DCHECK_EQ(SCAN_STATE_NOT_STARTED, scan_state_);
227 255
228 has_roots_for_testing_ = true; 256 has_roots_for_testing_ = true;
229 roots_for_testing_ = roots; 257 roots_for_testing_ = roots;
230 } 258 }
231 259
232 void MediaFolderFinder::OnInitialized( 260 void MediaFolderFinder::OnInitialized(
233 const std::vector<base::FilePath>& roots) { 261 const std::vector<base::FilePath>& roots) {
234 DCHECK_EQ(SCAN_STATE_STARTED, scan_state_); 262 DCHECK_EQ(SCAN_STATE_STARTED, scan_state_);
235 DCHECK(!token_.IsValid());
236 DCHECK(filter_callback_.is_null());
237 263
238 std::set<base::FilePath> valid_roots; 264 std::set<base::FilePath> valid_roots;
239 for (size_t i = 0; i < roots.size(); ++i) { 265 for (size_t i = 0; i < roots.size(); ++i) {
240 // Skip if |path| is invalid or redundant. 266 // Skip if |path| is invalid or redundant.
241 const base::FilePath& path = roots[i]; 267 const base::FilePath& path = roots[i];
242 if (!IsValidScanPath(path)) 268 if (!IsValidScanPath(path))
243 continue; 269 continue;
244 if (ContainsKey(valid_roots, path)) 270 if (ContainsKey(valid_roots, path))
245 continue; 271 continue;
246 272
(...skipping 14 matching lines...) Expand all
261 continue; 287 continue;
262 // Remove anything |path| overlaps from |valid_roots|. 288 // Remove anything |path| overlaps from |valid_roots|.
263 for (size_t i = 0; i < overlapping_paths_to_remove.size(); ++i) 289 for (size_t i = 0; i < overlapping_paths_to_remove.size(); ++i)
264 valid_roots.erase(overlapping_paths_to_remove[i]); 290 valid_roots.erase(overlapping_paths_to_remove[i]);
265 291
266 valid_roots.insert(path); 292 valid_roots.insert(path);
267 } 293 }
268 294
269 std::copy(valid_roots.begin(), valid_roots.end(), 295 std::copy(valid_roots.begin(), valid_roots.end(),
270 std::back_inserter(folders_to_scan_)); 296 std::back_inserter(folders_to_scan_));
271 token_ = BrowserThread::GetBlockingPool()->GetSequenceToken();
272 filter_callback_ = base::Bind(&FilterPath,
273 base::Owned(new MediaPathFilter()));
274 ScanFolder(); 297 ScanFolder();
275 } 298 }
276 299
277 void MediaFolderFinder::ScanFolder() { 300 void MediaFolderFinder::ScanFolder() {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
279 DCHECK_EQ(SCAN_STATE_STARTED, scan_state_); 302 DCHECK_EQ(SCAN_STATE_STARTED, scan_state_);
280 303
281 if (folders_to_scan_.empty()) { 304 if (folders_to_scan_.empty()) {
282 scan_state_ = SCAN_STATE_FINISHED; 305 scan_state_ = SCAN_STATE_FINISHED;
283 results_callback_.Run(true /* success? */, results_); 306 results_callback_.Run(true /* success? */, results_);
284 return; 307 return;
285 } 308 }
286 309
287 DCHECK(token_.IsValid());
288 DCHECK(!filter_callback_.is_null());
289
290 base::FilePath folder_to_scan = folders_to_scan_.back(); 310 base::FilePath folder_to_scan = folders_to_scan_.back();
291 folders_to_scan_.pop_back(); 311 folders_to_scan_.pop_back();
292 MediaGalleryScanResult* scan_result = new MediaGalleryScanResult(); 312 base::PostTaskAndReplyWithResult(
293 std::vector<base::FilePath>* new_folders = new std::vector<base::FilePath>(); 313 worker_task_runner_, FROM_HERE,
294 scoped_refptr<base::SequencedTaskRunner> task_runner = 314 base::Bind(&Worker::ScanFolder,
295 BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(token_); 315 base::Unretained(worker_),
296 task_runner->PostTaskAndReply( 316 folder_to_scan),
297 FROM_HERE,
298 base::Bind(&ScanFolderOnBlockingPool,
299 folder_to_scan,
300 filter_callback_,
301 base::Unretained(scan_result),
302 base::Unretained(new_folders)),
303 base::Bind(&MediaFolderFinder::GotScanResults, 317 base::Bind(&MediaFolderFinder::GotScanResults,
304 weak_factory_.GetWeakPtr(), 318 weak_factory_.GetWeakPtr(),
305 folder_to_scan, 319 folder_to_scan));
306 base::Owned(scan_result),
307 base::Owned(new_folders)));
308 } 320 }
309 321
310 void MediaFolderFinder::GotScanResults( 322 void MediaFolderFinder::GotScanResults(const base::FilePath& path,
311 const base::FilePath& path, 323 const WorkerReply& reply) {
312 const MediaGalleryScanResult* scan_result,
313 const std::vector<base::FilePath>* new_folders) {
314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
315 DCHECK_EQ(SCAN_STATE_STARTED, scan_state_); 325 DCHECK_EQ(SCAN_STATE_STARTED, scan_state_);
316 DCHECK(!path.empty()); 326 DCHECK(!path.empty());
317 DCHECK(scan_result);
318 DCHECK(new_folders);
319 CHECK(!ContainsKey(results_, path)); 327 CHECK(!ContainsKey(results_, path));
320 328
321 if (!IsEmptyScanResult(*scan_result)) 329 if (!IsEmptyScanResult(reply.scan_result))
322 results_[path] = *scan_result; 330 results_[path] = reply.scan_result;
323 331
324 // Push new folders to the |folders_to_scan_| in reverse order. 332 // Push new folders to the |folders_to_scan_| in reverse order.
325 std::copy(new_folders->rbegin(), new_folders->rend(), 333 std::copy(reply.new_folders.rbegin(), reply.new_folders.rend(),
326 std::back_inserter(folders_to_scan_)); 334 std::back_inserter(folders_to_scan_));
327 335
328 ScanFolder(); 336 ScanFolder();
329 } 337 }
OLDNEW
« no previous file with comments | « chrome/browser/media_galleries/media_folder_finder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698