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

Unified Diff: chrome/browser/extensions/api/downloads/downloads_api.cc

Issue 16924017: A few minor changes to the chrome.downloads extension API (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: @r211135 Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/api/downloads/downloads_api.cc
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index b831d52d88f5323f54b336e07b2496bdea7c990a..b8a8ad3bb4d8ac15e2f18051e7d31b53f1c53a82 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -14,6 +14,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/json/json_writer.h"
#include "base/lazy_instance.h"
@@ -29,9 +30,11 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_danger_prompt.h"
#include "chrome/browser/download/download_file_icon_extractor.h"
+#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/download/download_query.h"
#include "chrome/browser/download/download_service.h"
#include "chrome/browser/download/download_service_factory.h"
+#include "chrome/browser/download/download_shelf.h"
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/extensions/event_names.h"
#include "chrome/browser/extensions/event_router.h"
@@ -42,8 +45,10 @@
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/icon_loader.h"
#include "chrome/browser/icon_manager.h"
+#include "chrome/browser/platform_util.h"
#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/cancelable_task_tracker.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/api/downloads.h"
@@ -77,16 +82,18 @@ using content::DownloadManager;
namespace download_extension_errors {
// Error messages
-const char kGenericError[] = "I'm afraid I can't do that";
const char kIconNotFoundError[] = "Icon not found";
const char kInvalidDangerTypeError[] = "Invalid danger type";
const char kInvalidFilenameError[] = "Invalid filename";
const char kInvalidFilterError[] = "Invalid query filter";
+const char kInvalidHeaderError[] = "Invalid request header";
const char kInvalidOperationError[] = "Invalid operation";
const char kInvalidOrderByError[] = "Invalid orderBy field";
const char kInvalidQueryLimit[] = "Invalid query limit";
const char kInvalidStateError[] = "Invalid state";
const char kInvalidURLError[] = "Invalid URL";
+const char kNotPermittedURLError[] = "In order to access that URL, this "
+ "extension must add the host to \"permissions\" in manifest.json";
const char kNotImplementedError[] = "NotImplemented";
const char kTooManyListenersError[] = "Each extension may have at most one "
"onDeterminingFilename listener between all of its renderer execution "
@@ -101,19 +108,20 @@ const int kDefaultIconSize = 32;
// Parameter keys
const char kBytesReceivedKey[] = "bytesReceived";
-const char kDangerAcceptedKey[] = "dangerAccepted";
+const char kCanResumeKey[] = "canResume";
+const char kDangerAccepted[] = "accepted";
const char kDangerContent[] = "content";
const char kDangerFile[] = "file";
+const char kDangerHost[] = "host";
const char kDangerKey[] = "danger";
const char kDangerSafe[] = "safe";
const char kDangerUncommon[] = "uncommon";
-const char kDangerAccepted[] = "accepted";
-const char kDangerHost[] = "host";
const char kDangerUrl[] = "url";
const char kEndTimeKey[] = "endTime";
const char kEndedAfterKey[] = "endedAfter";
const char kEndedBeforeKey[] = "endedBefore";
const char kErrorKey[] = "error";
+const char kEstimatedEndTimeKey[] = "estimatedEndTime";
const char kExistsKey[] = "exists";
const char kFileSizeKey[] = "fileSize";
const char kFilenameKey[] = "filename";
@@ -123,6 +131,7 @@ const char kIncognito[] = "incognito";
const char kMimeKey[] = "mime";
const char kPausedKey[] = "paused";
const char kQueryKey[] = "query";
+const char kReferrerUrlKey[] = "referrer";
const char kStartTimeKey[] = "startTime";
const char kStartedAfterKey[] = "startedAfter";
const char kStartedBeforeKey[] = "startedBefore";
@@ -215,15 +224,14 @@ scoped_ptr<base::DictionaryValue> DownloadItemToJSON(
json->SetInteger(kIdKey, download_item->GetId());
const GURL& url = download_item->GetOriginalUrl();
json->SetString(kUrlKey, (url.is_valid() ? url.spec() : std::string()));
+ const GURL& referrer = download_item->GetReferrerUrl();
+ json->SetString(kReferrerUrlKey, (referrer.is_valid() ? referrer.spec()
+ : std::string()));
json->SetString(kFilenameKey,
download_item->GetTargetFilePath().LossyDisplayName());
json->SetString(kDangerKey, DangerString(download_item->GetDangerType()));
- if (download_item->GetDangerType() !=
- content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS)
- json->SetBoolean(kDangerAcceptedKey,
- download_item->GetDangerType() ==
- content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED);
json->SetString(kStateKey, StateString(download_item->GetState()));
+ json->SetBoolean(kCanResumeKey, download_item->CanResume());
json->SetBoolean(kPausedKey, download_item->IsPaused());
json->SetString(kMimeKey, download_item->GetMimeType());
json->SetString(kStartTimeKey, TimeToISO8601(download_item->GetStartTime()));
@@ -231,14 +239,19 @@ scoped_ptr<base::DictionaryValue> DownloadItemToJSON(
json->SetInteger(kTotalBytesKey, download_item->GetTotalBytes());
json->SetBoolean(kIncognito, incognito);
if (download_item->GetState() == DownloadItem::INTERRUPTED) {
- json->SetInteger(kErrorKey, static_cast<int>(
+ json->SetString(kErrorKey, content::InterruptReasonDebugString(
download_item->GetLastReason()));
} else if (download_item->GetState() == DownloadItem::CANCELLED) {
- json->SetInteger(kErrorKey, static_cast<int>(
+ json->SetString(kErrorKey, content::InterruptReasonDebugString(
content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED));
}
if (!download_item->GetEndTime().is_null())
json->SetString(kEndTimeKey, TimeToISO8601(download_item->GetEndTime()));
+ base::TimeDelta time_remaining;
+ if (download_item->TimeRemaining(&time_remaining)) {
+ base::Time now = base::Time::Now();
+ json->SetString(kEstimatedEndTimeKey, TimeToISO8601(now + time_remaining));
+ }
// TODO(benjhayden): Implement fileSize.
json->SetInteger(kFileSizeKey, download_item->GetTotalBytes());
return scoped_ptr<base::DictionaryValue>(json);
@@ -299,7 +312,6 @@ typedef base::hash_map<std::string, DownloadQuery::FilterType> FilterTypeMap;
void InitFilterTypeMap(FilterTypeMap& filter_types) {
filter_types[kBytesReceivedKey] = DownloadQuery::FILTER_BYTES_RECEIVED;
- filter_types[kDangerAcceptedKey] = DownloadQuery::FILTER_DANGER_ACCEPTED;
filter_types[kExistsKey] = DownloadQuery::FILTER_EXISTS;
filter_types[kFilenameKey] = DownloadQuery::FILTER_FILENAME;
filter_types[kFilenameRegexKey] = DownloadQuery::FILTER_FILENAME_REGEX;
@@ -325,7 +337,6 @@ typedef base::hash_map<std::string, DownloadQuery::SortType> SortTypeMap;
void InitSortTypeMap(SortTypeMap& sorter_types) {
sorter_types[kBytesReceivedKey] = DownloadQuery::SORT_BYTES_RECEIVED;
sorter_types[kDangerKey] = DownloadQuery::SORT_DANGER;
- sorter_types[kDangerAcceptedKey] = DownloadQuery::SORT_DANGER_ACCEPTED;
sorter_types[kEndTimeKey] = DownloadQuery::SORT_END_TIME;
sorter_types[kExistsKey] = DownloadQuery::SORT_EXISTS;
sorter_types[kFilenameKey] = DownloadQuery::SORT_FILENAME;
@@ -394,6 +405,8 @@ enum DownloadsFunctionName {
DOWNLOADS_FUNCTION_DRAG = 9,
DOWNLOADS_FUNCTION_GET_FILE_ICON = 10,
DOWNLOADS_FUNCTION_OPEN = 11,
+ DOWNLOADS_FUNCTION_DELETE_FILE = 12,
+ DOWNLOADS_FUNCTION_SET_SHELF_VISIBLE = 13,
// Insert new values here, not at the beginning.
DOWNLOADS_FUNCTION_LAST
};
@@ -405,7 +418,9 @@ void RecordApiFunctions(DownloadsFunctionName function) {
}
void CompileDownloadQueryOrderBy(
- const std::string& order_by_str, std::string* error, DownloadQuery* query) {
+ const std::vector<std::string>& order_by_strs,
+ std::string* error,
+ DownloadQuery* query) {
// TODO(benjhayden): Consider switching from LazyInstance to explicit string
// comparisons.
static base::LazyInstance<SortTypeMap> sorter_types =
@@ -413,8 +428,6 @@ void CompileDownloadQueryOrderBy(
if (sorter_types.Get().size() == 0)
InitSortTypeMap(sorter_types.Get());
- std::vector<std::string> order_by_strs;
- base::SplitString(order_by_str, ' ', &order_by_strs);
for (std::vector<std::string>::const_iterator iter = order_by_strs.begin();
iter != order_by_strs.end(); ++iter) {
std::string term_str = *iter;
@@ -450,13 +463,18 @@ void RunDownloadQuery(
DownloadQuery query_out;
+ size_t limit = 1000;
if (query_in.limit.get()) {
if (*query_in.limit.get() < 0) {
*error = download_extension_errors::kInvalidQueryLimit;
return;
}
- query_out.Limit(*query_in.limit.get());
+ limit = *query_in.limit.get();
}
+ if (limit > 0) {
+ query_out.Limit(limit);
+ }
+
std::string state_string =
extensions::api::downloads::ToString(query_in.state);
if (!state_string.empty()) {
@@ -513,6 +531,21 @@ void RunDownloadQuery(
query_out.Search(all_items.begin(), all_items.end(), results);
}
+DownloadPathReservationTracker::FilenameConflictAction ConvertConflictAction(
+ extensions::api::downloads::FilenameConflictAction action) {
+ switch (action) {
+ case extensions::api::downloads::FILENAME_CONFLICT_ACTION_NONE:
+ case extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY:
+ return DownloadPathReservationTracker::UNIQUIFY;
+ case extensions::api::downloads::FILENAME_CONFLICT_ACTION_OVERWRITE:
+ return DownloadPathReservationTracker::OVERWRITE;
+ case extensions::api::downloads::FILENAME_CONFLICT_ACTION_PROMPT:
+ return DownloadPathReservationTracker::PROMPT;
+ }
+ NOTREACHED();
+ return DownloadPathReservationTracker::UNIQUIFY;
+}
+
class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data {
public:
static ExtensionDownloadsEventRouterData* Get(DownloadItem* download_item) {
@@ -531,6 +564,8 @@ class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data {
: updated_(0),
changed_fired_(0),
json_(json_item.Pass()),
+ creator_conflict_action_(
+ extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY),
determined_conflict_action_(
extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY) {
download_item->SetUserData(kKey, this);
@@ -556,6 +591,10 @@ class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data {
const ExtensionDownloadsEventRouter::FilenameChangedCallback& change) {
filename_no_change_ = no_change;
filename_change_ = change;
+ determined_filename_ = creator_suggested_filename_;
+ determined_conflict_action_ = creator_conflict_action_;
+ // determiner_.install_time should default to 0 so that creator suggestions
+ // should be lower priority than any actual onDeterminingFilename listeners.
}
void ClearPendingDeterminers() {
@@ -603,6 +642,28 @@ class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data {
return false;
}
+ void CreatorSuggestedFilename(
+ const base::FilePath& filename,
+ extensions::api::downloads::FilenameConflictAction conflict_action) {
+ creator_suggested_filename_ = filename;
+ creator_conflict_action_ = conflict_action;
+ }
+
+ base::FilePath creator_suggested_filename() const {
+ return creator_suggested_filename_;
+ }
+
+ extensions::api::downloads::FilenameConflictAction
+ creator_conflict_action() const {
+ return creator_conflict_action_;
+ }
+
+ void ResetCreatorSuggestion() {
+ creator_suggested_filename_.clear();
+ creator_conflict_action_ =
+ extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY;
+ }
+
// Returns false if this |extension_id| was not expected or if this
// |extension_id| has already reported. The caller is responsible for
// validating |filename|.
@@ -664,15 +725,8 @@ class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data {
filename_no_change_.Run();
} else {
if (!filename_change_.is_null()) {
- DownloadPathReservationTracker::FilenameConflictAction conflict_action =
- DownloadPathReservationTracker::UNIQUIFY;
- if (determined_conflict_action_ ==
- extensions::api::downloads::FILENAME_CONFLICT_ACTION_OVERWRITE)
- conflict_action = DownloadPathReservationTracker::OVERWRITE;
- if (determined_conflict_action_ ==
- extensions::api::downloads::FILENAME_CONFLICT_ACTION_PROMPT)
- conflict_action = DownloadPathReservationTracker::PROMPT;
- filename_change_.Run(determined_filename_, conflict_action);
+ filename_change_.Run(determined_filename_, ConvertConflictAction(
+ determined_conflict_action_));
}
}
// Don't clear determiners_ immediately in case there's a second listener
@@ -698,6 +752,9 @@ class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data {
DeterminerInfoVector determiners_;
+ base::FilePath creator_suggested_filename_;
+ extensions::api::downloads::FilenameConflictAction
+ creator_conflict_action_;
base::FilePath determined_filename_;
extensions::api::downloads::FilenameConflictAction
determined_conflict_action_;
@@ -807,13 +864,15 @@ bool DownloadsDownloadFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(params.get());
const extensions::api::downloads::DownloadOptions& options = params->options;
GURL download_url(options.url);
- if (!download_url.is_valid() ||
- (!download_url.SchemeIs("data") &&
- download_url.GetOrigin() != GetExtension()->url().GetOrigin() &&
- !extensions::PermissionsData::HasHostPermission(GetExtension(),
- download_url))) {
+ if (!download_url.is_valid()) {
error_ = download_extension_errors::kInvalidURLError;
return false;
+ } else if (!download_url.SchemeIs("data") &&
+ download_url.GetOrigin() != GetExtension()->url().GetOrigin() &&
+ !extensions::PermissionsData::HasHostPermission(GetExtension(),
+ download_url)) {
+ error_ = download_extension_errors::kNotPermittedURLError;
+ return false;
}
Profile* current_profile = profile();
@@ -827,28 +886,24 @@ bool DownloadsDownloadFunction::RunImpl() {
render_view_host()->GetRoutingID(),
current_profile->GetResourceContext()));
+ base::FilePath creator_suggested_filename;
if (options.filename.get()) {
- // TODO(benjhayden): Make json_schema_compiler generate string16s instead of
- // std::strings. Can't get filename16 from options.ToValue() because that
- // converts it from std::string.
+#if defined(OS_WIN)
+ // Can't get filename16 from options.ToValue() because that converts it from
+ // std::string.
base::DictionaryValue* options_value = NULL;
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &options_value));
- string16 filename16;
+ base::string16 filename16;
EXTENSION_FUNCTION_VALIDATE(options_value->GetString(
kFilenameKey, &filename16));
-#if defined(OS_WIN)
- base::FilePath file_path(filename16);
+ creator_suggested_filename = base::FilePath(filename16);
#elif defined(OS_POSIX)
- base::FilePath file_path(*options.filename.get());
+ creator_suggested_filename = base::FilePath(*options.filename.get());
#endif
- if (!net::IsSafePortableBasename(file_path) ||
- (file_path.DirName().value() != base::FilePath::kCurrentDirectory)) {
+ if (!net::IsSafePortableRelativePath(creator_suggested_filename)) {
error_ = download_extension_errors::kInvalidFilenameError;
return false;
}
- // TODO(benjhayden) Ensure that this filename is interpreted as a path
- // relative to the default downloads directory without allowing '..'.
- download_params->set_suggested_name(filename16);
}
if (options.save_as.get())
@@ -862,7 +917,7 @@ bool DownloadsDownloadFunction::RunImpl() {
++iter) {
const HeaderNameValuePair& name_value = **iter;
if (!net::HttpUtil::IsSafeHeader(name_value.name)) {
- error_ = download_extension_errors::kGenericError;
+ error_ = download_extension_errors::kInvalidHeaderError;
return false;
}
download_params->add_request_header(name_value.name, name_value.value);
@@ -876,7 +931,8 @@ bool DownloadsDownloadFunction::RunImpl() {
if (options.body.get())
download_params->set_post_body(*options.body.get());
download_params->set_callback(base::Bind(
- &DownloadsDownloadFunction::OnStarted, this));
+ &DownloadsDownloadFunction::OnStarted, this,
+ creator_suggested_filename, options.conflict_action));
// Prevent login prompts for 401/407 responses.
download_params->set_load_flags(net::LOAD_DO_NOT_PROMPT_FOR_LOGIN);
@@ -888,12 +944,26 @@ bool DownloadsDownloadFunction::RunImpl() {
}
void DownloadsDownloadFunction::OnStarted(
- DownloadItem* item, net::Error error) {
+ const base::FilePath& creator_suggested_filename,
+ extensions::api::downloads::FilenameConflictAction creator_conflict_action,
+ DownloadItem* item,
+ net::Error error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
VLOG(1) << __FUNCTION__ << " " << item << " " << error;
if (item) {
DCHECK_EQ(net::OK, error);
SetResult(base::Value::CreateIntegerValue(item->GetId()));
+ if (!creator_suggested_filename.empty()) {
+ ExtensionDownloadsEventRouterData* data =
+ ExtensionDownloadsEventRouterData::Get(item);
+ if (!data) {
+ data = new ExtensionDownloadsEventRouterData(
+ item,
+ scoped_ptr<base::DictionaryValue>(new base::DictionaryValue()));
+ }
+ data->CreatorSuggestedFilename(
+ creator_suggested_filename, creator_conflict_action);
+ }
} else {
DCHECK_NE(net::OK, error);
error_ = net::ErrorToString(error);
@@ -1035,6 +1105,53 @@ bool DownloadsEraseFunction::RunImpl() {
return true;
}
+DownloadsDeleteFileFunction::DownloadsDeleteFileFunction() {}
+
+DownloadsDeleteFileFunction::~DownloadsDeleteFileFunction() {}
+
+bool DownloadsDeleteFileFunction::RunImpl() {
+ scoped_ptr<extensions::api::downloads::DeleteFile::Params> params(
+ extensions::api::downloads::DeleteFile::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+ DownloadItem* download_item = GetDownload(
+ profile(), include_incognito(), params->download_id);
+ if (!download_item ||
+ (download_item->GetState() == DownloadItem::IN_PROGRESS) ||
+ download_item->GetFileExternallyRemoved()) {
+ error_ = download_extension_errors::kInvalidOperationError;
+ return false;
+ }
+
+ RecordApiFunctions(DOWNLOADS_FUNCTION_DELETE_FILE);
+
+ DownloadManager* manager = NULL;
+ DownloadManager* incognito_manager = NULL;
+ GetManagers(profile(), include_incognito(), &manager, &incognito_manager);
+ ManagerDestructionObserver::CheckForHistoryFilesRemoval(manager);
+ ManagerDestructionObserver::CheckForHistoryFilesRemoval(incognito_manager);
+
+ BrowserThread::PostTaskAndReply(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&DownloadsDeleteFileFunction::DeleteOnFileThread, this,
+ download_item->GetFullPath()),
asanka 2013/07/16 19:57:52 I'd avoid deleting files unless the download is CO
benjhayden 2013/07/19 15:53:55 Done.
+ base::Bind(&DownloadsDeleteFileFunction::RespondOnUIThread, this));
+ return true;
+}
+
+void DownloadsDeleteFileFunction::DeleteOnFileThread(
+ const base::FilePath& path) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ if (file_util::DirectoryExists(path)) {
+ error_ = download_extension_errors::kInvalidOperationError;
+ return;
+ }
+ base::Delete(path, false);
+}
+
+void DownloadsDeleteFileFunction::RespondOnUIThread() {
+ SendResponse(error_.empty());
+}
+
DownloadsAcceptDangerFunction::DownloadsAcceptDangerFunction() {}
DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {}
@@ -1061,20 +1178,29 @@ bool DownloadsAcceptDangerFunction::RunImpl() {
web_contents,
true,
base::Bind(&DownloadsAcceptDangerFunction::DangerPromptCallback,
- this, true, params->download_id),
- base::Bind(&DownloadsAcceptDangerFunction::DangerPromptCallback,
- this, false, params->download_id));
+ this, params->download_id));
// DownloadDangerPrompt deletes itself
return true;
}
void DownloadsAcceptDangerFunction::DangerPromptCallback(
- bool accept, int download_id) {
- if (accept) {
- DownloadItem* download_item = GetDownloadIfInProgress(
- profile(), include_incognito(), download_id);
- if (download_item)
+ int download_id, DownloadDangerPrompt::Action action) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DownloadItem* download_item = GetDownloadIfInProgress(
+ profile(), include_incognito(), download_id);
+ if (!download_item) {
+ error_ = download_extension_errors::kInvalidOperationError;
+ return;
+ }
+ switch (action) {
+ case DownloadDangerPrompt::ACCEPT:
download_item->ValidateDangerousDownload();
+ break;
+ case DownloadDangerPrompt::CANCEL:
+ download_item->Remove();
+ break;
+ case DownloadDangerPrompt::DISMISS:
+ break;
}
SendResponse(error_.empty());
}
@@ -1087,13 +1213,21 @@ bool DownloadsShowFunction::RunImpl() {
scoped_ptr<extensions::api::downloads::Show::Params> params(
extensions::api::downloads::Show::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
- DownloadItem* download_item = GetDownload(
- profile(), include_incognito(), params->download_id);
- if (!download_item) {
- error_ = download_extension_errors::kInvalidOperationError;
- return false;
+ if (params->download_id) {
+ DownloadItem* download_item = GetDownload(
+ profile(), include_incognito(), *params->download_id);
+ if (!download_item) {
+ error_ = download_extension_errors::kInvalidOperationError;
+ return false;
+ }
+ download_item->ShowDownloadInShell();
+ } else {
+ DownloadManager* manager = NULL;
+ DownloadManager* incognito_manager = NULL;
+ GetManagers(profile(), include_incognito(), &manager, &incognito_manager);
+ platform_util::OpenItem(DownloadPrefs::FromDownloadManager(
+ manager)->DownloadPath());
}
- download_item->ShowDownloadInShell();
RecordApiFunctions(DOWNLOADS_FUNCTION_SHOW);
return true;
}
@@ -1146,6 +1280,26 @@ bool DownloadsDragFunction::RunImpl() {
return true;
}
+DownloadsSetShelfVisibleFunction::DownloadsSetShelfVisibleFunction() {}
+
+DownloadsSetShelfVisibleFunction::~DownloadsSetShelfVisibleFunction() {}
+
+bool DownloadsSetShelfVisibleFunction::RunImpl() {
+ scoped_ptr<extensions::api::downloads::SetShelfVisible::Params> params(
+ extensions::api::downloads::SetShelfVisible::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+ DownloadShelf* shelf = GetCurrentBrowser()->window()->GetDownloadShelf();
asanka 2013/07/16 19:57:52 Is it expected that this will operate on the forem
benjhayden 2013/07/19 15:53:55 Yep, it will probably primarily be called from bac
asanka 2013/07/23 21:13:48 The browser window for a download is determined by
asargent_no_longer_on_chrome 2013/07/23 21:36:57 Note that chrome can be running but with no curren
+ if (params->visible) {
+ if (!shelf->IsShowing())
+ shelf->Show();
asanka 2013/07/16 19:57:52 What's supposed to happen if there are no download
benjhayden 2013/07/19 15:53:55 Done.
+ } else {
+ if (shelf->IsShowing())
+ shelf->Close(DownloadShelf::USER_ACTION);
+ }
+ RecordApiFunctions(DOWNLOADS_FUNCTION_SET_SHELF_VISIBLE);
+ return true;
+}
+
DownloadsGetFileIconFunction::DownloadsGetFileIconFunction()
: icon_extractor_(new DownloadFileIconExtractorImpl()) {
}
@@ -1268,7 +1422,14 @@ void ExtensionDownloadsEventRouter::OnDeterminingFilename(
json);
if (!any_determiners) {
data->ClearPendingDeterminers();
- no_change.Run();
+ if (!data->creator_suggested_filename().empty()) {
+ change.Run(data->creator_suggested_filename(),
+ ConvertConflictAction(data->creator_conflict_action()));
+ // If all listeners are removed, don't keep |data| around.
+ data->ResetCreatorSuggestion();
+ } else {
+ no_change.Run();
+ }
}
}
@@ -1358,7 +1519,8 @@ void ExtensionDownloadsEventRouter::OnListenerRemoved(
// should proceed.
data->DeterminerRemoved(details.extension_id);
}
- if (!any_listeners) {
+ if (!any_listeners &&
+ data->creator_suggested_filename().empty()) {
ExtensionDownloadsEventRouterData::Remove(*iter);
}
}
@@ -1428,7 +1590,9 @@ void ExtensionDownloadsEventRouter::OnDownloadUpdated(
for (base::DictionaryValue::Iterator iter(*new_json.get());
!iter.IsAtEnd(); iter.Advance()) {
new_fields.insert(iter.key());
- if (iter.key() != kBytesReceivedKey) {
+ if ((iter.key() != kBytesReceivedKey) &&
+ (iter.key() != kIdKey) &&
+ (iter.key() != kEstimatedEndTimeKey)) {
const base::Value* old_value = NULL;
if (!data->json().HasKey(iter.key()) ||
(data->json().Get(iter.key(), &old_value) &&
@@ -1445,7 +1609,9 @@ void ExtensionDownloadsEventRouter::OnDownloadUpdated(
// difference in |delta|.
for (base::DictionaryValue::Iterator iter(data->json());
!iter.IsAtEnd(); iter.Advance()) {
- if (new_fields.find(iter.key()) == new_fields.end()) {
+ if ((new_fields.find(iter.key()) == new_fields.end()) &&
+ (iter.key() != kEstimatedEndTimeKey)) {
asanka 2013/07/16 19:57:52 Why exclude kEstimatedEndTimeKey? It can also disa
benjhayden 2013/07/19 15:53:55 estimatedEndTime is not in DownloadDelta because i
+ // estimatedEndTime disappears after completion, but bytesReceived stays.
delta->Set(iter.key() + ".previous", iter.value().DeepCopy());
changed = true;
}

Powered by Google App Engine
This is Rietveld 408576698