Commit 70f57730 authored by thestig@chromium.org's avatar thestig@chromium.org

Media Galleries: Initial media scanner implementation.

BUG=161119

Review URL: https://codereview.chromium.org/149363004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247993 0039d316-1c4b-4281-b951-d872f2087c98
parent 0c930814
......@@ -12,7 +12,7 @@
namespace {
const base::FilePath::CharType* const kExtraSupportedExtensions[] = {
const base::FilePath::CharType* const kExtraSupportedImageExtensions[] = {
// RAW picture file types.
// Some of which are just image/tiff.
FILE_PATH_LITERAL("3fr"), // (Hasselblad)
......@@ -45,8 +45,9 @@ const base::FilePath::CharType* const kExtraSupportedExtensions[] = {
// - Leica / Panasonic RAW files - image/x-panasonic-raw
// - Phase One RAW files - image/x-phaseone-raw
FILE_PATH_LITERAL("raw"),
};
// Video files types.
const base::FilePath::CharType* const kExtraSupportedVideoExtensions[] = {
FILE_PATH_LITERAL("3gp"),
FILE_PATH_LITERAL("3gpp"),
FILE_PATH_LITERAL("avi"),
......@@ -58,9 +59,11 @@ const base::FilePath::CharType* const kExtraSupportedExtensions[] = {
FILE_PATH_LITERAL("mpegps"),
FILE_PATH_LITERAL("mpg"),
FILE_PATH_LITERAL("wmv"),
};
// Audio file types. Many of these file types are audio files in the same
// containers that the MIME sniffer already detects as video/subtype.
const base::FilePath::CharType* const kExtraSupportedAudioExtensions[] = {
// Many of these file types are audio files in the same containers that the
// MIME sniffer already detects as video/subtype.
FILE_PATH_LITERAL("aac"), // audio/mpeg
FILE_PATH_LITERAL("alac"), // video/mp4
FILE_PATH_LITERAL("flac"), // audio/x-flac
......@@ -75,6 +78,18 @@ bool IsUnsupportedExtension(const base::FilePath::StringType& extension) {
!net::IsSupportedMimeType(mime_type);
}
std::vector<base::FilePath::StringType> GetMediaExtensionList(
const std::string& mime_type) {
std::vector<base::FilePath::StringType> extensions;
net::GetExtensionsForMimeType(mime_type, &extensions);
std::vector<base::FilePath::StringType>::iterator new_end =
std::remove_if(extensions.begin(),
extensions.end(),
&IsUnsupportedExtension);
extensions.erase(new_end, extensions.end());
return extensions;
}
} // namespace
MediaPathFilter::MediaPathFilter()
......@@ -86,10 +101,16 @@ MediaPathFilter::~MediaPathFilter() {
}
bool MediaPathFilter::Match(const base::FilePath& path) {
return GetType(path) != MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN;
}
MediaGalleryScanFileType MediaPathFilter::GetType(const base::FilePath& path) {
EnsureInitialized();
return std::binary_search(media_file_extensions_.begin(),
media_file_extensions_.end(),
StringToLowerASCII(path.Extension()));
MediaFileExtensionMap::const_iterator it =
media_file_extensions_map_.find(StringToLowerASCII(path.Extension()));
if (it == media_file_extensions_map_.end())
return MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN;
return static_cast<MediaGalleryScanFileType>(it->second);
}
void MediaPathFilter::EnsureInitialized() {
......@@ -97,26 +118,51 @@ void MediaPathFilter::EnsureInitialized() {
if (initialized_)
return;
// This may require I/O, so doing this in the ctor and removing
// |initialized_| would result in a ThreadRestrictions failure.
net::GetExtensionsForMimeType("image/*", &media_file_extensions_);
net::GetExtensionsForMimeType("audio/*", &media_file_extensions_);
net::GetExtensionsForMimeType("video/*", &media_file_extensions_);
// This may require I/O when it calls net::GetExtensionsForMimeType(), so
// doing this in the ctor and removing |initialized_| would result in a
// ThreadRestrictions failure.
AddExtensionsToMediaFileExtensionMap(GetMediaExtensionList("image/*"),
MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE);
AddExtensionsToMediaFileExtensionMap(GetMediaExtensionList("audio/*"),
MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO);
AddExtensionsToMediaFileExtensionMap(GetMediaExtensionList("video/*"),
MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO);
AddAdditionalExtensionsToMediaFileExtensionMap(
kExtraSupportedImageExtensions,
arraysize(kExtraSupportedImageExtensions),
MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE);
AddAdditionalExtensionsToMediaFileExtensionMap(
kExtraSupportedAudioExtensions,
arraysize(kExtraSupportedAudioExtensions),
MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO);
AddAdditionalExtensionsToMediaFileExtensionMap(
kExtraSupportedVideoExtensions,
arraysize(kExtraSupportedVideoExtensions),
MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO);
MediaFileExtensionList::iterator new_end =
std::remove_if(media_file_extensions_.begin(),
media_file_extensions_.end(),
&IsUnsupportedExtension);
media_file_extensions_.erase(new_end, media_file_extensions_.end());
initialized_ = true;
}
// Add other common extensions.
for (size_t i = 0; i < arraysize(kExtraSupportedExtensions); ++i)
media_file_extensions_.push_back(kExtraSupportedExtensions[i]);
void MediaPathFilter::AddExtensionsToMediaFileExtensionMap(
const MediaFileExtensionList& extensions_list,
MediaGalleryScanFileType type) {
for (size_t i = 0; i < extensions_list.size(); ++i)
AddExtensionToMediaFileExtensionMap(extensions_list[i].c_str(), type);
}
for (MediaFileExtensionList::iterator itr = media_file_extensions_.begin();
itr != media_file_extensions_.end(); ++itr)
*itr = base::FilePath::kExtensionSeparator + *itr;
std::sort(media_file_extensions_.begin(), media_file_extensions_.end());
void MediaPathFilter::AddAdditionalExtensionsToMediaFileExtensionMap(
const base::FilePath::CharType* const* extensions_list,
size_t extensions_list_size,
MediaGalleryScanFileType type) {
for (size_t i = 0; i < extensions_list_size; ++i)
AddExtensionToMediaFileExtensionMap(extensions_list[i], type);
}
initialized_ = true;
void MediaPathFilter::AddExtensionToMediaFileExtensionMap(
const base::FilePath::CharType* extension,
MediaGalleryScanFileType type) {
base::FilePath::StringType extension_with_sep =
base::FilePath::kExtensionSeparator +
base::FilePath::StringType(extension);
media_file_extensions_map_[extension_with_sep] |= type;
}
......@@ -5,10 +5,13 @@
#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MEDIA_PATH_FILTER_H_
#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MEDIA_PATH_FILTER_H_
#include <string>
#include <vector>
#include "base/containers/hash_tables.h"
#include "base/files/file_path.h"
#include "base/sequence_checker.h"
#include "chrome/browser/media_galleries/media_scan_types.h"
// This class holds the list of file path extensions that we should expose on
// media filesystem.
......@@ -16,17 +19,38 @@ class MediaPathFilter {
public:
MediaPathFilter();
~MediaPathFilter();
// Returns true if |path| is a media file.
bool Match(const base::FilePath& path);
// Returns the type of |path| or MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN if it
// is not a media file.
MediaGalleryScanFileType GetType(const base::FilePath& path);
private:
typedef std::vector<base::FilePath::StringType> MediaFileExtensionList;
// Key: .extension
// Value: MediaGalleryScanFileType, but stored as an int to allow "|="
typedef base::hash_map<base::FilePath::StringType, int> MediaFileExtensionMap;
void EnsureInitialized();
void AddExtensionsToMediaFileExtensionMap(
const MediaFileExtensionList& extensions_list,
MediaGalleryScanFileType type);
void AddAdditionalExtensionsToMediaFileExtensionMap(
const base::FilePath::CharType* const* extensions_list,
size_t extensions_list_size,
MediaGalleryScanFileType type);
void AddExtensionToMediaFileExtensionMap(
const base::FilePath::CharType* extension,
MediaGalleryScanFileType type);
// Checks |initialized_| is only accessed on one sequence.
base::SequenceChecker sequence_checker_;
bool initialized_;
MediaFileExtensionList media_file_extensions_;
MediaFileExtensionMap media_file_extensions_map_;
DISALLOW_COPY_AND_ASSIGN(MediaPathFilter);
};
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/media_galleries/media_folder_finder.h"
#include "base/files/file_enumerator.h"
#include "base/stl_util.h"
#include "base/task_runner_util.h"
#include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
#include "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace {
bool IsValidScanPath(const base::FilePath& path) {
return !path.empty() && path.IsAbsolute();
}
MediaGalleryScanFileType FilterPath(MediaPathFilter* filter,
const base::FilePath& path) {
DCHECK(IsValidScanPath(path));
return filter->GetType(path);
}
void ScanFolderOnBlockingPool(
const base::FilePath& path,
const MediaFolderFinder::FilterCallback& filter_callback_,
MediaGalleryScanResult* scan_result,
std::vector<base::FilePath>* new_folders) {
CHECK(IsValidScanPath(path));
DCHECK(scan_result);
DCHECK(new_folders);
DCHECK(IsEmptyScanResult(*scan_result));
base::FileEnumerator enumerator(
path,
false, /* recursive? */
base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
while (!enumerator.Next().empty()) {
base::FileEnumerator::FileInfo file_info = enumerator.GetInfo();
base::FilePath full_path = path.Append(file_info.GetName());
if (file_info.IsDirectory()) {
new_folders->push_back(full_path);
continue;
}
// TODO(thestig) Make sure there is at least 1 file above a size threshold:
// images >= 200KB, videos >= 1MB, music >= 500KB.
MediaGalleryScanFileType type = filter_callback_.Run(full_path);
if (type == MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN)
continue;
if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE)
scan_result->image_count += 1;
if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO)
scan_result->audio_count += 1;
if (type & MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO)
scan_result->video_count += 1;
}
}
} // namespace
MediaFolderFinder::MediaFolderFinder(
const std::vector<base::FilePath>& roots,
const MediaFolderFinderResultsCallback& callback)
: results_callback_(callback),
scan_state_(SCAN_STATE_NOT_STARTED),
weak_factory_(this) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
for (size_t i = 0; i < roots.size(); ++i) {
const base::FilePath& path = roots[i];
if (!IsValidScanPath(path))
continue;
// TODO(thestig) Check |path| for overlap with the rest of |roots|.
folders_to_scan_.push(path);
}
}
MediaFolderFinder::~MediaFolderFinder() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (scan_state_ == SCAN_STATE_FINISHED)
return;
MediaFolderFinderResults empty_results;
results_callback_.Run(false /* success? */, empty_results);
}
void MediaFolderFinder::StartScan() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (scan_state_ != SCAN_STATE_NOT_STARTED)
return;
scan_state_ = SCAN_STATE_STARTED;
DCHECK(!token_.IsValid());
DCHECK(filter_callback_.is_null());
token_ = BrowserThread::GetBlockingPool()->GetSequenceToken();
filter_callback_ = base::Bind(&FilterPath,
base::Owned(new MediaPathFilter()));
ScanFolder();
}
void MediaFolderFinder::ScanFolder() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK_EQ(SCAN_STATE_STARTED, scan_state_);
if (folders_to_scan_.empty()) {
scan_state_ = SCAN_STATE_FINISHED;
results_callback_.Run(true /* success? */, results_);
return;
}
DCHECK(token_.IsValid());
DCHECK(!filter_callback_.is_null());
base::FilePath folder_to_scan = folders_to_scan_.top();
folders_to_scan_.pop();
MediaGalleryScanResult* scan_result = new MediaGalleryScanResult();
std::vector<base::FilePath>* new_folders = new std::vector<base::FilePath>();
scoped_refptr<base::SequencedTaskRunner> task_runner =
BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(token_);
task_runner->PostTaskAndReply(
FROM_HERE,
base::Bind(&ScanFolderOnBlockingPool,
folder_to_scan,
filter_callback_,
base::Unretained(scan_result),
base::Unretained(new_folders)),
base::Bind(&MediaFolderFinder::GotScanResults,
weak_factory_.GetWeakPtr(),
folder_to_scan,
base::Owned(scan_result),
base::Owned(new_folders)));
}
void MediaFolderFinder::GotScanResults(
const base::FilePath& path,
const MediaGalleryScanResult* scan_result,
const std::vector<base::FilePath>* new_folders) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK_EQ(SCAN_STATE_STARTED, scan_state_);
DCHECK(!path.empty());
DCHECK(scan_result);
DCHECK(new_folders);
CHECK(!ContainsKey(results_, path));
if (!IsEmptyScanResult(*scan_result))
results_[path] = *scan_result;
// Push new folders to the |folders_to_scan_| stack in reverse order.
for (size_t i = new_folders->size(); i > 0; --i) {
const base::FilePath& path_to_add = (*new_folders)[i - 1];
folders_to_scan_.push(path_to_add);
}
ScanFolder();
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_MEDIA_GALLERIES_MEDIA_FOLDER_FINDER_H_
#define CHROME_BROWSER_MEDIA_GALLERIES_MEDIA_FOLDER_FINDER_H_
#include <map>
#include <stack>
#include <vector>
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/media_galleries/media_scan_types.h"
// MediaFolderFinder scans local hard drives and look for folders that contain
// media files.
class MediaFolderFinder {
public:
typedef std::map<base::FilePath, MediaGalleryScanResult>
MediaFolderFinderResults;
typedef base::Callback<void(bool /*success*/,
const MediaFolderFinderResults& /*results*/)>
MediaFolderFinderResultsCallback;
typedef base::Callback<MediaGalleryScanFileType(const base::FilePath&)>
FilterCallback;
// Set up a scan with a given set of |roots| as starting points.
// The elements of |roots| should not overlap and should be absolute.
// |callback| will get called when the scan finishes. If the object is deleted
// before it finishes, the scan will stop and |callback| will get called with
// success = false.
MediaFolderFinder(const std::vector<base::FilePath>& roots,
const MediaFolderFinderResultsCallback& callback);
~MediaFolderFinder();
// Start the scan.
void StartScan();
private:
enum ScanState {
SCAN_STATE_NOT_STARTED,
SCAN_STATE_STARTED,
SCAN_STATE_FINISHED,
};
// Scan a folder from |folders_to_scan_|.
void ScanFolder();
// Callback that returns the |scan_result| for |path| and the |new_folders|
// to scan in future calls to ScanFolder().
void GotScanResults(const base::FilePath& path,
const MediaGalleryScanResult* scan_result,
const std::vector<base::FilePath>* new_folders);
const MediaFolderFinderResultsCallback results_callback_;
MediaFolderFinderResults results_;
std::stack<base::FilePath> folders_to_scan_;
ScanState scan_state_;
// Token to make sure all calls with |filter_callback_| are on the same
// sequence.
base::SequencedWorkerPool::SequenceToken token_;
// Callback used to filter through files and make sure they are media files.
FilterCallback filter_callback_;
base::WeakPtrFactory<MediaFolderFinder> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MediaFolderFinder);
};
#endif // CHROME_BROWSER_MEDIA_GALLERIES_MEDIA_FOLDER_FINDER_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/media_galleries/media_folder_finder.h"
#include <set>
#include <string>
#include "base/bind.h"
#include "base/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/media_galleries/media_scan_types.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread_bundle.h"
class MediaFolderFinderTest : public testing::Test {
public:
MediaFolderFinderTest() {
}
virtual ~MediaFolderFinderTest() {
}
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(fake_dir_.CreateUniqueTempDir());
}
virtual void TearDown() OVERRIDE {
ASSERT_EQ(NULL, media_folder_finder_.get());
}
protected:
void CreateMediaFolderFinder(
const std::vector<base::FilePath> roots,
bool expected_success,
const MediaFolderFinder::MediaFolderFinderResults& expected_results) {
EXPECT_EQ(NULL, media_folder_finder_.get());
received_results_ = false;
expected_success_ = expected_success;
expected_results_ = expected_results;
media_folder_finder_.reset(
new MediaFolderFinder(roots,
base::Bind(&MediaFolderFinderTest::OnGotResults,
base::Unretained(this))));
}
void StartScan() {
media_folder_finder_->StartScan();
}
void DeleteMediaFolderFinder() {
EXPECT_TRUE(media_folder_finder_.get() != NULL);
media_folder_finder_.reset();
}
bool received_results() const {
return received_results_;
}
const base::FilePath& fake_dir() {
return fake_dir_.path();
}
void CreateTestDir(const base::FilePath& parent_dir) {
ASSERT_TRUE(fake_dir().IsParent(parent_dir));
ASSERT_TRUE(base::CreateDirectory(parent_dir));
}
void CreateTestFile(const base::FilePath& parent_dir,
MediaGalleryScanFileType type,
size_t count,
bool big,
MediaFolderFinder::MediaFolderFinderResults* results) {
CreateTestDir(parent_dir);
std::string extension;
size_t filesize;
MediaGalleryScanResult& result = (*results)[parent_dir];
switch (type) {
case MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE:
extension = "jpg";
filesize = 10;
result.image_count += count;
break;
case MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO:
extension = "wav";
filesize = 20;
result.audio_count += count;
break;
case MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO:
extension = "avi";
filesize = 30;
result.video_count += count;
break;
case MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN:
extension = "txt";
filesize = 10;
if (IsEmptyScanResult(result))
results->erase(parent_dir);
break;
default:
NOTREACHED();
return;
}
if (big)
filesize *= 100000;
for (size_t i = 0; i < count; ++i) {
base::FilePath test_file(parent_dir.AppendASCII("dummy." + extension));
int uniquifier =
file_util::GetUniquePathNumber(test_file,
base::FilePath::StringType());
if (uniquifier > 0) {
test_file = test_file.InsertBeforeExtensionASCII(
base::StringPrintf(" (%d)", uniquifier));
filesize += uniquifier;
}
std::string dummy_data;
dummy_data.resize(filesize);
int bytes_written =
file_util::WriteFile(test_file, dummy_data.c_str(), filesize);
ASSERT_GE(bytes_written, 0);
ASSERT_EQ(filesize, static_cast<size_t>(bytes_written));
}
}
void RunLoop() {
base::RunLoop().RunUntilIdle();
content::BrowserThread::GetBlockingPool()->FlushForTesting();
}
void RunLoopUntilReceivedCallback() {
while (!received_results())
RunLoop();
}
private:
void OnGotResults(
bool success,
const MediaFolderFinder::MediaFolderFinderResults& results) {
received_results_ = true;
EXPECT_EQ(expected_success_, success);
std::set<base::FilePath> expected_keys =
GetKeysFromResults(expected_results_);
ASSERT_EQ(expected_keys, GetKeysFromResults(results));
for (MediaFolderFinder::MediaFolderFinderResults::const_iterator it =
results.begin();
it != results.end(); ++it) {
const base::FilePath& folder = it->first;
const MediaGalleryScanResult& expected = it->second;
const MediaGalleryScanResult& actual = results.find(folder)->second;
EXPECT_EQ(expected.image_count, actual.image_count)
<< " Image count for " << folder.value();
EXPECT_EQ(expected.audio_count, actual.audio_count)
<< " Audio count for " << folder.value();
EXPECT_EQ(expected.video_count, actual.video_count)
<< " Video count for " << folder.value();
}
}
std::set<base::FilePath> GetKeysFromResults(
const MediaFolderFinder::MediaFolderFinderResults& results) {
std::set<base::FilePath> keys;
for (MediaFolderFinder::MediaFolderFinderResults::const_iterator it =
results.begin();
it != results.end(); ++it) {
keys.insert(it->first);
}
return keys;
}
content::TestBrowserThreadBundle thread_bundle_;
base::ScopedTempDir fake_dir_;
scoped_ptr<MediaFolderFinder> media_folder_finder_;
bool expected_success_;
MediaFolderFinder::MediaFolderFinderResults expected_results_;
bool received_results_;
DISALLOW_COPY_AND_ASSIGN(MediaFolderFinderTest);
};
TEST_F(MediaFolderFinderTest, NoScan) {
MediaFolderFinder::MediaFolderFinderResults expected_results;
std::vector<base::FilePath> folders;
folders.push_back(fake_dir());
CreateMediaFolderFinder(folders, false, expected_results);
DeleteMediaFolderFinder();
EXPECT_TRUE(received_results());
}
TEST_F(MediaFolderFinderTest, ScanAndCancel) {
MediaFolderFinder::MediaFolderFinderResults expected_results;
std::vector<base::FilePath> folders;
folders.push_back(fake_dir());
CreateMediaFolderFinder(folders, false, expected_results);
StartScan();
RunLoop();
DeleteMediaFolderFinder();
EXPECT_TRUE(received_results());
}
TEST_F(MediaFolderFinderTest, ScanNothing) {
MediaFolderFinder::MediaFolderFinderResults expected_results;
std::vector<base::FilePath> folders;
CreateMediaFolderFinder(folders, true, expected_results);
StartScan();
RunLoopUntilReceivedCallback();
DeleteMediaFolderFinder();
}
TEST_F(MediaFolderFinderTest, EmptyScan) {
MediaFolderFinder::MediaFolderFinderResults expected_results;
std::vector<base::FilePath> folders;
folders.push_back(fake_dir());
CreateMediaFolderFinder(folders, true, expected_results);
StartScan();
RunLoopUntilReceivedCallback();
DeleteMediaFolderFinder();
}
TEST_F(MediaFolderFinderTest, ScanMediaFiles) {
MediaFolderFinder::MediaFolderFinderResults expected_results;
std::vector<base::FilePath> folders;
folders.push_back(fake_dir());
base::FilePath dir1 = fake_dir().AppendASCII("dir1");
base::FilePath dir2 = fake_dir().AppendASCII("dir2");
base::FilePath dir2_3 = dir2.AppendASCII("dir2_3");
base::FilePath dir2_4 = dir2.AppendASCII("dir2_4");
base::FilePath dir2_4_5 = dir2_4.AppendASCII("dir2_4_5");
base::FilePath dir2_4_empty = dir2_4.AppendASCII("dir2_4_empty");
base::FilePath dir_empty = fake_dir().AppendASCII("dir_empty");
CreateTestFile(dir1, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 2, true,
&expected_results);
CreateTestFile(dir1, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 1, false,
&expected_results);
CreateTestFile(dir1, MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN, 1, false,
&expected_results);
CreateTestFile(dir2_3, MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO, 4, true,
&expected_results);
CreateTestFile(dir2_3, MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO, 3, false,
&expected_results);
CreateTestFile(dir2_4, MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN, 5, false,
&expected_results);
CreateTestFile(dir2_4_5, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 2, true,
&expected_results);
CreateTestFile(dir2_4_5, MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO, 4, true,
&expected_results);
CreateTestFile(dir2_4_5, MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO, 1, true,
&expected_results);
CreateTestFile(dir2_4_5, MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE, 5, false,
&expected_results);
CreateTestFile(dir2_4_5, MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO, 3, false,
&expected_results);
CreateTestFile(dir2_4_5, MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN, 3, true,
&expected_results);
CreateTestDir(dir2_4_empty);
CreateTestDir(dir_empty);
CreateMediaFolderFinder(folders, true, expected_results);
StartScan();
RunLoopUntilReceivedCallback();
DeleteMediaFolderFinder();
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/media_galleries/media_scan_types.h"
bool IsEmptyScanResult(const MediaGalleryScanResult& scan_result) {
return (scan_result.image_count == 0 &&
scan_result.audio_count == 0 &&
scan_result.video_count == 0);
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_MEDIA_GALLERIES_MEDIA_SCAN_TYPES_H_
#define CHROME_BROWSER_MEDIA_GALLERIES_MEDIA_SCAN_TYPES_H_
struct MediaGalleryScanResult {
int image_count;
int audio_count;
int video_count;
};
enum MediaGalleryScanFileType {
MEDIA_GALLERY_SCAN_FILE_TYPE_UNKNOWN = 0,
MEDIA_GALLERY_SCAN_FILE_TYPE_IMAGE = 1 << 0,
MEDIA_GALLERY_SCAN_FILE_TYPE_AUDIO = 1 << 1,
MEDIA_GALLERY_SCAN_FILE_TYPE_VIDEO = 1 << 2,
};
bool IsEmptyScanResult(const MediaGalleryScanResult& scan_result);
#endif // CHROME_BROWSER_MEDIA_GALLERIES_MEDIA_SCAN_TYPES_H_
......@@ -1157,6 +1157,8 @@
'browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm',
'browser/media_galleries/media_file_system_registry.cc',
'browser/media_galleries/media_file_system_registry.h',
'browser/media_galleries/media_folder_finder.cc',
'browser/media_galleries/media_folder_finder.h',
'browser/media_galleries/media_galleries_dialog_controller.cc',
'browser/media_galleries/media_galleries_dialog_controller.h',
'browser/media_galleries/media_galleries_histograms.cc',
......@@ -1172,6 +1174,8 @@
'browser/media_galleries/media_scan_manager.cc',
'browser/media_galleries/media_scan_manager.h',
'browser/media_galleries/media_scan_manager_observer.h',
'browser/media_galleries/media_scan_types.cc',
'browser/media_galleries/media_scan_types.h',
'browser/media_galleries/win/mtp_device_delegate_impl_win.cc',
'browser/media_galleries/win/mtp_device_delegate_impl_win.h',
'browser/media_galleries/win/mtp_device_object_entry.cc',
......
......@@ -1033,6 +1033,7 @@
'browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm',
'browser/media_galleries/win/mtp_device_delegate_impl_win_unittest.cc',
'browser/media_galleries/media_file_system_registry_unittest.cc',
'browser/media_galleries/media_folder_finder_unittest.cc',
'browser/media_galleries/media_galleries_dialog_controller_mock.cc',
'browser/media_galleries/media_galleries_dialog_controller_mock.h',
'browser/media_galleries/media_galleries_dialog_controller_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment