diff options
author | asanka@chromium.org <asanka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-09 19:38:02 +0000 |
---|---|---|
committer | asanka@chromium.org <asanka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-09 19:38:02 +0000 |
commit | 45e4fab2ec46c7a3ebe6476f5a6d25f2aaf1e4cf (patch) | |
tree | aae06a3d01902d89c562d4a32a4771302f267c08 /chrome/browser | |
parent | 431b5cd77b2985869e33bf31d7eccd479a2a5372 (diff) | |
download | chromium_src-45e4fab2ec46c7a3ebe6476f5a6d25f2aaf1e4cf.zip chromium_src-45e4fab2ec46c7a3ebe6476f5a6d25f2aaf1e4cf.tar.gz chromium_src-45e4fab2ec46c7a3ebe6476f5a6d25f2aaf1e4cf.tar.bz2 |
Implement chrome.experimental.downloads.getFileIcon().
BUG=12133
TEST=browser_tests --gtest_filter=DownloadExtensionTest.*:DownloadsApiTest.*
Review URL: http://codereview.chromium.org/8519004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@116898 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/download/download_extension_api.cc | 133 | ||||
-rw-r--r-- | chrome/browser/download/download_extension_api.h | 28 | ||||
-rw-r--r-- | chrome/browser/download/download_extension_test.cc | 290 | ||||
-rw-r--r-- | chrome/browser/download/download_file_icon_extractor.h | 33 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_function_dispatcher.cc | 1 |
5 files changed, 475 insertions, 10 deletions
diff --git a/chrome/browser/download/download_extension_api.cc b/chrome/browser/download/download_extension_api.cc index f551c94..7f9effc 100644 --- a/chrome/browser/download/download_extension_api.cc +++ b/chrome/browser/download/download_extension_api.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -22,6 +22,7 @@ #include "base/stringprintf.h" #include "base/values.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/download/download_file_icon_extractor.h" #include "chrome/browser/download/download_service.h" #include "chrome/browser/download/download_service_factory.h" #include "chrome/browser/download/download_util.h" @@ -31,6 +32,7 @@ #include "chrome/browser/icon_manager.h" #include "chrome/browser/renderer_host/chrome_render_message_filter.h" #include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/webui/web_ui_util.h" #include "content/browser/download/download_file_manager.h" #include "content/browser/download/download_id.h" #include "content/browser/download/download_state_info.h" @@ -50,15 +52,19 @@ using content::DownloadManager; namespace download_extension_errors { // Error messages -const char kNotImplementedError[] = "NotImplemented."; const char kGenericError[] = "I'm afraid I can't do that."; -const char kInvalidURLError[] = "Invalid URL."; +const char kIconNotFoundError[] = "Icon not found."; const char kInvalidOperationError[] = "Invalid operation."; +const char kInvalidURLError[] = "Invalid URL."; +const char kNotImplementedError[] = "NotImplemented."; } // namespace download_extension_errors namespace { +// Default icon size for getFileIcon() in pixels. +const int kDefaultIconSize = 32; + // Parameter keys const char kBodyKey[] = "body"; const char kBytesReceivedKey[] = "bytesReceived"; @@ -80,6 +86,7 @@ const char kMethodKey[] = "method"; const char kMimeKey[] = "mime"; const char kPausedKey[] = "paused"; const char kSaveAsKey[] = "saveAs"; +const char kSizeKey[] = "size"; const char kStartTimeKey[] = "startTime"; const char kStateComplete[] = "complete"; const char kStateInProgress[] = "in_progress"; @@ -497,6 +504,126 @@ bool DownloadsDragFunction::RunInternal() { } namespace { + +class DownloadFileIconExtractorImpl : public DownloadFileIconExtractor { + public: + DownloadFileIconExtractorImpl() {} + + ~DownloadFileIconExtractorImpl() {} + + virtual bool ExtractIconURLForPath(const FilePath& path, + IconLoader::IconSize icon_size, + IconURLCallback callback) OVERRIDE; + private: + void OnIconLoadComplete(IconManager::Handle handle, gfx::Image* icon); + + CancelableRequestConsumer cancelable_consumer_; + IconURLCallback callback_; +}; + +bool DownloadFileIconExtractorImpl::ExtractIconURLForPath( + const FilePath& path, + IconLoader::IconSize icon_size, + IconURLCallback callback) { + callback_ = callback; + IconManager* im = g_browser_process->icon_manager(); + // The contents of the file at |path| may have changed since a previous + // request, in which case the associated icon may also have changed. + // Therefore, for the moment we always call LoadIcon instead of attempting + // a LookupIcon. + im->LoadIcon( + path, icon_size, &cancelable_consumer_, + base::Bind(&DownloadFileIconExtractorImpl::OnIconLoadComplete, + base::Unretained(this))); + return true; +} + +void DownloadFileIconExtractorImpl::OnIconLoadComplete( + IconManager::Handle handle, + gfx::Image* icon) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + std::string url; + if (icon) + url = web_ui_util::GetImageDataUrl(*icon); + callback_.Run(url); +} + +IconLoader::IconSize IconLoaderSizeFromPixelSize(int pixel_size) { + switch (pixel_size) { + case 16: return IconLoader::SMALL; + case 32: return IconLoader::NORMAL; + default: + NOTREACHED(); + return IconLoader::NORMAL; + } +} + +} // namespace + +DownloadsGetFileIconFunction::DownloadsGetFileIconFunction() + : AsyncDownloadsFunction(DOWNLOADS_FUNCTION_GET_FILE_ICON), + icon_size_(kDefaultIconSize), + icon_extractor_(new DownloadFileIconExtractorImpl()) { +} + +DownloadsGetFileIconFunction::~DownloadsGetFileIconFunction() {} + +void DownloadsGetFileIconFunction::SetIconExtractorForTesting( + DownloadFileIconExtractor* extractor) { + DCHECK(extractor); + icon_extractor_.reset(extractor); +} + +bool DownloadsGetFileIconFunction::ParseArgs() { + int dl_id = 0; + EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &dl_id)); + + base::DictionaryValue* options = NULL; + EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options)); + if (options->HasKey(kSizeKey)) { + EXTENSION_FUNCTION_VALIDATE(options->GetInteger(kSizeKey, &icon_size_)); + // We only support 16px and 32px icons. This is enforced in + // experimental.downloads.json. + DCHECK(icon_size_ == 16 || icon_size_ == 32); + } + + DownloadManager* download_manager = + DownloadServiceFactory::GetForProfile(profile())->GetDownloadManager(); + DownloadItem* download_item = download_manager->GetDownloadItem(dl_id); + if (download_item == NULL) { + // The DownloadItem is is added to history when the path is determined. If + // the download is not in history, then we don't have a path / final + // filename and no icon. + error_ = download_extension_errors::kInvalidOperationError; + return false; + } + // In-progress downloads return the intermediate filename for GetFullPath() + // which doesn't have the final extension. Therefore we won't be able to + // derive a good file icon for it. So we use GetTargetFilePath() instead. + path_ = download_item->GetTargetFilePath(); + DCHECK(!path_.empty()); + return true; +} + +bool DownloadsGetFileIconFunction::RunInternal() { + DCHECK(!path_.empty()); + DCHECK(icon_extractor_.get()); + EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath( + path_, IconLoaderSizeFromPixelSize(icon_size_), + base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this))); + return true; +} + +void DownloadsGetFileIconFunction::OnIconURLExtracted(const std::string& url) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (url.empty()) + error_ = download_extension_errors::kIconNotFoundError; + else + result_.reset(base::Value::CreateStringValue(url)); + SendResponse(error_.empty()); +} + +namespace { base::DictionaryValue* DownloadItemToJSON(DownloadItem* item) { base::DictionaryValue* json = new base::DictionaryValue(); json->SetInteger(kIdKey, item->GetId()); diff --git a/chrome/browser/download/download_extension_api.h b/chrome/browser/download/download_extension_api.h index 84e7825..dea8e67 100644 --- a/chrome/browser/download/download_extension_api.h +++ b/chrome/browser/download/download_extension_api.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -18,6 +18,7 @@ #include "content/public/browser/download_item.h" #include "content/public/browser/download_manager.h" +class DownloadFileIconExtractor; class ResourceDispatcherHost; namespace content { @@ -31,10 +32,11 @@ class ResourceContext; namespace download_extension_errors { // Errors that can be returned through chrome.extension.lastError.message. -extern const char kNotImplementedError[]; extern const char kGenericError[]; -extern const char kInvalidUrlError[]; +extern const char kIconNotFoundError[]; extern const char kInvalidOperationError[]; +extern const char kInvalidUrlError[]; +extern const char kNotImplementedError[]; } // namespace download_extension_errors @@ -51,6 +53,7 @@ class DownloadsFunctionInterface { DOWNLOADS_FUNCTION_ACCEPT_DANGER = 7, DOWNLOADS_FUNCTION_SHOW = 8, DOWNLOADS_FUNCTION_DRAG = 9, + DOWNLOADS_FUNCTION_GET_FILE_ICON = 10, // Insert new values here, not at the beginning. DOWNLOADS_FUNCTION_LAST }; @@ -267,6 +270,25 @@ class DownloadsDragFunction : public AsyncDownloadsFunction { DISALLOW_COPY_AND_ASSIGN(DownloadsDragFunction); }; +class DownloadsGetFileIconFunction : public AsyncDownloadsFunction { + public: + DownloadsGetFileIconFunction(); + virtual ~DownloadsGetFileIconFunction(); + void SetIconExtractorForTesting(DownloadFileIconExtractor* extractor); + DECLARE_EXTENSION_FUNCTION_NAME("experimental.downloads.getFileIcon"); + + protected: + virtual bool ParseArgs() OVERRIDE; + virtual bool RunInternal() OVERRIDE; + + private: + void OnIconURLExtracted(const std::string& url); + FilePath path_; + int icon_size_; + scoped_ptr<DownloadFileIconExtractor> icon_extractor_; + DISALLOW_COPY_AND_ASSIGN(DownloadsGetFileIconFunction); +}; + class ExtensionDownloadsEventRouter : public content::DownloadManager::Observer { public: diff --git a/chrome/browser/download/download_extension_test.cc b/chrome/browser/download/download_extension_test.cc index 6132e92..ffea074 100644 --- a/chrome/browser/download/download_extension_test.cc +++ b/chrome/browser/download/download_extension_test.cc @@ -1,9 +1,14 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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 <algorithm> + +#include "base/file_util.h" +#include "base/scoped_temp_dir.h" #include "base/stringprintf.h" #include "chrome/browser/download/download_extension_api.h" +#include "chrome/browser/download/download_file_icon_extractor.h" #include "chrome/browser/download/download_service.h" #include "chrome/browser/download/download_service_factory.h" #include "chrome/browser/download/download_test_observer.h" @@ -15,19 +20,26 @@ #include "chrome/common/pref_names.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" +#include "content/browser/download/download_persistent_store_info.h" #include "content/browser/net/url_request_slow_download_job.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/download_manager.h" +#include "net/base/data_url.h" +#include "net/base/net_util.h" +#include "ui/gfx/codec/png_codec.h" +using content::BrowserThread; using content::DownloadItem; using content::DownloadManager; +namespace { + class DownloadExtensionTest : public InProcessBrowserTest { protected: // InProcessBrowserTest virtual void SetUpOnMainThread() OVERRIDE { - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true)); InProcessBrowserTest::SetUpOnMainThread(); ASSERT_TRUE(CreateAndSetDownloadsDirectory(browser())); @@ -46,6 +58,11 @@ class DownloadExtensionTest : public InProcessBrowserTest { scoped_ptr<DownloadTestObserver> observer( CreateDownloadObserver(1, DownloadItem::IN_PROGRESS)); GURL slow_download_url(URLRequestSlowDownloadJob::kUnknownSizeUrl); + DownloadManager* manager = GetDownloadManager(); + + EXPECT_EQ(0, manager->InProgressCount()); + if (manager->InProgressCount() != 0) + return NULL; ui_test_utils::NavigateToURLWithDisposition( browser(), slow_download_url, CURRENT_TAB, @@ -57,7 +74,7 @@ class DownloadExtensionTest : public InProcessBrowserTest { return NULL; DownloadManager::DownloadVector items; - GetDownloadManager()->GetAllDownloads(FilePath(), &items); + manager->GetAllDownloads(FilePath(), &items); DownloadItem* new_item = NULL; for (DownloadManager::DownloadVector::iterator iter = items.begin(); @@ -71,6 +88,16 @@ class DownloadExtensionTest : public InProcessBrowserTest { return new_item; } + void FinishPendingSlowDownloads() { + scoped_ptr<DownloadTestObserver> observer( + CreateDownloadObserver(1, DownloadItem::COMPLETE)); + GURL finish_url(URLRequestSlowDownloadJob::kFinishDownloadUrl); + ui_test_utils::NavigateToURLWithDisposition( + browser(), finish_url, NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + observer->WaitForFinished(); + } + DownloadTestObserver* CreateDownloadObserver( size_t download_count, DownloadItem::DownloadState finished_state) { @@ -81,6 +108,8 @@ class DownloadExtensionTest : public InProcessBrowserTest { bool RunFunction(UIThreadExtensionFunction* function, const std::string& args) { + // extension_function_test_utils::RunFunction() does not take + // ownership of |function|. scoped_refptr<ExtensionFunction> function_owner(function); return extension_function_test_utils::RunFunction( function, args, browser(), extension_function_test_utils::NONE); @@ -92,10 +121,51 @@ class DownloadExtensionTest : public InProcessBrowserTest { function, args, browser(), extension_function_test_utils::NONE); } + base::Value* RunFunctionAndReturnResult(UIThreadExtensionFunction* function, + const std::string& args) { + return extension_function_test_utils::RunFunctionAndReturnResult( + function, args, browser()); + } + + bool RunFunctionAndReturnString(UIThreadExtensionFunction* function, + const std::string& args, + std::string* result_string) { + scoped_ptr<base::Value> result(RunFunctionAndReturnResult(function, args)); + EXPECT_TRUE(result.get()); + return result.get() && result->GetAsString(result_string); + } + std::string DownloadItemIdAsArgList(const DownloadItem* download_item) { return base::StringPrintf("[%d]", download_item->GetId()); } + // Checks if a data URL encoded image is a PNG of a given size. + void ExpectDataURLIsPNGWithSize(const std::string& url, int expected_size) { + std::string mime_type; + std::string charset; + std::string data; + EXPECT_FALSE(url.empty()); + EXPECT_TRUE(net::DataURL::Parse(GURL(url), &mime_type, &charset, &data)); + EXPECT_STREQ("image/png", mime_type.c_str()); + EXPECT_FALSE(data.empty()); + + if (data.empty()) + return; + + int width = -1, height = -1; + std::vector<unsigned char> decoded_data; + EXPECT_TRUE(gfx::PNGCodec::Decode( + reinterpret_cast<const unsigned char*>(data.c_str()), data.length(), + gfx::PNGCodec::FORMAT_RGBA, &decoded_data, + &width, &height)); + EXPECT_EQ(expected_size, width); + EXPECT_EQ(expected_size, height); + } + + const FilePath& downloads_directory() { + return downloads_directory_.path(); + } + private: bool CreateAndSetDownloadsDirectory(Browser* browser) { if (!downloads_directory_.CreateUniqueTempDir()) @@ -109,6 +179,47 @@ class DownloadExtensionTest : public InProcessBrowserTest { ScopedTempDir downloads_directory_; }; +class MockIconExtractorImpl : public DownloadFileIconExtractor { + public: + MockIconExtractorImpl(const FilePath& path, IconLoader::IconSize icon_size, + const std::string& response) + : expected_path_(path), + expected_icon_size_(icon_size), + response_(response) { + } + virtual ~MockIconExtractorImpl() {} + + virtual bool ExtractIconURLForPath(const FilePath& path, + IconLoader::IconSize icon_size, + IconURLCallback callback) OVERRIDE { + EXPECT_STREQ(expected_path_.value().c_str(), path.value().c_str()); + EXPECT_EQ(expected_icon_size_, icon_size); + if (expected_path_ == path && + expected_icon_size_ == icon_size) { + callback_ = callback; + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&MockIconExtractorImpl::RunCallback, + base::Unretained(this))); + return true; + } else { + return false; + } + } + + private: + void RunCallback() { + callback_.Run(response_); + } + + FilePath expected_path_; + IconLoader::IconSize expected_icon_size_; + std::string response_; + IconURLCallback callback_; +}; + +} // namespace + IN_PROC_BROWSER_TEST_F(DownloadExtensionTest, DownloadsApi_PauseResumeCancel) { DownloadItem* download_item = CreateSlowTestDownload(); ASSERT_TRUE(download_item); @@ -164,3 +275,174 @@ IN_PROC_BROWSER_TEST_F(DownloadExtensionTest, DownloadsApi_PauseResumeCancel) { // Calling pause()/resume()/cancel() with invalid download Ids is // tested in the API test (DownloadsApiTest). } + +// Test downloads.getFileIcon() on in-progress, finished, cancelled and deleted +// download items. +IN_PROC_BROWSER_TEST_F(DownloadExtensionTest, DownloadsApi_FileIcon_Active) { + DownloadItem* download_item = CreateSlowTestDownload(); + ASSERT_TRUE(download_item); + + // Get the icon for the in-progress download. This call should succeed even + // if the file type isn't registered. + std::string args = base::StringPrintf("[%d, {}]", download_item->GetId()); + std::string result_string; + EXPECT_TRUE(RunFunctionAndReturnString(new DownloadsGetFileIconFunction(), + args, &result_string)); + + // Note: We are checking if the result is a Data URL that has encoded + // image/png data for an icon of a specific size. Of these, only the icon size + // is specified in the API contract. The image type (image/png) and URL type + // (Data) are implementation details. + + // The default size for icons returned by getFileIcon() is 32x32. + ExpectDataURLIsPNGWithSize(result_string, 32); + + // Test whether the correct path is being pased into the icon extractor. + FilePath expected_path(download_item->GetTargetFilePath()); + scoped_refptr<DownloadsGetFileIconFunction> function( + new DownloadsGetFileIconFunction()); + function->SetIconExtractorForTesting(new MockIconExtractorImpl( + expected_path, IconLoader::NORMAL, "foo")); + EXPECT_TRUE(RunFunctionAndReturnString(function.release(), args, + &result_string)); + + // Now try a 16x16 icon. + args = base::StringPrintf("[%d, {\"size\": 16}]", download_item->GetId()); + EXPECT_TRUE(RunFunctionAndReturnString(new DownloadsGetFileIconFunction(), + args, &result_string)); + ExpectDataURLIsPNGWithSize(result_string, 16); + + // Explicitly asking for 32x32 should give us a 32x32 icon. + args = base::StringPrintf("[%d, {\"size\": 32}]", download_item->GetId()); + EXPECT_TRUE(RunFunctionAndReturnString(new DownloadsGetFileIconFunction(), + args, &result_string)); + ExpectDataURLIsPNGWithSize(result_string, 32); + + // Finish the download and try again. + FinishPendingSlowDownloads(); + EXPECT_EQ(DownloadItem::COMPLETE, download_item->GetState()); + EXPECT_TRUE(RunFunctionAndReturnString(new DownloadsGetFileIconFunction(), + args, &result_string)); + ExpectDataURLIsPNGWithSize(result_string, 32); + + // Check the path passed to the icon extractor post-completion. + function = new DownloadsGetFileIconFunction(); + function->SetIconExtractorForTesting(new MockIconExtractorImpl( + expected_path, IconLoader::NORMAL, "foo")); + EXPECT_TRUE(RunFunctionAndReturnString(function.release(), args, + &result_string)); + + // Now create another download. + download_item = CreateSlowTestDownload(); + ASSERT_TRUE(download_item); + expected_path = download_item->GetTargetFilePath(); + + // Cancel the download. As long as the download has a target path, we should + // be able to query the file icon. + download_item->Cancel(true); + // Let cleanup complete on the FILE thread. + ui_test_utils::RunAllPendingInMessageLoop(BrowserThread::FILE); + args = base::StringPrintf("[%d, {\"size\": 32}]", download_item->GetId()); + EXPECT_TRUE(RunFunctionAndReturnString(new DownloadsGetFileIconFunction(), + args, &result_string)); + ExpectDataURLIsPNGWithSize(result_string, 32); + + // Check the path passed to the icon extractor post-cancellation. + function = new DownloadsGetFileIconFunction(); + function->SetIconExtractorForTesting(new MockIconExtractorImpl( + expected_path, IconLoader::NORMAL, "foo")); + EXPECT_TRUE(RunFunctionAndReturnString(function.release(), args, + &result_string)); + + // Simulate an error during icon load by invoking the mock with an empty + // result string. + function = new DownloadsGetFileIconFunction(); + function->SetIconExtractorForTesting(new MockIconExtractorImpl( + expected_path, IconLoader::NORMAL, "")); + std::string error = RunFunctionAndReturnError(function.release(), args); + EXPECT_STREQ(download_extension_errors::kIconNotFoundError, + error.c_str()); + + // Once the download item is deleted, we should return kInvalidOperationError. + download_item->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD); + error = RunFunctionAndReturnError(new DownloadsGetFileIconFunction(), args); + EXPECT_STREQ(download_extension_errors::kInvalidOperationError, + error.c_str()); + + // Asking for icons of other (invalid) sizes is tested in the API test + // (DownloadsApiTest). +} + +// Test that we can acquire file icons for history downloads regardless of +// whether they exist or not. If the file doesn't exist we should receive a +// generic icon from the OS/toolkit that may or may not be specific to the file +// type. +IN_PROC_BROWSER_TEST_F(DownloadExtensionTest, DownloadsApi_FileIcon_History) { + base::Time current(base::Time::Now()); + FilePath real_path( + downloads_directory().Append(FILE_PATH_LITERAL("real.txt"))); + FilePath fake_path( + downloads_directory().Append(FILE_PATH_LITERAL("fake.txt"))); + DownloadPersistentStoreInfo history_entries[] = { + DownloadPersistentStoreInfo( + real_path, + GURL("http://does.not.exist/foo"), + GURL(), + current, current, // start_time == end_time == current. + 1, 1, // received_bytes == total_bytes == 1. + DownloadItem::COMPLETE, + 1, false), + DownloadPersistentStoreInfo( + fake_path, + GURL("http://does.not.exist/bar"), + GURL(), + current, current, // start_time == end_time == current. + 1, 1, // received_bytes == total_bytes == 1. + DownloadItem::COMPLETE, + 2, false) + }; + std::vector<DownloadPersistentStoreInfo> entries( + history_entries, history_entries + arraysize(history_entries)); + + DownloadManager* manager = GetDownloadManager(); + manager->OnPersistentStoreQueryComplete(&entries); + + EXPECT_EQ(0, file_util::WriteFile(real_path, "", 0)); + ASSERT_TRUE(file_util::PathExists(real_path)); + ASSERT_FALSE(file_util::PathExists(fake_path)); + + DownloadManager::DownloadVector all_downloads; + manager->SearchDownloads(string16(), &all_downloads); + ASSERT_EQ(2u, all_downloads.size()); + if (all_downloads[0]->GetId() > all_downloads[1]->GetId()) + std::swap(all_downloads[0], all_downloads[1]); + EXPECT_EQ(real_path.value(), all_downloads[0]->GetFullPath().value()); + EXPECT_EQ(fake_path.value(), all_downloads[1]->GetFullPath().value()); + + for (DownloadManager::DownloadVector::iterator iter = all_downloads.begin(); + iter != all_downloads.end(); + ++iter) { + std::string args(base::StringPrintf("[%d, {\"size\": 32}]", + (*iter)->GetId())); + std::string result_string; + EXPECT_TRUE(RunFunctionAndReturnString( + new DownloadsGetFileIconFunction(), args, &result_string)); + // Note: We are checking if the result is a Data URL that has encoded + // image/png data for an icon of a specific size. Of these, only the icon + // size is specified in the API contract. The image type (image/png) and URL + // type (Data) are implementation details. + ExpectDataURLIsPNGWithSize(result_string, 32); + + // Use a MockIconExtractorImpl to test if the correct path is being passed + // into the DownloadFileIconExtractor. + scoped_refptr<DownloadsGetFileIconFunction> function( + new DownloadsGetFileIconFunction()); + function->SetIconExtractorForTesting(new MockIconExtractorImpl( + (*iter)->GetFullPath(), IconLoader::NORMAL, "hello")); + EXPECT_TRUE(RunFunctionAndReturnString(function.release(), args, + &result_string)); + EXPECT_STREQ("hello", result_string.c_str()); + } + + // The temporary files should be cleaned up when the ScopedTempDir is removed. +} diff --git a/chrome/browser/download/download_file_icon_extractor.h b/chrome/browser/download/download_file_icon_extractor.h new file mode 100644 index 0000000..6543ae9 --- /dev/null +++ b/chrome/browser/download/download_file_icon_extractor.h @@ -0,0 +1,33 @@ +// Copyright (c) 2012 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_DOWNLOAD_DOWNLOAD_FILE_ICON_EXTRACTOR_H_ +#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FILE_ICON_EXTRACTOR_H_ +#pragma once + +#include <string> + +#include "base/callback.h" +#include "base/file_path.h" +#include "chrome/browser/icon_loader.h" + +// Helper class for DownloadsGetFileIconFunction. Only used for a single icon +// extraction. +class DownloadFileIconExtractor { + public: + // Callback for |ExtractIconForPath|. The parameter is a URL as a string for a + // suitable icon. The string could be empty if the icon could not be + // determined. + typedef base::Callback<void(const std::string&)> IconURLCallback; + + virtual ~DownloadFileIconExtractor() {} + + // Should return false if the request was invalid. If the return value is + // true, then |callback| should be called with the result. + virtual bool ExtractIconURLForPath(const FilePath& path, + IconLoader::IconSize icon_size, + IconURLCallback callback) = 0; +}; + +#endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FILE_ICON_EXTRACTOR_H_ diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index 6d41e2a..e1a122b 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -484,6 +484,7 @@ void FactoryRegistry::ResetFunctions() { RegisterFunction<DownloadsAcceptDangerFunction>(); RegisterFunction<DownloadsShowFunction>(); RegisterFunction<DownloadsDragFunction>(); + RegisterFunction<DownloadsGetFileIconFunction>(); // PageCapture RegisterFunction<PageCaptureSaveAsMHTMLFunction>(); |