Index: chrome/browser/chromeos/extensions/file_manager/event_router.cc |
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc |
index 67efcf35e876b40871467752dfa51f651fa9f51a..f709ef8b1def57b4a4fd812cd631b54a2a25c1ff 100644 |
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc |
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc |
@@ -15,6 +15,7 @@ |
#include "chrome/browser/app_mode/app_mode_utils.h" |
#include "chrome/browser/chrome_notification_types.h" |
#include "chrome/browser/chromeos/drive/drive_integration_service.h" |
+#include "chrome/browser/chromeos/drive/file_change.h" |
#include "chrome/browser/chromeos/drive/file_system_interface.h" |
#include "chrome/browser/chromeos/drive/file_system_util.h" |
#include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h" |
@@ -26,6 +27,7 @@ |
#include "chrome/browser/chromeos/login/ui/login_display_host_impl.h" |
#include "chrome/browser/drive/drive_service_interface.h" |
#include "chrome/browser/extensions/extension_service.h" |
+#include "chrome/browser/extensions/extension_util.h" |
#include "chrome/browser/profiles/profile.h" |
#include "chrome/browser/profiles/profile_manager.h" |
#include "chrome/common/chrome_switches.h" |
@@ -36,6 +38,7 @@ |
#include "content/public/browser/browser_thread.h" |
#include "content/public/browser/notification_source.h" |
#include "content/public/browser/render_process_host.h" |
+#include "content/public/browser/storage_partition.h" |
#include "extensions/browser/event_router.h" |
#include "extensions/browser/extension_host.h" |
#include "extensions/browser/extension_prefs.h" |
@@ -64,6 +67,11 @@ const char kFileTransferStateFailed[] = "failed"; |
// Frequency of sending onFileTransferUpdated. |
const int64 kProgressEventFrequencyInMilliseconds = 1000; |
+// Maximim size of detailed change info on directory change event. If the size |
+// exceeds the maximum size, the detailed info is omitted and the force refresh |
+// is kicked. |
+const size_t kDirectoryChangeEventMaxDetailInfoSize = 1000; |
+ |
// Utility function to check if |job_info| is a file uploading job. |
bool IsUploadJob(drive::JobType type) { |
return (type == drive::TYPE_UPLOAD_NEW_FILE || |
@@ -200,6 +208,18 @@ CopyProgressTypeToCopyProgressStatusType( |
return file_browser_private::COPY_PROGRESS_STATUS_TYPE_NONE; |
} |
+file_browser_private::ChangeType ConvertChangeTypeFromDriveToApi( |
+ drive::FileChange::ChangeType type) { |
+ switch (type) { |
+ case drive::FileChange::ADD_OR_UPDATE: |
+ return file_browser_private::CHANGE_TYPE_ADD_OR_UPDATE; |
+ case drive::FileChange::DELETE: |
+ return file_browser_private::CHANGE_TYPE_DELETE; |
+ } |
+ NOTREACHED(); |
+ return file_browser_private::CHANGE_TYPE_ADD_OR_UPDATE; |
+} |
+ |
std::string FileErrorToErrorName(base::File::Error error_code) { |
namespace js = extensions::api::file_browser_private; |
switch (error_code) { |
@@ -448,7 +468,8 @@ void EventRouter::AddFileWatch(const base::FilePath& local_path, |
watcher->WatchLocalFile( |
watch_path, |
base::Bind(&EventRouter::HandleFileWatchNotification, |
- weak_factory_.GetWeakPtr()), |
+ weak_factory_.GetWeakPtr(), |
+ static_cast<drive::FileChange*>(NULL)), |
callback); |
} |
@@ -630,7 +651,24 @@ void EventRouter::SendDriveFileTransferEvent(bool always) { |
} |
void EventRouter::OnDirectoryChanged(const base::FilePath& drive_path) { |
- HandleFileWatchNotification(drive_path, false); |
+ HandleFileWatchNotification(NULL, drive_path, false); |
+} |
+ |
+void EventRouter::OnFileChanged(const drive::FileChange& changed_files) { |
+ typedef std::map<base::FilePath, drive::FileChange> FileChangeMap; |
+ |
+ FileChangeMap map; |
+ const drive::FileChange::Map& changed_file_map = changed_files.map(); |
+ for (drive::FileChange::Map::const_iterator it = changed_file_map.begin(); |
+ it != changed_file_map.end(); |
+ it++) { |
+ const base::FilePath& path = it->first; |
+ map[path.DirName()].Update(path, it->second); |
+ } |
+ |
+ for (FileChangeMap::const_iterator it = map.begin(); it != map.end(); it++) { |
+ HandleFileWatchNotification(&(it->second), it->first, false); |
+ } |
} |
void EventRouter::OnDriveSyncError(drive::file_system::DriveSyncErrorType type, |
@@ -668,7 +706,8 @@ void EventRouter::OnRefreshTokenInvalid() { |
file_browser_private::OnDriveConnectionStatusChanged::Create()); |
} |
-void EventRouter::HandleFileWatchNotification(const base::FilePath& local_path, |
+void EventRouter::HandleFileWatchNotification(const drive::FileChange* list, |
+ const base::FilePath& local_path, |
bool got_error) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
@@ -676,21 +715,36 @@ void EventRouter::HandleFileWatchNotification(const base::FilePath& local_path, |
if (iter == file_watchers_.end()) { |
return; |
} |
- DispatchDirectoryChangeEvent(iter->second->virtual_path(), got_error, |
+ |
+ if (list && list->size() > kDirectoryChangeEventMaxDetailInfoSize) { |
+ // Removes the detailed information, if the list size is more than |
+ // kDirectoryChangeEventMaxDetailInfoSize, since passing large list |
+ // and processing it may cause more itme. |
+ // This will be invoked full-refresh in Files.app. |
+ list = NULL; |
+ } |
+ |
+ DispatchDirectoryChangeEvent(iter->second->virtual_path(), |
+ list, |
+ got_error, |
iter->second->GetExtensionIds()); |
} |
void EventRouter::DispatchDirectoryChangeEvent( |
const base::FilePath& virtual_path, |
+ const drive::FileChange* list, |
bool got_error, |
const std::vector<std::string>& extension_ids) { |
if (!profile_) { |
NOTREACHED(); |
return; |
} |
+ linked_ptr<drive::FileChange> changes; |
+ if (list) |
+ changes.reset(new drive::FileChange(*list)); // Copy |
for (size_t i = 0; i < extension_ids.size(); ++i) { |
- const std::string& extension_id = extension_ids[i]; |
+ std::string* extension_id = new std::string(extension_ids[i]); |
FileDefinition file_definition; |
file_definition.virtual_path = virtual_path; |
@@ -698,18 +752,24 @@ void EventRouter::DispatchDirectoryChangeEvent( |
file_manager::util::ConvertFileDefinitionToEntryDefinition( |
profile_, |
- extension_id, |
+ *extension_id, |
file_definition, |
base::Bind( |
&EventRouter::DispatchDirectoryChangeEventWithEntryDefinition, |
weak_factory_.GetWeakPtr(), |
+ changes, |
+ base::Owned(extension_id), |
got_error)); |
} |
} |
void EventRouter::DispatchDirectoryChangeEventWithEntryDefinition( |
+ const linked_ptr<drive::FileChange> list, |
+ const std::string* extension_id, |
bool watcher_error, |
const EntryDefinition& entry_definition) { |
+ typedef std::map<base::FilePath, drive::FileChange::ChangeList> ChangeListMap; |
+ |
if (entry_definition.error != base::File::FILE_OK || |
!entry_definition.is_directory) { |
DVLOG(1) << "Unable to dispatch event because resolving the directory " |
@@ -722,6 +782,36 @@ void EventRouter::DispatchDirectoryChangeEventWithEntryDefinition( |
? file_browser_private::FILE_WATCH_EVENT_TYPE_ERROR |
: file_browser_private::FILE_WATCH_EVENT_TYPE_CHANGED; |
+ // Detailed information is available. |
+ if (list.get()) { |
+ event.changed_files.reset( |
+ new std::vector<linked_ptr<file_browser_private::FileChange> >); |
+ |
+ if (list->map().empty()) |
+ return; |
+ |
+ for (drive::FileChange::Map::const_iterator it = list->map().begin(); |
+ it != list->map().end(); |
+ it++) { |
+ linked_ptr<file_browser_private::FileChange> change_list( |
+ new file_browser_private::FileChange); |
+ |
+ GURL url = util::ConvertDrivePathToFileSystemUrl( |
+ profile_, it->first, *extension_id); |
+ change_list->url = url.spec(); |
+ |
+ for (drive::FileChange::ChangeList::List::const_iterator change = |
+ it->second.list().begin(); |
+ change != it->second.list().end(); |
+ change++) { |
+ change_list->changes.push_back( |
+ ConvertChangeTypeFromDriveToApi(change->change())); |
+ } |
+ |
+ event.changed_files->push_back(change_list); |
+ } |
+ } |
+ |
event.entry.additional_properties.SetString( |
"fileSystemName", entry_definition.file_system_name); |
event.entry.additional_properties.SetString( |
@@ -740,6 +830,7 @@ void EventRouter::DispatchDeviceEvent( |
file_browser_private::DeviceEventType type, |
const std::string& device_path) { |
file_browser_private::DeviceEvent event; |
+ |
event.type = type; |
event.device_path = device_path; |
BroadcastEvent(profile_, |