15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/media_galleries/media_folder_finder.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <algorithm>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <set>
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/files/file_enumerator.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/path_service.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/sequence_checker.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/stl_util.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_util.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/task_runner_util.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/threading/sequenced_worker_pool.h"
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/extensions/api/file_system/file_system_api.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/common/chrome_paths.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/storage_monitor/storage_monitor.h"
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_CHROMEOS)
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/chrome_paths.h"
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chromeos/dbus/cros_disks_client.h"
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)using storage_monitor::StorageInfo;
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)using storage_monitor::StorageMonitor;
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef base::Callback<void(const std::vector<base::FilePath>& /*roots*/)>
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DefaultScanRootsCallback;
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using content::BrowserThread;
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int64 kMinimumImageSize = 200 * 1024;    // 200 KB
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int64 kMinimumAudioSize = 500 * 1024;    // 500 KB
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int64 kMinimumVideoSize = 1024 * 1024;   // 1 MB
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kPrunedPaths[] = {
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(OS_WIN)
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::DIR_IE_INTERNET_CACHE,
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::DIR_PROGRAM_FILES,
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::DIR_PROGRAM_FILESX86,
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::DIR_WINDOWS,
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(OS_MACOSX) && !defined(OS_IOS)
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  chrome::DIR_USER_APPLICATIONS,
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  chrome::DIR_USER_LIBRARY,
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(OS_LINUX)
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::DIR_CACHE,
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(OS_WIN) || defined(OS_LINUX)
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::DIR_TEMP,
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool IsValidScanPath(const base::FilePath& path) {
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return !path.empty() && path.IsAbsolute();
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CountScanResult(MediaGalleryScanFileType type,
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     MediaGalleryScanResult* scan_result) {
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE)
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scan_result->image_count += 1;
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scan_result->audio_count += 1;
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scan_result->video_count += 1;
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool FileMeetsSizeRequirement(MediaGalleryScanFileType type, int64 size) {
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE)
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (size >= kMinimumImageSize)
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return true;
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO)
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (size >= kMinimumAudioSize)
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return true;
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO)
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (size >= kMinimumVideoSize)
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return true;
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Return true if |path| should not be considered as the starting point for a
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// media scan.
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShouldIgnoreScanRoot(const base::FilePath& path) {
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_MACOSX)
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Scanning root is of little value.
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return (path.value() == "/");
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#elif defined(OS_CHROMEOS)
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Sanity check to make sure mount points are where they should be.
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FilePath mount_point =
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      chromeos::CrosDisksClient::GetRemovableDiskMountPoint();
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return mount_point.IsParent(path);
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#elif defined(OS_LINUX)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // /media and /mnt are likely the only places with interesting mount points.
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (StartsWithASCII(path.value(), "/media", true) ||
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      StartsWithASCII(path.value(), "/mnt", true)) {
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#elif defined(OS_WIN)
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#else
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOTIMPLEMENTED();
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Return a location that is likely to have user data to scan, if any.
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::FilePath GetPlatformSpecificDefaultScanRoot() {
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FilePath root;
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_CHROMEOS)
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS_SAFE, &root);
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#elif defined(OS_MACOSX) || defined(OS_LINUX)
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PathService::Get(base::DIR_HOME, &root);
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#elif defined(OS_WIN)
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Nothing to add.
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#else
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOTIMPLEMENTED();
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return root;
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Find the likely locations with user media files and pass them to
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// |callback|. Locations are platform specific.
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GetDefaultScanRoots(const DefaultScanRootsCallback& callback,
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         bool has_override,
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         const std::vector<base::FilePath>& override_paths) {
134e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (has_override) {
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback.Run(override_paths);
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  StorageMonitor* monitor = StorageMonitor::GetInstance();
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(monitor->IsInitialized());
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<base::FilePath> roots;
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<StorageInfo> storages = monitor->GetAllAvailableStorages();
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < storages.size(); ++i) {
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    StorageInfo::Type type;
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!StorageInfo::CrackDeviceId(storages[i].device_id(), &type, NULL) ||
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        (type != StorageInfo::FIXED_MASS_STORAGE &&
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         type != StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM)) {
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::FilePath path(storages[i].location());
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (ShouldIgnoreScanRoot(path))
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    roots.push_back(path);
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FilePath platform_root = GetPlatformSpecificDefaultScanRoot();
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!platform_root.empty())
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    roots.push_back(platform_root);
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(roots);
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MediaFolderFinder::WorkerReply::WorkerReply() {}
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MediaFolderFinder::WorkerReply::~WorkerReply() {}
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The Worker is created on the UI thread, but does all its work on a blocking
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// SequencedTaskRunner.
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class MediaFolderFinder::Worker {
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  explicit Worker(const std::vector<base::FilePath>& graylisted_folders);
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ~Worker();
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Scans |path| and return the results.
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WorkerReply ScanFolder(const base::FilePath& path);
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void MakeFolderPathsAbsolute();
183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool folder_paths_are_absolute_;
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<base::FilePath> graylisted_folders_;
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<base::FilePath> pruned_folders_;
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<MediaPathFilter> filter_;
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::SequenceChecker sequence_checker_;
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Worker);
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)MediaFolderFinder::Worker::Worker(
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::vector<base::FilePath>& graylisted_folders)
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : folder_paths_are_absolute_(false),
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      graylisted_folders_(graylisted_folders),
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      filter_(new MediaPathFilter) {
200e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (size_t i = 0; i < arraysize(kPrunedPaths); ++i) {
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::FilePath path;
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (PathService::Get(kPrunedPaths[i], &path))
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      pruned_folders_.push_back(path);
206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sequence_checker_.DetachFromSequence();
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MediaFolderFinder::Worker::~Worker() {
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MediaFolderFinder::WorkerReply MediaFolderFinder::Worker::ScanFolder(
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& path) {
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK(IsValidScanPath(path));
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!folder_paths_are_absolute_)
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    MakeFolderPathsAbsolute();
222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WorkerReply reply;
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool folder_meets_size_requirement = false;
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool is_graylisted_folder = false;
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::FilePath abspath = base::MakeAbsoluteFilePath(path);
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (abspath.empty())
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return reply;
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (size_t i = 0; i < graylisted_folders_.size(); ++i) {
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (abspath == graylisted_folders_[i] ||
232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        abspath.IsParent(graylisted_folders_[i])) {
233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      is_graylisted_folder = true;
234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      break;
235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FileEnumerator enumerator(
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      path,
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      false, /* recursive? */
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_POSIX)
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      | base::FileEnumerator::SHOW_SYM_LINKS  // show symlinks, not follow.
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      );  // NOLINT
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (!enumerator.Next().empty()) {
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::FileEnumerator::FileInfo file_info = enumerator.GetInfo();
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::FilePath full_path = path.Append(file_info.GetName());
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (MediaPathFilter::ShouldSkip(full_path))
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Enumerating a directory.
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (file_info.IsDirectory()) {
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      bool is_pruned_folder = false;
255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::FilePath abs_full_path = base::MakeAbsoluteFilePath(full_path);
256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (abs_full_path.empty())
257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        continue;
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      for (size_t i = 0; i < pruned_folders_.size(); ++i) {
259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (abs_full_path == pruned_folders_[i]) {
260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          is_pruned_folder = true;
261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          break;
262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        }
263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
265a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (!is_pruned_folder)
266a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        reply.new_folders.push_back(full_path);
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
270a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Enumerating a file.
271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    //
272a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Do not include scan results for graylisted folders.
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (is_graylisted_folder)
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      continue;
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MediaGalleryScanFileType type = filter_->GetType(full_path);
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (type == MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN)
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    CountScanResult(type, &reply.scan_result);
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!folder_meets_size_requirement) {
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      folder_meets_size_requirement =
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          FileMeetsSizeRequirement(type, file_info.GetSize());
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Make sure there is at least 1 file above a size threshold.
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!folder_meets_size_requirement)
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    reply.scan_result = MediaGalleryScanResult();
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return reply;
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void MediaFolderFinder::Worker::MakeFolderPathsAbsolute() {
293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!folder_paths_are_absolute_);
295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  folder_paths_are_absolute_ = true;
296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<base::FilePath> abs_paths;
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (size_t i = 0; i < graylisted_folders_.size(); ++i) {
299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::FilePath path = base::MakeAbsoluteFilePath(graylisted_folders_[i]);
300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (!path.empty())
301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      abs_paths.push_back(path);
302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  graylisted_folders_ = abs_paths;
304a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  abs_paths.clear();
305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (size_t i = 0; i < pruned_folders_.size(); ++i) {
306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::FilePath path = base::MakeAbsoluteFilePath(pruned_folders_[i]);
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (!path.empty())
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      abs_paths.push_back(path);
309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pruned_folders_ = abs_paths;
311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MediaFolderFinder::MediaFolderFinder(
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const MediaFolderFinderResultsCallback& callback)
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : results_callback_(callback),
316a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      graylisted_folders_(
317a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          extensions::file_system_api::GetGrayListedDirectories()),
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scan_state_(SCAN_STATE_NOT_STARTED),
319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      worker_(new Worker(graylisted_folders_)),
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      has_roots_for_testing_(false),
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      weak_factory_(this) {
322e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  worker_task_runner_ = pool->GetSequencedTaskRunner(pool->GetSequenceToken());
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MediaFolderFinder::~MediaFolderFinder() {
329e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  worker_task_runner_->DeleteSoon(FROM_HERE, worker_);
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (scan_state_ == SCAN_STATE_FINISHED)
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MediaFolderFinderResults empty_results;
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  results_callback_.Run(false /* success? */, empty_results);
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MediaFolderFinder::StartScan() {
341e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (scan_state_ != SCAN_STATE_NOT_STARTED)
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scan_state_ = SCAN_STATE_STARTED;
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GetDefaultScanRoots(
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&MediaFolderFinder::OnInitialized, weak_factory_.GetWeakPtr()),
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      has_roots_for_testing_,
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      roots_for_testing_);
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const std::vector<base::FilePath>&
354a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)MediaFolderFinder::graylisted_folders() const {
355a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return graylisted_folders_;
356a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MediaFolderFinder::SetRootsForTesting(
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::vector<base::FilePath>& roots) {
360e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(SCAN_STATE_NOT_STARTED, scan_state_);
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  has_roots_for_testing_ = true;
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  roots_for_testing_ = roots;
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MediaFolderFinder::OnInitialized(
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::vector<base::FilePath>& roots) {
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(SCAN_STATE_STARTED, scan_state_);
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::set<base::FilePath> valid_roots;
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < roots.size(); ++i) {
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Skip if |path| is invalid or redundant.
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& path = roots[i];
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!IsValidScanPath(path))
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (ContainsKey(valid_roots, path))
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Check for overlap.
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool valid_roots_contains_path = false;
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<base::FilePath> overlapping_paths_to_remove;
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (std::set<base::FilePath>::iterator it = valid_roots.begin();
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         it != valid_roots.end(); ++it) {
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (it->IsParent(path)) {
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        valid_roots_contains_path = true;
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        break;
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const base::FilePath& other_path = *it;
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (path.IsParent(other_path))
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        overlapping_paths_to_remove.push_back(other_path);
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (valid_roots_contains_path)
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Remove anything |path| overlaps from |valid_roots|.
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (size_t i = 0; i < overlapping_paths_to_remove.size(); ++i)
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid_roots.erase(overlapping_paths_to_remove[i]);
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    valid_roots.insert(path);
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::copy(valid_roots.begin(), valid_roots.end(),
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            std::back_inserter(folders_to_scan_));
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScanFolder();
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MediaFolderFinder::ScanFolder() {
408e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(SCAN_STATE_STARTED, scan_state_);
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (folders_to_scan_.empty()) {
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scan_state_ = SCAN_STATE_FINISHED;
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    results_callback_.Run(true /* success? */, results_);
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FilePath folder_to_scan = folders_to_scan_.back();
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  folders_to_scan_.pop_back();
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::PostTaskAndReplyWithResult(
4201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      worker_task_runner_.get(),
4211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      FROM_HERE,
4221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(
4231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          &Worker::ScanFolder, base::Unretained(worker_), folder_to_scan),
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&MediaFolderFinder::GotScanResults,
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 weak_factory_.GetWeakPtr(),
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 folder_to_scan));
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MediaFolderFinder::GotScanResults(const base::FilePath& path,
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       const WorkerReply& reply) {
431e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(SCAN_STATE_STARTED, scan_state_);
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!path.empty());
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK(!ContainsKey(results_, path));
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!IsEmptyScanResult(reply.scan_result))
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    results_[path] = reply.scan_result;
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Push new folders to the |folders_to_scan_| in reverse order.
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::copy(reply.new_folders.rbegin(), reply.new_folders.rend(),
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            std::back_inserter(folders_to_scan_));
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScanFolder();
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
445