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 4ff5784df9313d8d08910176ad1085fa6adfe77b..43b6b43c4c0a768ec146c099412e1dffffc7f09e 100644 |
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc |
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc |
@@ -190,7 +190,9 @@ bool ValidateFilename(const string16& filename) { |
return true; |
} |
-scoped_ptr<base::DictionaryValue> DownloadItemToJSON(DownloadItem* item) { |
+scoped_ptr<base::DictionaryValue> DownloadItemToJSON( |
+ DownloadItem* item, |
+ bool incognito) { |
base::DictionaryValue* json = new base::DictionaryValue(); |
json->SetInteger(kIdKey, item->GetId()); |
json->SetString(kUrlKey, item->GetOriginalUrl().spec()); |
@@ -206,7 +208,7 @@ scoped_ptr<base::DictionaryValue> DownloadItemToJSON(DownloadItem* item) { |
(item->GetStartTime() - base::Time::UnixEpoch()).InMilliseconds()); |
json->SetInteger(kBytesReceivedKey, item->GetReceivedBytes()); |
json->SetInteger(kTotalBytesKey, item->GetTotalBytes()); |
- json->SetBoolean(kIncognito, item->IsOtr()); |
+ json->SetBoolean(kIncognito, incognito); |
if (item->GetState() == DownloadItem::INTERRUPTED) { |
json->SetInteger(kErrorKey, static_cast<int>(item->GetLastReason())); |
} else if (item->GetState() == DownloadItem::CANCELLED) { |
@@ -318,15 +320,23 @@ bool IsNotTemporaryDownloadFilter(const DownloadItem& item) { |
return !item.IsTemporary(); |
} |
+// Set |manager| to the on-record DownloadManager, and |incognito_manager| to |
+// the off-record DownloadManager if one exists and is requested via |
+// |include_incognito|. This should work regardless of whether |profile| is |
+// original or incognito. |
void GetManagers( |
Profile* profile, |
bool include_incognito, |
- DownloadManager** manager, DownloadManager** incognito_manager) { |
- *manager = BrowserContext::GetDownloadManager(profile); |
- *incognito_manager = NULL; |
- if (include_incognito && profile->HasOffTheRecordProfile()) { |
+ DownloadManager** manager, |
+ DownloadManager** incognito_manager) { |
+ *manager = BrowserContext::GetDownloadManager(profile->GetOriginalProfile()); |
+ if (profile->HasOffTheRecordProfile() && |
+ (include_incognito || |
+ profile->IsOffTheRecord())) { |
*incognito_manager = BrowserContext::GetDownloadManager( |
profile->GetOffTheRecordProfile()); |
+ } else { |
+ *incognito_manager = NULL; |
} |
} |
@@ -396,8 +406,8 @@ void CompileDownloadQueryOrderBy( |
void RunDownloadQuery( |
const extensions::api::downloads::DownloadQuery& query_in, |
- Profile* profile, |
- bool include_incognito, |
+ DownloadManager* manager, |
+ DownloadManager* incognito_manager, |
std::string* error, |
DownloadQuery::DownloadVector* results) { |
// TODO(benjhayden): Consider switching from LazyInstance to explicit string |
@@ -453,9 +463,6 @@ void RunDownloadQuery( |
} |
} |
- DownloadManager* manager = NULL; |
- DownloadManager* incognito_manager = NULL; |
- GetManagers(profile, include_incognito, &manager, &incognito_manager); |
DownloadQuery::DownloadVector all_items; |
if (query_in.id.get()) { |
DownloadItem* item = manager->GetDownload(*query_in.id.get()); |
@@ -472,6 +479,31 @@ void RunDownloadQuery( |
query_out.Search(all_items.begin(), all_items.end(), results); |
} |
+void DispatchEventInternal( |
+ Profile* target_profile, |
+ const char* event_name, |
+ const std::string& json_args, |
+ scoped_ptr<base::ListValue> event_args) { |
+ target_profile->GetExtensionEventRouter()->DispatchEventToRenderers( |
+ event_name, |
+ event_args.Pass(), |
+ target_profile, |
+ GURL(), |
+ extensions::EventFilteringInfo()); |
+ |
+ ExtensionDownloadsEventRouter::DownloadsNotificationSource |
+ notification_source; |
+ notification_source.event_name = event_name; |
+ notification_source.profile = target_profile; |
+ content::Source<ExtensionDownloadsEventRouter::DownloadsNotificationSource> |
+ content_source(¬ification_source); |
+ std::string args_copy(json_args); |
+ content::NotificationService::current()->Notify( |
+ chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT, |
+ content_source, |
+ content::Details<std::string>(&args_copy)); |
+} |
+ |
} // namespace |
DownloadsDownloadFunction::DownloadsDownloadFunction() {} |
@@ -574,16 +606,28 @@ bool DownloadsSearchFunction::RunImpl() { |
scoped_ptr<extensions::api::downloads::Search::Params> params( |
extensions::api::downloads::Search::Params::Create(*args_)); |
EXTENSION_FUNCTION_VALIDATE(params.get()); |
+ DownloadManager* manager = NULL; |
+ DownloadManager* incognito_manager = NULL; |
+ GetManagers(profile(), include_incognito(), &manager, &incognito_manager); |
DownloadQuery::DownloadVector results; |
- RunDownloadQuery(params->query, profile(), include_incognito(), |
- &error_, &results); |
+ RunDownloadQuery(params->query, |
+ manager, |
+ incognito_manager, |
+ &error_, |
+ &results); |
if (!error_.empty()) |
return false; |
+ |
base::ListValue* json_results = new base::ListValue(); |
for (DownloadManager::DownloadVector::const_iterator it = results.begin(); |
it != results.end(); ++it) { |
- scoped_ptr<base::DictionaryValue> item(DownloadItemToJSON(*it)); |
- json_results->Append(item.release()); |
+ DownloadItem* item = *it; |
+ int32 download_id = item->GetId(); |
+ bool off_record = ((incognito_manager != NULL) && |
+ (incognito_manager->GetDownload(download_id) != NULL)); |
+ scoped_ptr<base::DictionaryValue> json_item(DownloadItemToJSON( |
+ *it, off_record)); |
+ json_results->Append(json_item.release()); |
} |
SetResult(json_results); |
RecordApiFunctions(DOWNLOADS_FUNCTION_SEARCH); |
@@ -796,8 +840,6 @@ ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( |
: profile_(profile), |
manager_(manager) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- DCHECK(profile_); |
- DCHECK(manager_); |
manager_->AddObserver(this); |
} |
@@ -851,7 +893,8 @@ void ExtensionDownloadsEventRouter::OnDownloadUpdated(DownloadItem* item) { |
int download_id = item->GetId(); |
base::DictionaryValue* old_json = item_jsons_[download_id]; |
- scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON(item)); |
+ scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON( |
+ item, profile_->IsOffTheRecord())); |
scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue()); |
delta->SetInteger(kIdKey, download_id); |
std::set<std::string> new_fields; |
@@ -905,7 +948,7 @@ void ExtensionDownloadsEventRouter::OnDownloadCreated( |
download_item->AddObserver(this); |
scoped_ptr<base::DictionaryValue> json_item( |
- DownloadItemToJSON(download_item)); |
+ DownloadItemToJSON(download_item, profile_->IsOffTheRecord())); |
DispatchEvent(extensions::event_names::kOnDownloadCreated, |
json_item->DeepCopy()); |
int32 download_id = download_item->GetId(); |
@@ -926,23 +969,27 @@ void ExtensionDownloadsEventRouter::ManagerGoingDown( |
void ExtensionDownloadsEventRouter::DispatchEvent( |
const char* event_name, base::Value* arg) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- scoped_ptr<ListValue> args(new ListValue()); |
+ scoped_ptr<base::ListValue> args(new base::ListValue()); |
args->Append(arg); |
std::string json_args; |
base::JSONWriter::Write(args.get(), &json_args); |
- |
- profile_->GetExtensionEventRouter()->DispatchEventToRenderers( |
- event_name, |
- args.Pass(), |
- profile_, |
- GURL(), |
- extensions::EventFilteringInfo()); |
- |
- DownloadsNotificationSource notification_source; |
- notification_source.event_name = event_name; |
- notification_source.profile = profile_; |
- content::NotificationService::current()->Notify( |
- chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT, |
- content::Source<DownloadsNotificationSource>(¬ification_source), |
- content::Details<std::string>(&json_args)); |
+ // There is a one EDER for each on-record Profile, and a separate EDER for |
+ // each off-record Profile, so there is exactly one EDER for each |
+ // DownloadManager. EDER only watches its own DM, so all the items that an |
+ // EDER sees are either all on-record or all off-record. However, we want |
+ // extensions in off-record contexts to see on-record items. So, if this EDER |
+ // is watching an on-record DM, and there is a corresponding off-record |
+ // Profile, then dispatch this event to both the on-record Profile and the |
+ // off-record Profile. There may or may not be an off-record Profile, so send |
+ // a *copy* of |args| to the off-record Profile, and Pass() |args| |
+ // to the Profile that we know is there. |
+ if (profile_->HasOffTheRecordProfile() && |
+ !profile_->IsOffTheRecord()) { |
+ DispatchEventInternal( |
+ profile_->GetOffTheRecordProfile(), |
+ event_name, |
+ json_args, |
+ scoped_ptr<base::ListValue>(args->DeepCopy())); |
+ } |
+ DispatchEventInternal(profile_, event_name, json_args, args.Pass()); |
} |