summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/DEPS1
-rw-r--r--apps/launcher.cc134
-rw-r--r--chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc27
-rw-r--r--chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h13
-rw-r--r--chrome/browser/chromeos/file_manager/file_tasks.cc82
-rw-r--r--chrome/browser/chromeos/file_manager/file_tasks.h34
-rw-r--r--chrome/browser/chromeos/file_manager/file_tasks_unittest.cc247
-rw-r--r--chrome/browser/chromeos/file_manager/open_util.cc22
-rw-r--r--chrome/browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc50
-rw-r--r--chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc53
-rw-r--r--chrome/browser/extensions/api/file_handlers/app_file_handler_util.h41
-rw-r--r--chrome/browser/extensions/api/file_handlers/directory_util.cc84
-rw-r--r--chrome/browser/extensions/api/file_handlers/directory_util.h65
-rw-r--r--chrome/browser/extensions/api/file_handlers/directory_util_unittest.cc99
-rw-r--r--chrome/browser/extensions/api/file_system/file_system_api.cc14
-rw-r--r--chrome/chrome_browser_extensions.gypi2
-rw-r--r--chrome/chrome_tests_unit.gypi1
-rw-r--r--chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/manifest.json3
-rw-r--r--chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/test.js81
-rw-r--r--extensions/browser/api/app_runtime/app_runtime_api.cc8
-rw-r--r--extensions/browser/api/app_runtime/app_runtime_api.h3
-rw-r--r--extensions/browser/entry_info.h28
-rw-r--r--extensions/common/api/app_runtime.idl6
-rw-r--r--extensions/common/manifest_constants.cc5
-rw-r--r--extensions/common/manifest_constants.h1
-rw-r--r--extensions/common/manifest_handlers/file_handler_info.cc14
-rw-r--r--extensions/common/manifest_handlers/file_handler_info.h3
-rw-r--r--extensions/renderer/resources/app_runtime_custom_bindings.js21
-rw-r--r--ui/file_manager/file_manager/foreground/js/file_tasks.js18
-rw-r--r--ui/file_manager/file_manager/foreground/js/task_controller.js4
30 files changed, 798 insertions, 366 deletions
diff --git a/apps/DEPS b/apps/DEPS
index e2f3d69..d1ec499 100644
--- a/apps/DEPS
+++ b/apps/DEPS
@@ -30,6 +30,7 @@ include_rules = [
# Pieces of the extensions system that need to move to src/extensions.
# See http://crbug.com/162530 for details.
"+chrome/browser/extensions/api/file_handlers/app_file_handler_util.h",
+ "+chrome/browser/extensions/api/file_handlers/directory_util.h",
"+chrome/browser/extensions/api/file_handlers/mime_util.h",
"+chrome/browser/extensions/api/file_system/file_system_api.h",
"+chrome/browser/extensions/chrome_extension_web_contents_observer.h",
diff --git a/apps/launcher.cc b/apps/launcher.cc
index 309dcd58..2ae0648 100644
--- a/apps/launcher.cc
+++ b/apps/launcher.cc
@@ -12,9 +12,11 @@
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
+#include "chrome/browser/extensions/api/file_handlers/directory_util.h"
#include "chrome/browser/extensions/api/file_handlers/mime_util.h"
#include "chrome/browser/extensions/api/file_system/file_system_api.h"
#include "chrome/browser/profiles/profile.h"
@@ -24,6 +26,7 @@
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "extensions/browser/api/app_runtime/app_runtime_api.h"
+#include "extensions/browser/entry_info.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_prefs.h"
@@ -46,9 +49,9 @@ namespace app_runtime = extensions::api::app_runtime;
using content::BrowserThread;
using extensions::AppRuntimeEventRouter;
using extensions::app_file_handler_util::CreateFileEntry;
-using extensions::app_file_handler_util::FileHandlerCanHandleFile;
+using extensions::app_file_handler_util::FileHandlerCanHandleEntry;
using extensions::app_file_handler_util::FileHandlerForId;
-using extensions::app_file_handler_util::FirstFileHandlerForFile;
+using extensions::app_file_handler_util::FirstFileHandlerForEntry;
using extensions::app_file_handler_util::HasFileSystemWritePermission;
using extensions::app_file_handler_util::PrepareFilesForWritableApp;
using extensions::EventRouter;
@@ -93,18 +96,22 @@ class PlatformAppPathLauncher
public:
PlatformAppPathLauncher(Profile* profile,
const Extension* extension,
- const std::vector<base::FilePath>& file_paths)
+ const std::vector<base::FilePath>& entry_paths)
: profile_(profile),
extension_id(extension->id()),
- file_paths_(file_paths),
- collector_(profile) {}
+ entry_paths_(entry_paths),
+ mime_type_collector_(profile),
+ is_directory_collector_(profile) {}
PlatformAppPathLauncher(Profile* profile,
const Extension* extension,
const base::FilePath& file_path)
- : profile_(profile), extension_id(extension->id()), collector_(profile) {
+ : profile_(profile),
+ extension_id(extension->id()),
+ mime_type_collector_(profile),
+ is_directory_collector_(profile) {
if (!file_path.empty())
- file_paths_.push_back(file_path);
+ entry_paths_.push_back(file_path);
}
void Launch() {
@@ -114,26 +121,19 @@ class PlatformAppPathLauncher
if (!extension)
return;
- if (file_paths_.empty()) {
+ if (entry_paths_.empty()) {
LaunchWithNoLaunchData();
return;
}
- for (size_t i = 0; i < file_paths_.size(); ++i) {
- DCHECK(file_paths_[i].IsAbsolute());
- }
-
- if (HasFileSystemWritePermission(extension)) {
- PrepareFilesForWritableApp(
- file_paths_,
- profile_,
- false,
- base::Bind(&PlatformAppPathLauncher::OnFilesValid, this),
- base::Bind(&PlatformAppPathLauncher::OnFilesInvalid, this));
- return;
+ for (size_t i = 0; i < entry_paths_.size(); ++i) {
+ DCHECK(entry_paths_[i].IsAbsolute());
}
- OnFilesValid();
+ is_directory_collector_.CollectForEntriesPaths(
+ entry_paths_,
+ base::Bind(&PlatformAppPathLauncher::OnAreDirectoriesCollected, this,
+ HasFileSystemWritePermission(extension)));
}
void LaunchWithHandler(const std::string& handler_id) {
@@ -158,9 +158,8 @@ class PlatformAppPathLauncher
void MakePathAbsolute(const base::FilePath& current_directory) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
- for (std::vector<base::FilePath>::iterator it = file_paths_.begin();
- it != file_paths_.end();
- ++it) {
+ for (std::vector<base::FilePath>::iterator it = entry_paths_.begin();
+ it != entry_paths_.end(); ++it) {
if (!DoMakePathAbsolute(current_directory, &*it)) {
LOG(WARNING) << "Cannot make absolute path from " << it->value();
BrowserThread::PostTask(
@@ -176,10 +175,12 @@ class PlatformAppPathLauncher
base::Bind(&PlatformAppPathLauncher::Launch, this));
}
- void OnFilesValid() {
- collector_.CollectForLocalPaths(
- file_paths_,
- base::Bind(&PlatformAppPathLauncher::OnMimeTypesCollected, this));
+ void OnFilesValid(scoped_ptr<std::set<base::FilePath>> directory_paths) {
+ mime_type_collector_.CollectForLocalPaths(
+ entry_paths_,
+ base::Bind(
+ &PlatformAppPathLauncher::OnAreDirectoriesAndMimeTypesCollected,
+ this, base::Passed(std::move(directory_paths))));
}
void OnFilesInvalid(const base::FilePath& /* error_path */) {
@@ -198,45 +199,60 @@ class PlatformAppPathLauncher
profile_, extension, extensions::SOURCE_FILE_HANDLER);
}
- void OnMimeTypesCollected(scoped_ptr<std::vector<std::string> > mime_types) {
- DCHECK(file_paths_.size() == mime_types->size());
-
- const Extension* extension = GetExtension();
- if (!extension)
+ void OnAreDirectoriesCollected(
+ bool has_file_system_write_permission,
+ scoped_ptr<std::set<base::FilePath>> directory_paths) {
+ if (has_file_system_write_permission) {
+ std::set<base::FilePath>* const directory_paths_ptr =
+ directory_paths.get();
+ PrepareFilesForWritableApp(
+ entry_paths_, profile_, *directory_paths_ptr,
+ base::Bind(&PlatformAppPathLauncher::OnFilesValid, this,
+ base::Passed(std::move(directory_paths))),
+ base::Bind(&PlatformAppPathLauncher::OnFilesInvalid, this));
return;
+ }
+
+ OnFilesValid(std::move(directory_paths));
+ }
+ void OnAreDirectoriesAndMimeTypesCollected(
+ scoped_ptr<std::set<base::FilePath>> directory_paths,
+ scoped_ptr<std::vector<std::string>> mime_types) {
+ DCHECK(entry_paths_.size() == mime_types->size());
// If fetching a mime type failed, then use a fallback one.
- for (size_t i = 0; i < mime_types->size(); ++i) {
+ for (size_t i = 0; i < entry_paths_.size(); ++i) {
const std::string mime_type =
!(*mime_types)[i].empty() ? (*mime_types)[i] : kFallbackMimeType;
- mime_types_.push_back(mime_type);
+ bool is_directory =
+ directory_paths->find(entry_paths_[i]) != directory_paths->end();
+ entries_.push_back(
+ extensions::EntryInfo(entry_paths_[i], mime_type, is_directory));
}
+ const Extension* extension = GetExtension();
+ if (!extension)
+ return;
+
// Find file handler from the platform app for the file being opened.
const extensions::FileHandlerInfo* handler = NULL;
if (!handler_id_.empty()) {
handler = FileHandlerForId(*extension, handler_id_);
if (handler) {
- for (size_t i = 0; i < file_paths_.size(); ++i) {
- if (!FileHandlerCanHandleFile(
- *handler, mime_types_[i], file_paths_[i])) {
+ for (size_t i = 0; i < entry_paths_.size(); ++i) {
+ if (!FileHandlerCanHandleEntry(*handler, entries_[i])) {
LOG(WARNING)
<< "Extension does not provide a valid file handler for "
- << file_paths_[i].value();
+ << entry_paths_[i].value();
handler = NULL;
break;
}
}
}
} else {
- std::set<std::pair<base::FilePath, std::string> > path_and_file_type_set;
- for (size_t i = 0; i < file_paths_.size(); ++i) {
- path_and_file_type_set.insert(
- std::make_pair(file_paths_[i], mime_types_[i]));
- }
const std::vector<const extensions::FileHandlerInfo*>& handlers =
- extensions::app_file_handler_util::FindFileHandlersForFiles(
- *extension, path_and_file_type_set);
+ extensions::app_file_handler_util::FindFileHandlersForEntries(
+ *extension, entries_);
if (!handlers.empty())
handler = handlers[0];
}
@@ -286,15 +302,15 @@ class PlatformAppPathLauncher
return;
}
- std::vector<GrantedFileEntry> file_entries;
- for (size_t i = 0; i < file_paths_.size(); ++i) {
- file_entries.push_back(CreateFileEntry(
+ std::vector<GrantedFileEntry> granted_entries;
+ for (size_t i = 0; i < entry_paths_.size(); ++i) {
+ granted_entries.push_back(CreateFileEntry(
profile_, extension, host->render_process_host()->GetID(),
- file_paths_[i], false));
+ entries_[i].path, entries_[i].is_directory));
}
AppRuntimeEventRouter::DispatchOnLaunchedEventWithFileEntries(
- profile_, extension, handler_id_, mime_types_, file_entries);
+ profile_, extension, handler_id_, entries_, granted_entries);
}
const Extension* GetExtension() const {
@@ -308,12 +324,16 @@ class PlatformAppPathLauncher
// not kept as the extension may be unloaded and deleted during the course of
// the launch.
const std::string extension_id;
- // The path to be passed through to the app.
- std::vector<base::FilePath> file_paths_;
- std::vector<std::string> mime_types_;
+ // A list of files and directories to be passed through to the app.
+ std::vector<base::FilePath> entry_paths_;
+ // A corresponding list with EntryInfo for every base::FilePath in
+ // entry_paths_.
+ std::vector<extensions::EntryInfo> entries_;
// The ID of the file handler used to launch the app.
std::string handler_id_;
- extensions::app_file_handler_util::MimeTypeCollector collector_;
+ extensions::app_file_handler_util::MimeTypeCollector mime_type_collector_;
+ extensions::app_file_handler_util::IsDirectoryCollector
+ is_directory_collector_;
DISALLOW_COPY_AND_ASSIGN(PlatformAppPathLauncher);
};
@@ -388,9 +408,9 @@ void LaunchPlatformAppWithFileHandler(
Profile* profile,
const Extension* extension,
const std::string& handler_id,
- const std::vector<base::FilePath>& file_paths) {
+ const std::vector<base::FilePath>& entry_paths) {
scoped_refptr<PlatformAppPathLauncher> launcher =
- new PlatformAppPathLauncher(profile, extension, file_paths);
+ new PlatformAppPathLauncher(profile, extension, entry_paths);
launcher->LaunchWithHandler(handler_id);
}
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
index e52205f..0d39a2a 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
@@ -13,11 +13,13 @@
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/browser/chromeos/file_manager/fileapi_util.h"
#include "chrome/browser/chromeos/fileapi/file_system_backend.h"
+#include "chrome/browser/extensions/api/file_handlers/directory_util.h"
#include "chrome/browser/extensions/api/file_handlers/mime_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/file_manager_private.h"
#include "chrome/common/extensions/api/file_manager_private_internal.h"
#include "content/public/browser/browser_thread.h"
+#include "extensions/browser/entry_info.h"
#include "net/base/filename_util.h"
#include "storage/browser/fileapi/file_system_context.h"
#include "storage/browser/fileapi/file_system_url.h"
@@ -149,8 +151,9 @@ bool FileManagerPrivateInternalGetFileTasksFunction::RunAsync() {
local_paths_.push_back(file_system_url.path());
}
- collector_.reset(new app_file_handler_util::MimeTypeCollector(GetProfile()));
- collector_->CollectForLocalPaths(
+ mime_type_collector_.reset(
+ new app_file_handler_util::MimeTypeCollector(GetProfile()));
+ mime_type_collector_->CollectForLocalPaths(
local_paths_,
base::Bind(
&FileManagerPrivateInternalGetFileTasksFunction::OnMimeTypesCollected,
@@ -161,15 +164,29 @@ bool FileManagerPrivateInternalGetFileTasksFunction::RunAsync() {
void FileManagerPrivateInternalGetFileTasksFunction::OnMimeTypesCollected(
scoped_ptr<std::vector<std::string>> mime_types) {
- app_file_handler_util::PathAndMimeTypeSet path_mime_set;
+ is_directory_collector_.reset(
+ new app_file_handler_util::IsDirectoryCollector(GetProfile()));
+ is_directory_collector_->CollectForEntriesPaths(
+ local_paths_, base::Bind(&FileManagerPrivateInternalGetFileTasksFunction::
+ OnAreDirectoriesAndMimeTypesCollected,
+ this, base::Passed(std::move(mime_types))));
+}
+
+void FileManagerPrivateInternalGetFileTasksFunction::
+ OnAreDirectoriesAndMimeTypesCollected(
+ scoped_ptr<std::vector<std::string>> mime_types,
+ scoped_ptr<std::set<base::FilePath>> directory_paths) {
+ std::vector<EntryInfo> entries;
for (size_t i = 0; i < local_paths_.size(); ++i) {
- path_mime_set.insert(std::make_pair(local_paths_[i], (*mime_types)[i]));
+ entries.push_back(EntryInfo(
+ local_paths_[i], (*mime_types)[i],
+ directory_paths->find(local_paths_[i]) != directory_paths->end()));
}
std::vector<file_manager::file_tasks::FullTaskDescriptor> tasks;
file_manager::file_tasks::FindAllTypesOfTasks(
GetProfile(), drive::util::GetDriveAppRegistryByProfile(GetProfile()),
- path_mime_set, urls_, &tasks);
+ entries, urls_, &tasks);
// Convert the tasks into JSON compatible objects.
using api::file_manager_private::FileTask;
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h
index 25087a0..80b4b67 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h
@@ -7,6 +7,8 @@
#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_PRIVATE_API_TASKS_H_
#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_PRIVATE_API_TASKS_H_
+#include <set>
+#include <string>
#include <vector>
#include "base/memory/scoped_ptr.h"
@@ -20,6 +22,7 @@ class FilePath;
namespace extensions {
namespace app_file_handler_util {
+class IsDirectoryCollector;
class MimeTypeCollector;
} // namespace app_file_handler_util
@@ -59,11 +62,13 @@ class FileManagerPrivateInternalGetFileTasksFunction
private:
void OnMimeTypesCollected(scoped_ptr<std::vector<std::string> > mime_types);
- void OnSniffingMimeTypeCompleted(
- scoped_ptr<app_file_handler_util::PathAndMimeTypeSet> path_mime_set,
- scoped_ptr<std::vector<GURL>> urls);
+ void OnAreDirectoriesAndMimeTypesCollected(
+ scoped_ptr<std::vector<std::string>> mime_types,
+ scoped_ptr<std::set<base::FilePath>> path_directory_set);
- scoped_ptr<app_file_handler_util::MimeTypeCollector> collector_;
+ scoped_ptr<app_file_handler_util::IsDirectoryCollector>
+ is_directory_collector_;
+ scoped_ptr<app_file_handler_util::MimeTypeCollector> mime_type_collector_;
std::vector<GURL> urls_;
std::vector<base::FilePath> local_paths_;
};
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.cc b/chrome/browser/chromeos/file_manager/file_tasks.cc
index d2a0746..b1d4cee 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks.cc
@@ -6,6 +6,8 @@
#include <stddef.h>
+#include <map>
+
#include "apps/launcher.h"
#include "base/bind.h"
#include "base/macros.h"
@@ -32,6 +34,7 @@
#include "components/mime_util/mime_util.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
+#include "extensions/browser/entry_info.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
@@ -41,7 +44,7 @@
#include "storage/browser/fileapi/file_system_url.h"
using extensions::Extension;
-using extensions::app_file_handler_util::FindFileHandlersForFiles;
+using extensions::app_file_handler_util::FindFileHandlersForEntries;
using storage::FileSystemURL;
namespace file_manager {
@@ -91,10 +94,9 @@ const size_t kDriveTaskExtensionPrefixLength =
arraysize(kDriveTaskExtensionPrefix) - 1;
// Returns true if path_mime_set contains a Google document.
-bool ContainsGoogleDocument(const PathAndMimeTypeSet& path_mime_set) {
- for (PathAndMimeTypeSet::const_iterator iter = path_mime_set.begin();
- iter != path_mime_set.end(); ++iter) {
- if (drive::util::HasHostedDocumentExtension(iter->first))
+bool ContainsGoogleDocument(const std::vector<extensions::EntryInfo>& entries) {
+ for (const auto& it : entries) {
+ if (drive::util::HasHostedDocumentExtension(it.path))
return true;
}
return false;
@@ -302,20 +304,19 @@ bool ExecuteFileTask(Profile* profile,
return false;
}
-void FindDriveAppTasks(
- const drive::DriveAppRegistry& drive_app_registry,
- const PathAndMimeTypeSet& path_mime_set,
- std::vector<FullTaskDescriptor>* result_list) {
+void FindDriveAppTasks(const drive::DriveAppRegistry& drive_app_registry,
+ const std::vector<extensions::EntryInfo>& entries,
+ std::vector<FullTaskDescriptor>* result_list) {
DCHECK(result_list);
bool is_first = true;
typedef std::map<std::string, drive::DriveAppInfo> DriveAppInfoMap;
DriveAppInfoMap drive_app_map;
- for (PathAndMimeTypeSet::const_iterator it = path_mime_set.begin();
- it != path_mime_set.end(); ++it) {
- const base::FilePath& file_path = it->first;
- const std::string& mime_type = it->second;
+ for (std::vector<extensions::EntryInfo>::const_iterator it = entries.begin();
+ it != entries.end(); ++it) {
+ const base::FilePath& file_path = it->path;
+ const std::string& mime_type = it->mime_type;
// Return immediately if a file not on Drive is found, as Drive app tasks
// work only if all files are on Drive.
if (!drive::util::IsUnderDriveMountPoint(file_path))
@@ -369,7 +370,7 @@ void FindDriveAppTasks(
bool IsGoodMatchFileHandler(
const extensions::FileHandlerInfo& file_handler_info,
- const PathAndMimeTypeSet& path_mime_set) {
+ const std::vector<extensions::EntryInfo>& entries) {
if (file_handler_info.extensions.count("*") > 0 ||
file_handler_info.types.count("*") > 0 ||
file_handler_info.types.count("*/*") > 0)
@@ -378,20 +379,24 @@ bool IsGoodMatchFileHandler(
// If text/* file handler matches with unsupported text mime type, we don't
// regard it as good match.
if (file_handler_info.types.count("text/*")) {
- for (const auto& path_mime : path_mime_set) {
- if (mime_util::IsUnsupportedTextMimeType(path_mime.second))
+ for (const auto& entry : entries) {
+ if (mime_util::IsUnsupportedTextMimeType(entry.mime_type))
return false;
}
}
+ // We consider it a good match if no directories are selected.
+ for (const auto& entry : entries) {
+ if (entry.is_directory)
+ return false;
+ }
return true;
}
-void FindFileHandlerTasks(
- Profile* profile,
- const PathAndMimeTypeSet& path_mime_set,
- std::vector<FullTaskDescriptor>* result_list) {
- DCHECK(!path_mime_set.empty());
+void FindFileHandlerTasks(Profile* profile,
+ const std::vector<extensions::EntryInfo>& entries,
+ std::vector<FullTaskDescriptor>* result_list) {
+ DCHECK(!entries.empty());
DCHECK(result_list);
const extensions::ExtensionSet& enabled_extensions =
@@ -414,7 +419,7 @@ void FindFileHandlerTasks(
typedef std::vector<const extensions::FileHandlerInfo*> FileHandlerList;
FileHandlerList file_handlers =
- FindFileHandlersForFiles(*extension, path_mime_set);
+ FindFileHandlersForEntries(*extension, entries);
if (file_handlers.empty())
continue;
@@ -430,7 +435,7 @@ void FindFileHandlerTasks(
// such handler, show the first matching handler of the app.
const extensions::FileHandlerInfo* file_handler = file_handlers.front();
for (auto handler : file_handlers) {
- if (IsGoodMatchFileHandler(*handler, path_mime_set)) {
+ if (IsGoodMatchFileHandler(*handler, entries)) {
file_handler = handler;
break;
}
@@ -449,7 +454,7 @@ void FindFileHandlerTasks(
// If file handler doesn't match as good match, regards it as generic file
// handler.
const bool is_generic_file_handler =
- !IsGoodMatchFileHandler(*file_handler, path_mime_set);
+ !IsGoodMatchFileHandler(*file_handler, entries);
result_list->push_back(FullTaskDescriptor(
TaskDescriptor(extension->id(), file_tasks::TASK_TYPE_FILE_HANDLER,
file_handler->id),
@@ -501,23 +506,22 @@ void FindFileBrowserHandlerTasks(
}
}
-void FindAllTypesOfTasks(
- Profile* profile,
- const drive::DriveAppRegistry* drive_app_registry,
- const PathAndMimeTypeSet& path_mime_set,
- const std::vector<GURL>& file_urls,
- std::vector<FullTaskDescriptor>* result_list) {
+void FindAllTypesOfTasks(Profile* profile,
+ const drive::DriveAppRegistry* drive_app_registry,
+ const std::vector<extensions::EntryInfo>& entries,
+ const std::vector<GURL>& file_urls,
+ std::vector<FullTaskDescriptor>* result_list) {
DCHECK(profile);
DCHECK(result_list);
// Find Drive app tasks, if the drive app registry is present.
if (drive_app_registry)
- FindDriveAppTasks(*drive_app_registry, path_mime_set, result_list);
+ FindDriveAppTasks(*drive_app_registry, entries, result_list);
// Find and append file handler tasks. We know there aren't duplicates
// because Drive apps and platform apps are entirely different kinds of
// tasks.
- FindFileHandlerTasks(profile, path_mime_set, result_list);
+ FindFileHandlerTasks(profile, entries, result_list);
// Find and append file browser handler tasks. We know there aren't
// duplicates because "file_browser_handlers" and "file_handlers" shouldn't
@@ -525,21 +529,21 @@ void FindAllTypesOfTasks(
FindFileBrowserHandlerTasks(profile, file_urls, result_list);
// Google documents can only be handled by internal handlers.
- if (ContainsGoogleDocument(path_mime_set))
+ if (ContainsGoogleDocument(entries))
KeepOnlyFileManagerInternalTasks(result_list);
- ChooseAndSetDefaultTask(*profile->GetPrefs(), path_mime_set, result_list);
+ ChooseAndSetDefaultTask(*profile->GetPrefs(), entries, result_list);
}
void ChooseAndSetDefaultTask(const PrefService& pref_service,
- const PathAndMimeTypeSet& path_mime_set,
+ const std::vector<extensions::EntryInfo>& entries,
std::vector<FullTaskDescriptor>* tasks) {
// Collect the task IDs of default tasks from the preferences into a set.
std::set<std::string> default_task_ids;
- for (PathAndMimeTypeSet::const_iterator it = path_mime_set.begin();
- it != path_mime_set.end(); ++it) {
- const base::FilePath& file_path = it->first;
- const std::string& mime_type = it->second;
+ for (std::vector<extensions::EntryInfo>::const_iterator it = entries.begin();
+ it != entries.end(); ++it) {
+ const base::FilePath& file_path = it->path;
+ const std::string& mime_type = it->mime_type;
std::string task_id = file_tasks::GetDefaultTaskIdFromPrefs(
pref_service, mime_type, file_path.Extension());
default_task_ids.insert(task_id);
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.h b/chrome/browser/chromeos/file_manager/file_tasks.h
index 984347c..b357cc2 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.h
+++ b/chrome/browser/chromeos/file_manager/file_tasks.h
@@ -126,6 +126,10 @@ namespace drive {
class DriveAppRegistry;
}
+namespace extensions {
+struct EntryInfo;
+}
+
namespace storage {
class FileSystemURL;
}
@@ -254,26 +258,23 @@ bool ExecuteFileTask(Profile* profile,
const std::vector<storage::FileSystemURL>& file_urls,
const FileTaskFinishedCallback& done);
-typedef extensions::app_file_handler_util::PathAndMimeTypeSet
- PathAndMimeTypeSet;
-
-// Finds the Drive app tasks that can be used with the given |path_mime_set|
+// Finds the Drive app tasks that can be used with the given |entries|
// from |drive_app_registry|, and append them to the |result_list|.
// Drive app tasks will be found only if all of the files are on Drive.
void FindDriveAppTasks(const drive::DriveAppRegistry& drive_app_registry,
- const PathAndMimeTypeSet& path_mime_set,
+ const std::vector<extensions::EntryInfo>& entries,
std::vector<FullTaskDescriptor>* result_list);
-// Returns true if a file handler matches with files as good match.
+// Returns true if a file handler matches with entries as good match.
bool IsGoodMatchFileHandler(
const extensions::FileHandlerInfo& file_handler_info,
- const PathAndMimeTypeSet& path_mime_set);
+ const std::vector<extensions::EntryInfo>& entries);
// Finds the file handler tasks (apps declaring "file_handlers" in
-// manifest.json) that can be used with the given files, appending them to
+// manifest.json) that can be used with the given entries, appending them to
// the |result_list|.
void FindFileHandlerTasks(Profile* profile,
- const PathAndMimeTypeSet& path_mime_set,
+ const std::vector<extensions::EntryInfo>& entries,
std::vector<FullTaskDescriptor>* result_list);
// Finds the file browser handler tasks (app/extensions declaring
@@ -290,23 +291,22 @@ void FindFileBrowserHandlerTasks(
// |drive_app_registry| can be NULL if the drive app registry is not
// present.
//
-// If |path_mime_set| contains a Google document, only the internal tasks of
+// If |entries| contains a Google document, only the internal tasks of
// Files.app (i.e., tasks having the app ID of Files.app) are listed.
// This is to avoid dups between Drive app tasks and an internal handler that
// Files.app provides, and to avoid listing normal file handler and file browser
// handler tasks, which can handle only normal files.
-void FindAllTypesOfTasks(
- Profile* profile,
- const drive::DriveAppRegistry* drive_app_registry,
- const PathAndMimeTypeSet& path_mime_set,
- const std::vector<GURL>& file_urls,
- std::vector<FullTaskDescriptor>* result_list);
+void FindAllTypesOfTasks(Profile* profile,
+ const drive::DriveAppRegistry* drive_app_registry,
+ const std::vector<extensions::EntryInfo>& entries,
+ const std::vector<GURL>& file_urls,
+ std::vector<FullTaskDescriptor>* result_list);
// Chooses the default task in |tasks| and sets it as default, if the default
// task is found (i.e. the default task may not exist in |tasks|). No tasks
// should be set as default before calling this function.
void ChooseAndSetDefaultTask(const PrefService& pref_service,
- const PathAndMimeTypeSet& path_mime_set,
+ const std::vector<extensions::EntryInfo>& entries,
std::vector<FullTaskDescriptor>* tasks);
} // namespace file_tasks
diff --git a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
index 3ecee79..caa2b6c 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/chromeos/file_manager/file_tasks.h"
#include <algorithm>
+#include <set>
#include <utility>
#include "base/command_line.h"
@@ -22,6 +23,7 @@
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "extensions/browser/entry_info.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/extension_builder.h"
@@ -201,15 +203,12 @@ TEST(FileManagerFileTasksTest, FindDriveAppTasks) {
drive_app_registry.UpdateFromAppList(app_list);
// Find apps for a "text/plain" file. Foo.app and Bar.app should be found.
- PathAndMimeTypeSet path_mime_set;
- path_mime_set.insert(
- std::make_pair(
- drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
- "text/plain"));
+ std::vector<extensions::EntryInfo> entries;
+ entries.push_back(extensions::EntryInfo(
+ drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
+ "text/plain", false));
std::vector<FullTaskDescriptor> tasks;
- FindDriveAppTasks(drive_app_registry,
- path_mime_set,
- &tasks);
+ FindDriveAppTasks(drive_app_registry, entries, &tasks);
ASSERT_EQ(2U, tasks.size());
// Sort the app IDs, as the order is not guaranteed.
std::vector<std::string> app_ids;
@@ -222,31 +221,24 @@ TEST(FileManagerFileTasksTest, FindDriveAppTasks) {
// Find apps for "text/plain" and "text/html" files. Only Foo.app should be
// found.
- path_mime_set.clear();
- path_mime_set.insert(
- std::make_pair(
- drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
- "text/plain"));
- path_mime_set.insert(
- std::make_pair(
- drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.html"),
- "text/html"));
+ entries.clear();
+ entries.push_back(extensions::EntryInfo(
+ drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
+ "text/plain", false));
+ entries.push_back(extensions::EntryInfo(
+ drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.html"),
+ "text/html", false));
tasks.clear();
- FindDriveAppTasks(drive_app_registry,
- path_mime_set,
- &tasks);
+ FindDriveAppTasks(drive_app_registry, entries, &tasks);
ASSERT_EQ(1U, tasks.size());
// Confirm that only Foo.app is found.
EXPECT_EQ("foo_app_id", tasks[0].task_descriptor().app_id);
// Add a "text/plain" file not on Drive. No tasks should be found.
- path_mime_set.insert(
- std::make_pair(base::FilePath::FromUTF8Unsafe("not_on_drive.txt"),
- "text/plain"));
+ entries.push_back(extensions::EntryInfo(
+ base::FilePath::FromUTF8Unsafe("not_on_drive.txt"), "text/plain", false));
tasks.clear();
- FindDriveAppTasks(drive_app_registry,
- path_mime_set,
- &tasks);
+ FindDriveAppTasks(drive_app_registry, entries, &tasks);
// Confirm no tasks are found.
ASSERT_TRUE(tasks.empty());
}
@@ -277,14 +269,13 @@ TEST(FileManagerFileTasksTest, ChooseAndSetDefaultTask_MultipleTasks) {
GURL("http://example.com/nice_app.png"),
false /* is_default */,
false /* is_generic_file_handler */));
- PathAndMimeTypeSet path_mime_set;
- path_mime_set.insert(std::make_pair(
- base::FilePath::FromUTF8Unsafe("foo.txt"),
- "text/plain"));
+ std::vector<extensions::EntryInfo> entries;
+ entries.push_back(extensions::EntryInfo(
+ base::FilePath::FromUTF8Unsafe("foo.txt"), "text/plain", false));
// None of them should be chosen as default, as nothing is set in the
// preferences.
- ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
+ ChooseAndSetDefaultTask(pref_service, entries, &tasks);
EXPECT_FALSE(tasks[0].is_default());
EXPECT_FALSE(tasks[1].is_default());
@@ -297,7 +288,7 @@ TEST(FileManagerFileTasksTest, ChooseAndSetDefaultTask_MultipleTasks) {
UpdateDefaultTaskPreferences(&pref_service, mime_types, empty);
// Text.app should be chosen as default.
- ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
+ ChooseAndSetDefaultTask(pref_service, entries, &tasks);
EXPECT_TRUE(tasks[0].is_default());
EXPECT_FALSE(tasks[1].is_default());
@@ -306,7 +297,7 @@ TEST(FileManagerFileTasksTest, ChooseAndSetDefaultTask_MultipleTasks) {
// Clear the preferences and make sure none of them are default.
UpdateDefaultTaskPreferences(&pref_service, empty, empty);
- ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
+ ChooseAndSetDefaultTask(pref_service, entries, &tasks);
EXPECT_FALSE(tasks[0].is_default());
EXPECT_FALSE(tasks[1].is_default());
@@ -318,7 +309,7 @@ TEST(FileManagerFileTasksTest, ChooseAndSetDefaultTask_MultipleTasks) {
UpdateDefaultTaskPreferences(&pref_service, empty, suffixes);
// Now Nice.app should be chosen as default.
- ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
+ ChooseAndSetDefaultTask(pref_service, entries, &tasks);
EXPECT_FALSE(tasks[0].is_default());
EXPECT_TRUE(tasks[1].is_default());
}
@@ -340,14 +331,13 @@ TEST(FileManagerFileTasksTest, ChooseAndSetDefaultTask_FallbackFileBrowser) {
GURL("http://example.com/some_icon.png"),
false /* is_default */,
false /* is_generic_file_handler */));
- PathAndMimeTypeSet path_mime_set;
- path_mime_set.insert(std::make_pair(
- base::FilePath::FromUTF8Unsafe("foo.txt"),
- "text/plain"));
+ std::vector<extensions::EntryInfo> entries;
+ entries.push_back(extensions::EntryInfo(
+ base::FilePath::FromUTF8Unsafe("foo.txt"), "text/plain", false));
// The internal file browser handler should be chosen as default, as it's a
// fallback file browser handler.
- ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
+ ChooseAndSetDefaultTask(pref_service, entries, &tasks);
EXPECT_TRUE(tasks[0].is_default());
}
@@ -355,81 +345,79 @@ TEST(FileManagerFileTasksTest, ChooseAndSetDefaultTask_FallbackFileBrowser) {
// with files as good match or not.
TEST(FileManagerFileTasksTest, IsGoodMatchFileHandler) {
using FileHandlerInfo = extensions::FileHandlerInfo;
- typedef std::pair<base::FilePath, std::string> PathMime;
- PathAndMimeTypeSet path_and_mime_set_1;
- path_and_mime_set_1.insert(
- PathMime(base::FilePath(FILE_PATH_LITERAL("foo.jpg")), "image/jpeg"));
- path_and_mime_set_1.insert(
- PathMime(base::FilePath(FILE_PATH_LITERAL("bar.txt")), "text/plain"));
+ std::vector<extensions::EntryInfo> entries_1;
+ entries_1.push_back(extensions::EntryInfo(
+ base::FilePath(FILE_PATH_LITERAL("foo.jpg")), "image/jpeg", false));
+ entries_1.push_back(extensions::EntryInfo(
+ base::FilePath(FILE_PATH_LITERAL("bar.txt")), "text/plain", false));
- PathAndMimeTypeSet path_and_mime_set_2;
- path_and_mime_set_2.insert(
- PathMime(base::FilePath(FILE_PATH_LITERAL("foo.ics")), "text/calendar"));
+ std::vector<extensions::EntryInfo> entries_2;
+ entries_2.push_back(extensions::EntryInfo(
+ base::FilePath(FILE_PATH_LITERAL("foo.ics")), "text/calendar", false));
// extensions: ["*"]
FileHandlerInfo file_handler_info_1;
file_handler_info_1.extensions.insert("*");
- EXPECT_FALSE(
- IsGoodMatchFileHandler(file_handler_info_1, path_and_mime_set_1));
+ EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_1, entries_1));
// extensions: ["*", "jpg"]
FileHandlerInfo file_handler_info_2;
file_handler_info_2.extensions.insert("*");
file_handler_info_2.extensions.insert("jpg");
- EXPECT_FALSE(
- IsGoodMatchFileHandler(file_handler_info_2, path_and_mime_set_1));
+ EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_2, entries_1));
// extensions: ["jpg"]
FileHandlerInfo file_handler_info_3;
file_handler_info_3.extensions.insert("jpg");
- EXPECT_TRUE(IsGoodMatchFileHandler(file_handler_info_3, path_and_mime_set_1));
+ EXPECT_TRUE(IsGoodMatchFileHandler(file_handler_info_3, entries_1));
// types: ["*"]
FileHandlerInfo file_handler_info_4;
file_handler_info_4.types.insert("*");
- EXPECT_FALSE(
- IsGoodMatchFileHandler(file_handler_info_4, path_and_mime_set_1));
+ EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_4, entries_1));
// types: ["*/*"]
FileHandlerInfo file_handler_info_5;
file_handler_info_5.types.insert("*/*");
- EXPECT_FALSE(
- IsGoodMatchFileHandler(file_handler_info_5, path_and_mime_set_1));
+ EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_5, entries_1));
// types: ["image/*"]
FileHandlerInfo file_handler_info_6;
file_handler_info_6.types.insert("image/*");
// Partial wild card is not generic.
- EXPECT_TRUE(IsGoodMatchFileHandler(file_handler_info_6, path_and_mime_set_1));
+ EXPECT_TRUE(IsGoodMatchFileHandler(file_handler_info_6, entries_1));
// types: ["*", "image/*"]
FileHandlerInfo file_handler_info_7;
file_handler_info_7.types.insert("*");
file_handler_info_7.types.insert("image/*");
- EXPECT_FALSE(
- IsGoodMatchFileHandler(file_handler_info_7, path_and_mime_set_1));
+ EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_7, entries_1));
// extensions: ["*"], types: ["image/*"]
FileHandlerInfo file_handler_info_8;
file_handler_info_8.extensions.insert("*");
file_handler_info_8.types.insert("image/*");
- EXPECT_FALSE(
- IsGoodMatchFileHandler(file_handler_info_8, path_and_mime_set_1));
+ EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_8, entries_1));
// types: ["text/*"] and target files contain unsupported text mime type, e.g.
// text/calendar.
FileHandlerInfo file_handler_info_9;
file_handler_info_9.types.insert("text/*");
- EXPECT_FALSE(
- IsGoodMatchFileHandler(file_handler_info_9, path_and_mime_set_2));
+ EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_9, entries_2));
// types: ["text/*"] and target files don't contain unsupported text mime
// type.
FileHandlerInfo file_handler_info_10;
file_handler_info_10.types.insert("text/*");
- EXPECT_TRUE(
- IsGoodMatchFileHandler(file_handler_info_10, path_and_mime_set_1));
+ EXPECT_TRUE(IsGoodMatchFileHandler(file_handler_info_10, entries_1));
+
+ // path_directory_set not empty.
+ FileHandlerInfo file_handler_info_11;
+ std::vector<extensions::EntryInfo> entries_3;
+ entries_3.push_back(extensions::EntryInfo(
+ base::FilePath(FILE_PATH_LITERAL("dir1")), "", true));
+ EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_11, entries_3));
}
// Test using the test extension system, which needs lots of setup.
@@ -514,15 +502,14 @@ TEST_F(FileManagerFileTasksComplexTest, FindFileHandlerTasks) {
extension_service_->AddExtension(bar_app.Build().get());
// Find apps for a "text/plain" file. Foo.app and Bar.app should be found.
- PathAndMimeTypeSet path_mime_set;
- path_mime_set.insert(
- std::make_pair(
- drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
- "foo.txt"),
- "text/plain"));
+ std::vector<extensions::EntryInfo> entries;
+ entries.push_back(
+ extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
+ .AppendASCII("foo.txt"),
+ "text/plain", false));
std::vector<FullTaskDescriptor> tasks;
- FindFileHandlerTasks(&test_profile_, path_mime_set, &tasks);
+ FindFileHandlerTasks(&test_profile_, entries, &tasks);
ASSERT_EQ(2U, tasks.size());
// Sort the app IDs, as the order is not guaranteed.
std::vector<std::string> app_ids;
@@ -535,29 +522,26 @@ TEST_F(FileManagerFileTasksComplexTest, FindFileHandlerTasks) {
// Find apps for "text/plain" and "text/html" files. Only Foo.app should be
// found.
- path_mime_set.clear();
- path_mime_set.insert(
- std::make_pair(
- drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
- "foo.txt"),
- "text/plain"));
- path_mime_set.insert(
- std::make_pair(
- drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
- "foo.html"),
- "text/html"));
+ entries.clear();
+ entries.push_back(
+ extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
+ .AppendASCII("foo.txt"),
+ "text/plain", false));
+ entries.push_back(
+ extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
+ .AppendASCII("foo.html"),
+ "text/html", false));
tasks.clear();
- FindFileHandlerTasks(&test_profile_, path_mime_set, &tasks);
+ FindFileHandlerTasks(&test_profile_, entries, &tasks);
ASSERT_EQ(1U, tasks.size());
// Confirm that only Foo.app is found.
EXPECT_EQ(kFooId, tasks[0].task_descriptor().app_id);
// Add an "image/png" file. No tasks should be found.
- path_mime_set.insert(
- std::make_pair(base::FilePath::FromUTF8Unsafe("foo.png"),
- "image/png"));
+ entries.push_back(extensions::EntryInfo(
+ base::FilePath::FromUTF8Unsafe("foo.png"), "image/png", false));
tasks.clear();
- FindFileHandlerTasks(&test_profile_, path_mime_set, &tasks);
+ FindFileHandlerTasks(&test_profile_, entries, &tasks);
// Confirm no tasks are found.
ASSERT_TRUE(tasks.empty());
}
@@ -718,20 +702,16 @@ TEST_F(FileManagerFileTasksComplexTest, FindAllTypesOfTasks) {
drive_app_registry.UpdateFromAppList(app_list);
// Find apps for "foo.txt". All apps should be found.
- PathAndMimeTypeSet path_mime_set;
+ std::vector<extensions::EntryInfo> entries;
std::vector<GURL> file_urls;
- path_mime_set.insert(
- std::make_pair(
- drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
- "foo.txt"),
- "text/plain"));
+ entries.push_back(
+ extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
+ .AppendASCII("foo.txt"),
+ "text/plain", false));
file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
std::vector<FullTaskDescriptor> tasks;
- FindAllTypesOfTasks(&test_profile_,
- &drive_app_registry,
- path_mime_set,
- file_urls,
+ FindAllTypesOfTasks(&test_profile_, &drive_app_registry, entries, file_urls,
&tasks);
ASSERT_EQ(3U, tasks.size());
@@ -815,20 +795,16 @@ TEST_F(FileManagerFileTasksComplexTest, FindAllTypesOfTasks_GoogleDocument) {
// Find apps for a ".gdoc file". Only the built-in handler of Files.apps
// should be found.
- PathAndMimeTypeSet path_mime_set;
+ std::vector<extensions::EntryInfo> entries;
std::vector<GURL> file_urls;
- path_mime_set.insert(
- std::make_pair(
- drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
- "foo.gdoc"),
- "application/vnd.google-apps.document"));
+ entries.push_back(
+ extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
+ .AppendASCII("foo.gdoc"),
+ "application/vnd.google-apps.document", false));
file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.gdoc"));
std::vector<FullTaskDescriptor> tasks;
- FindAllTypesOfTasks(&test_profile_,
- &drive_app_registry,
- path_mime_set,
- file_urls,
+ FindAllTypesOfTasks(&test_profile_, &drive_app_registry, entries, file_urls,
&tasks);
ASSERT_EQ(1U, tasks.size());
EXPECT_EQ(kFileManagerAppId, tasks[0].task_descriptor().app_id);
@@ -871,7 +847,7 @@ TEST_F(FileManagerFileTasksComplexTest, FindFileHandlerTask_Generic) {
extension_service_->AddExtension(foo_app.Build().get());
// Bar app provides file handler for .txt and not provide generic file
- // handler.
+ // handler, but handles directories.
extensions::ExtensionBuilder bar_app;
bar_app.SetManifest(std::move(
extensions::DictionaryBuilder()
@@ -884,11 +860,14 @@ TEST_F(FileManagerFileTasksComplexTest, FindFileHandlerTask_Generic) {
std::move(extensions::DictionaryBuilder().Set(
"scripts", std::move(extensions::ListBuilder().Append(
"background.js")))))))
- .Set("file_handlers",
- std::move(extensions::DictionaryBuilder().Set(
- "text",
- std::move(extensions::DictionaryBuilder().Set(
- "extensions", std::move(extensions::ListBuilder().Append(
+ .Set(
+ "file_handlers",
+ std::move(extensions::DictionaryBuilder().Set(
+ "text",
+ std::move(extensions::DictionaryBuilder()
+ .SetBoolean("include_directories", true)
+ .Set("extensions",
+ std::move(extensions::ListBuilder().Append(
"txt")))))))));
bar_app.SetID(kBarId);
extension_service_->AddExtension(bar_app.Build().get());
@@ -946,14 +925,13 @@ TEST_F(FileManagerFileTasksComplexTest, FindFileHandlerTask_Generic) {
extension_service_->AddExtension(qux_app.Build().get());
// Test case with .txt file
- PathAndMimeTypeSet txt_path_mime_set;
- txt_path_mime_set.insert(
- std::make_pair(
- drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
- "foo.txt"),
- "text/plain"));
+ std::vector<extensions::EntryInfo> txt_entries;
+ txt_entries.push_back(
+ extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
+ .AppendASCII("foo.txt"),
+ "text/plain", false));
std::vector<FullTaskDescriptor> txt_result;
- FindFileHandlerTasks(&test_profile_, txt_path_mime_set, &txt_result);
+ FindFileHandlerTasks(&test_profile_, txt_entries, &txt_result);
EXPECT_EQ(4U, txt_result.size());
// Foo app provides a handler for text/plain.
EXPECT_EQ("Foo", txt_result[0].task_title());
@@ -969,14 +947,13 @@ TEST_F(FileManagerFileTasksComplexTest, FindFileHandlerTask_Generic) {
EXPECT_TRUE(txt_result[3].is_generic_file_handler());
// Test case with .jpg file
- PathAndMimeTypeSet jpg_path_mime_set;
- jpg_path_mime_set.insert(
- std::make_pair(
- drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
- "foo.jpg"),
- "image/jpeg"));
+ std::vector<extensions::EntryInfo> jpg_entries;
+ jpg_entries.push_back(
+ extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
+ .AppendASCII("foo.jpg"),
+ "image/jpeg", false));
std::vector<FullTaskDescriptor> jpg_result;
- FindFileHandlerTasks(&test_profile_, jpg_path_mime_set, &jpg_result);
+ FindFileHandlerTasks(&test_profile_, jpg_entries, &jpg_result);
EXPECT_EQ(3U, jpg_result.size());
// Foo app provides a handler for all types.
EXPECT_EQ("Foo", jpg_result[0].task_title());
@@ -988,6 +965,18 @@ TEST_F(FileManagerFileTasksComplexTest, FindFileHandlerTask_Generic) {
// Qux app provides a handler for all types.
EXPECT_EQ("Qux", jpg_result[2].task_title());
EXPECT_TRUE(jpg_result[2].is_generic_file_handler());
+
+ // Test case with directories.
+ std::vector<extensions::EntryInfo> dir_entries;
+ dir_entries.push_back(extensions::EntryInfo(
+ drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII("dir"),
+ "", true));
+ std::vector<FullTaskDescriptor> dir_result;
+ FindFileHandlerTasks(&test_profile_, dir_entries, &dir_result);
+ ASSERT_EQ(1U, dir_result.size());
+ // Confirm that only Bar.app is found and that it is a generic file handler.
+ EXPECT_EQ(kBarId, dir_result[0].task_descriptor().app_id);
+ EXPECT_TRUE(dir_result[0].is_generic_file_handler());
}
} // namespace file_tasks
diff --git a/chrome/browser/chromeos/file_manager/open_util.cc b/chrome/browser/chromeos/file_manager/open_util.cc
index 4883248..0a3ebc2 100644
--- a/chrome/browser/chromeos/file_manager/open_util.cc
+++ b/chrome/browser/chromeos/file_manager/open_util.cc
@@ -4,6 +4,10 @@
#include "chrome/browser/chromeos/file_manager/open_util.h"
+#include <set>
+#include <string>
+#include <vector>
+
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/logging.h"
@@ -14,9 +18,11 @@
#include "chrome/browser/chromeos/file_manager/fileapi_util.h"
#include "chrome/browser/chromeos/file_manager/path_util.h"
#include "chrome/browser/chromeos/file_manager/url_util.h"
+#include "chrome/browser/extensions/api/file_handlers/directory_util.h"
#include "chrome/browser/extensions/api/file_handlers/mime_util.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/user_metrics.h"
+#include "extensions/browser/entry_info.h"
#include "storage/browser/fileapi/file_system_backend.h"
#include "storage/browser/fileapi/file_system_context.h"
#include "storage/browser/fileapi/file_system_operation_runner.h"
@@ -42,9 +48,8 @@ void ExecuteFileTaskForUrl(Profile* profile,
file_tasks::ExecuteFileTask(
profile,
- GetFileManagerMainPageUrl(), // Executing the task on behalf of Files.app.
- task,
- std::vector<FileSystemURL>(1, file_system_context->CrackURL(url)),
+ GetFileManagerMainPageUrl(), // Executing task on behalf of Files.app.
+ task, std::vector<FileSystemURL>(1, file_system_context->CrackURL(url)),
file_tasks::FileTaskFinishedCallback());
}
@@ -74,19 +79,16 @@ void OpenFileWithMimeType(Profile* profile,
const GURL& url,
const platform_util::OpenOperationCallback& callback,
const std::string& mime_type) {
- extensions::app_file_handler_util::PathAndMimeTypeSet path_mime_set;
- path_mime_set.insert(std::make_pair(path, mime_type));
+ std::vector<extensions::EntryInfo> entries;
+ entries.push_back(extensions::EntryInfo(path, mime_type, false));
std::vector<GURL> file_urls;
file_urls.push_back(url);
std::vector<file_tasks::FullTaskDescriptor> tasks;
file_tasks::FindAllTypesOfTasks(
- profile,
- drive::util::GetDriveAppRegistryByProfile(profile),
- path_mime_set,
- file_urls,
- &tasks);
+ profile, drive::util::GetDriveAppRegistryByProfile(profile), entries,
+ file_urls, &tasks);
// Select a default handler. If a default handler is not available, select
// a non-generic file handler.
diff --git a/chrome/browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc b/chrome/browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc
index a4a8927..6454656 100644
--- a/chrome/browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc
+++ b/chrome/browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
+#include "extensions/browser/entry_info.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
@@ -16,30 +17,47 @@ FileHandlerInfo CreateHandlerInfoFromExtension(const std::string& extension) {
return handler_info;
}
+FileHandlerInfo CreateHandlerInfoFromIncludeDirectories(
+ bool include_directories) {
+ FileHandlerInfo handler_info;
+ handler_info.include_directories = include_directories;
+ return handler_info;
}
-TEST(FileHandlersAppFileHandlerUtilTest, FileHandlerCanHandleFile) {
+} // namespace
+
+TEST(FileHandlersAppFileHandlerUtilTest, FileHandlerCanHandleEntry) {
// File handler for extension "gz" should accept "*.gz", including "*.tar.gz".
- EXPECT_TRUE(FileHandlerCanHandleFile(
+ EXPECT_TRUE(FileHandlerCanHandleEntry(
CreateHandlerInfoFromExtension("gz"),
- "application/octet-stream",
- base::FilePath::FromUTF8Unsafe("foo.gz")));
- EXPECT_FALSE(FileHandlerCanHandleFile(
+ EntryInfo(base::FilePath::FromUTF8Unsafe("foo.gz"),
+ "application/octet-stream", false)));
+ EXPECT_FALSE(FileHandlerCanHandleEntry(
CreateHandlerInfoFromExtension("gz"),
- "application/octet-stream",
- base::FilePath::FromUTF8Unsafe("foo.tgz")));
- EXPECT_TRUE(FileHandlerCanHandleFile(
+ EntryInfo(base::FilePath::FromUTF8Unsafe("foo.tgz"),
+ "application/octet-stream", false)));
+ EXPECT_TRUE(FileHandlerCanHandleEntry(
CreateHandlerInfoFromExtension("gz"),
- "application/octet-stream",
- base::FilePath::FromUTF8Unsafe("foo.tar.gz")));
- EXPECT_FALSE(FileHandlerCanHandleFile(
+ EntryInfo(base::FilePath::FromUTF8Unsafe("foo.tar.gz"),
+ "application/octet-stream", false)));
+ EXPECT_FALSE(FileHandlerCanHandleEntry(
CreateHandlerInfoFromExtension("tar.gz"),
- "application/octet-stream",
- base::FilePath::FromUTF8Unsafe("foo.gz")));
- EXPECT_TRUE(FileHandlerCanHandleFile(
+ EntryInfo(base::FilePath::FromUTF8Unsafe("foo.gz"),
+ "application/octet-stream", false)));
+ EXPECT_TRUE(FileHandlerCanHandleEntry(
CreateHandlerInfoFromExtension("tar.gz"),
- "application/octet-stream",
- base::FilePath::FromUTF8Unsafe("foo.tar.gz")));
+ EntryInfo(base::FilePath::FromUTF8Unsafe("foo.tar.gz"),
+ "application/octet-stream", false)));
+ EXPECT_FALSE(FileHandlerCanHandleEntry(
+ CreateHandlerInfoFromExtension("gz"),
+ EntryInfo(base::FilePath::FromUTF8Unsafe("directory"), "", true)));
+
+ EXPECT_FALSE(FileHandlerCanHandleEntry(
+ CreateHandlerInfoFromIncludeDirectories(false),
+ EntryInfo(base::FilePath::FromUTF8Unsafe("directory"), "", true)));
+ EXPECT_TRUE(FileHandlerCanHandleEntry(
+ CreateHandlerInfoFromIncludeDirectories(true),
+ EntryInfo(base::FilePath::FromUTF8Unsafe("directory"), "", true)));
}
} // namespace app_file_handler_util
diff --git a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
index 9132be8..07ce6f1 100644
--- a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
+++ b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
@@ -10,6 +10,7 @@
#include "build/build_config.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_security_policy.h"
+#include "extensions/browser/entry_info.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/granted_file_entry.h"
#include "extensions/common/permissions/permissions_data.h"
@@ -101,7 +102,7 @@ class WritableFileChecker
WritableFileChecker(
const std::vector<base::FilePath>& paths,
Profile* profile,
- bool is_directory,
+ const std::set<base::FilePath>& directory_paths,
const base::Closure& on_success,
const base::Callback<void(const base::FilePath&)>& on_failure);
@@ -127,7 +128,7 @@ class WritableFileChecker
const std::vector<base::FilePath> paths_;
Profile* profile_;
- const bool is_directory_;
+ const std::set<base::FilePath> directory_paths_;
int outstanding_tasks_;
base::FilePath error_path_;
base::Closure on_success_;
@@ -137,12 +138,12 @@ class WritableFileChecker
WritableFileChecker::WritableFileChecker(
const std::vector<base::FilePath>& paths,
Profile* profile,
- bool is_directory,
+ const std::set<base::FilePath>& directory_paths,
const base::Closure& on_success,
const base::Callback<void(const base::FilePath&)>& on_failure)
: paths_(paths),
profile_(profile),
- is_directory_(is_directory),
+ directory_paths_(directory_paths),
outstanding_tasks_(1),
on_success_(on_success),
on_failure_(on_failure) {}
@@ -150,9 +151,10 @@ WritableFileChecker::WritableFileChecker(
void WritableFileChecker::Check() {
outstanding_tasks_ = paths_.size();
for (const auto& path : paths_) {
+ bool is_directory = directory_paths_.find(path) != directory_paths_.end();
#if defined(OS_CHROMEOS)
if (file_manager::util::IsUnderNonNativeLocalPath(profile_, path)) {
- if (is_directory_) {
+ if (is_directory) {
file_manager::util::IsNonNativeLocalPathDirectory(
profile_, path,
base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
@@ -166,8 +168,7 @@ void WritableFileChecker::Check() {
#endif
content::BrowserThread::PostTaskAndReplyWithResult(
content::BrowserThread::FILE, FROM_HERE,
- base::Bind(&PrepareNativeLocalFileForWritableApp, path,
- is_directory_),
+ base::Bind(&PrepareNativeLocalFileForWritableApp, path, is_directory),
base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
}
}
@@ -216,26 +217,25 @@ const FileHandlerInfo* FileHandlerForId(const Extension& app,
return NULL;
}
-const FileHandlerInfo* FirstFileHandlerForFile(
- const Extension& app,
- const std::string& mime_type,
- const base::FilePath& path) {
+const FileHandlerInfo* FirstFileHandlerForEntry(const Extension& app,
+ const EntryInfo& entry) {
const FileHandlersInfo* file_handlers = FileHandlers::GetFileHandlers(&app);
if (!file_handlers)
return NULL;
for (FileHandlersInfo::const_iterator i = file_handlers->begin();
i != file_handlers->end(); i++) {
- if (FileHandlerCanHandleFile(*i, mime_type, path))
+ if (FileHandlerCanHandleEntry(*i, entry))
return &*i;
}
return NULL;
}
-std::vector<const FileHandlerInfo*> FindFileHandlersForFiles(
- const Extension& app, const PathAndMimeTypeSet& files) {
+std::vector<const FileHandlerInfo*> FindFileHandlersForEntries(
+ const Extension& app,
+ const std::vector<EntryInfo> entries) {
std::vector<const FileHandlerInfo*> handlers;
- if (files.empty())
+ if (entries.empty())
return handlers;
// Look for file handlers which can handle all the MIME types specified.
@@ -246,9 +246,9 @@ std::vector<const FileHandlerInfo*> FindFileHandlersForFiles(
for (FileHandlersInfo::const_iterator data = file_handlers->begin();
data != file_handlers->end(); ++data) {
bool handles_all_types = true;
- for (PathAndMimeTypeSet::const_iterator it = files.begin();
- it != files.end(); ++it) {
- if (!FileHandlerCanHandleFile(*data, it->second, it->first)) {
+ for (std::vector<EntryInfo>::const_iterator it = entries.begin();
+ it != entries.end(); ++it) {
+ if (!FileHandlerCanHandleEntry(*data, *it)) {
handles_all_types = false;
break;
}
@@ -259,12 +259,13 @@ std::vector<const FileHandlerInfo*> FindFileHandlersForFiles(
return handlers;
}
-bool FileHandlerCanHandleFile(
- const FileHandlerInfo& handler,
- const std::string& mime_type,
- const base::FilePath& path) {
- return FileHandlerCanHandleFileWithMimeType(handler, mime_type) ||
- FileHandlerCanHandleFileWithExtension(handler, path);
+bool FileHandlerCanHandleEntry(const FileHandlerInfo& handler,
+ const EntryInfo& entry) {
+ if (entry.is_directory)
+ return handler.include_directories;
+
+ return FileHandlerCanHandleFileWithMimeType(handler, entry.mime_type) ||
+ FileHandlerCanHandleFileWithExtension(handler, entry.path);
}
GrantedFileEntry CreateFileEntry(
@@ -303,11 +304,11 @@ GrantedFileEntry CreateFileEntry(
void PrepareFilesForWritableApp(
const std::vector<base::FilePath>& paths,
Profile* profile,
- bool is_directory,
+ const std::set<base::FilePath>& directory_paths,
const base::Closure& on_success,
const base::Callback<void(const base::FilePath&)>& on_failure) {
scoped_refptr<WritableFileChecker> checker(new WritableFileChecker(
- paths, profile, is_directory, on_success, on_failure));
+ paths, profile, directory_paths, on_success, on_failure));
checker->Check();
}
diff --git a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.h b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.h
index 3ca6f6a..d90b7073 100644
--- a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.h
+++ b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.h
@@ -19,6 +19,7 @@ class Profile;
namespace extensions {
class ExtensionPrefs;
+struct EntryInfo;
struct FileHandlerInfo;
struct GrantedFileEntry;
@@ -28,31 +29,23 @@ namespace app_file_handler_util {
extern const char kInvalidParameters[];
extern const char kSecurityError[];
-// A set of pairs of path and its corresponding MIME type.
-typedef std::set<std::pair<base::FilePath, std::string> > PathAndMimeTypeSet;
-
// Returns the file handler with the specified |handler_id|, or NULL if there
// is no such handler.
const FileHandlerInfo* FileHandlerForId(const Extension& app,
const std::string& handler_id);
-// Returns the first file handler that can handle the given MIME type or
-// filename, or NULL if is no such handler.
-const FileHandlerInfo* FirstFileHandlerForFile(
- const Extension& app,
- const std::string& mime_type,
- const base::FilePath& path);
+// Returns the first file handler that can handle the given entry,
+// or NULL if is no such handler.
+const FileHandlerInfo* FirstFileHandlerForEntry(const Extension& app,
+ const EntryInfo* entry);
-// Returns the handlers that can handle all files in |files|. The paths in
-// |files| must be populated, but the MIME types are optional.
-std::vector<const FileHandlerInfo*>
-FindFileHandlersForFiles(const Extension& extension,
- const PathAndMimeTypeSet& files);
+// Returns the handlers that can handle all files in |entries|.
+std::vector<const FileHandlerInfo*> FindFileHandlersForEntries(
+ const Extension& extension,
+ const std::vector<EntryInfo> entries);
-bool FileHandlerCanHandleFile(
- const FileHandlerInfo& handler,
- const std::string& mime_type,
- const base::FilePath& path);
+bool FileHandlerCanHandleEntry(const FileHandlerInfo& handler,
+ const EntryInfo& entry);
// Creates a new file entry and allows |renderer_id| to access |path|. This
// registers a new file system for |path|.
@@ -62,15 +55,15 @@ GrantedFileEntry CreateFileEntry(Profile* profile,
const base::FilePath& path,
bool is_directory);
-// When |is_directory| is true, it verifies that directories exist at each of
-// the |paths| and calls back to |on_success| or otherwise to |on_failure|.
-// When |is_directory| is false, it ensures regular files exists (not links and
-// directories) at the |paths|, creating files if needed, and calls back to
-// |on_success| or to |on_failure| depending on the result.
+// |directory_paths| contain the set of directories out of |paths|.
+// For directories it makes sure they exist at their corresponding |paths|,
+// while for regular files it makes sure they exist (i.e. not links) at |paths|,
+// creating files if needed. If result is successful it calls |on_success|,
+// otherwise calls |on_failure|.
void PrepareFilesForWritableApp(
const std::vector<base::FilePath>& paths,
Profile* profile,
- bool is_directory,
+ const std::set<base::FilePath>& directory_paths,
const base::Closure& on_success,
const base::Callback<void(const base::FilePath&)>& on_failure);
diff --git a/chrome/browser/extensions/api/file_handlers/directory_util.cc b/chrome/browser/extensions/api/file_handlers/directory_util.cc
new file mode 100644
index 0000000..1638f2d
--- /dev/null
+++ b/chrome/browser/extensions/api/file_handlers/directory_util.cc
@@ -0,0 +1,84 @@
+// Copyright 2016 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/extensions/api/file_handlers/directory_util.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/thread_task_runner_handle.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/filename_util.h"
+#include "storage/browser/fileapi/file_system_url.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
+#endif
+
+namespace extensions {
+namespace app_file_handler_util {
+
+void EntryIsDirectory(Profile* profile,
+ const base::FilePath& path,
+ const base::Callback<void(bool)>& callback) {
+#if defined(OS_CHROMEOS)
+ if (file_manager::util::IsUnderNonNativeLocalPath(profile, path)) {
+ file_manager::util::IsNonNativeLocalPathDirectory(profile, path, callback);
+ return;
+ }
+#endif
+
+ base::File::Info file_info;
+ bool is_directory = GetFileInfo(path, &file_info) && file_info.is_directory;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback, is_directory));
+}
+
+IsDirectoryCollector::IsDirectoryCollector(Profile* profile)
+ : profile_(profile), left_(0), weak_ptr_factory_(this) {}
+
+IsDirectoryCollector::~IsDirectoryCollector() {}
+
+void IsDirectoryCollector::CollectForEntriesPaths(
+ const std::vector<base::FilePath>& paths,
+ const CompletionCallback& callback) {
+ DCHECK(!callback.is_null());
+ paths_ = paths;
+ callback_ = callback;
+
+ DCHECK(!result_.get());
+ result_.reset(new std::set<base::FilePath>());
+ left_ = paths.size();
+
+ if (!left_) {
+ // Nothing to process.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback_, base::Passed(&result_)));
+ callback_ = CompletionCallback();
+ return;
+ }
+
+ for (size_t i = 0; i < paths.size(); ++i) {
+ EntryIsDirectory(profile_, paths[i],
+ base::Bind(&IsDirectoryCollector::OnIsDirectoryCollected,
+ weak_ptr_factory_.GetWeakPtr(), i));
+ }
+}
+
+void IsDirectoryCollector::OnIsDirectoryCollected(size_t index,
+ bool is_directory) {
+ if (is_directory)
+ result_->insert(paths_[index]);
+ if (!--left_) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(callback_, base::Passed(&result_)));
+ // Release the callback to avoid a circullar reference in case an instance
+ // of this class is a member of a ref counted class, which instance is bound
+ // to this callback.
+ callback_ = CompletionCallback();
+ }
+}
+
+} // namespace app_file_handler_util
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/file_handlers/directory_util.h b/chrome/browser/extensions/api/file_handlers/directory_util.h
new file mode 100644
index 0000000..9921e6b
--- /dev/null
+++ b/chrome/browser/extensions/api/file_handlers/directory_util.h
@@ -0,0 +1,65 @@
+// Copyright 2016 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_EXTENSIONS_API_FILE_HANDLERS_DIRECTORY_UTIL_H_
+#define CHROME_BROWSER_EXTENSIONS_API_FILE_HANDLERS_DIRECTORY_UTIL_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+
+class Profile;
+
+namespace base {
+class FilePath;
+} // namespace base
+
+namespace storage {
+class FileSystemURL;
+} // namespace storage
+
+namespace extensions {
+namespace app_file_handler_util {
+
+// The callback parameter contains the result and is required for support of
+// non native local path directories that require a callback.
+void EntryIsDirectory(Profile* profile,
+ const base::FilePath& path,
+ const base::Callback<void(bool)>& callback);
+
+class IsDirectoryCollector {
+ public:
+ typedef base::Callback<void(scoped_ptr<std::set<base::FilePath>>)>
+ CompletionCallback;
+
+ explicit IsDirectoryCollector(Profile* profile);
+ virtual ~IsDirectoryCollector();
+
+ // For the given paths obtains a set with which of them are directories.
+ // The collector does not support virtual files if OS != CHROMEOS.
+ void CollectForEntriesPaths(const std::vector<base::FilePath>& paths,
+ const CompletionCallback& callback);
+
+ private:
+ void OnIsDirectoryCollected(size_t index, bool directory);
+
+ Profile* profile_;
+ std::vector<base::FilePath> paths_;
+ scoped_ptr<std::set<base::FilePath>> result_;
+ size_t left_;
+ CompletionCallback callback_;
+ base::WeakPtrFactory<IsDirectoryCollector> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(IsDirectoryCollector);
+};
+
+} // namespace app_file_handler_util
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_FILE_HANDLERS_DIRECTORY_UTIL_H_
diff --git a/chrome/browser/extensions/api/file_handlers/directory_util_unittest.cc b/chrome/browser/extensions/api/file_handlers/directory_util_unittest.cc
new file mode 100644
index 0000000..3530d19
--- /dev/null
+++ b/chrome/browser/extensions/api/file_handlers/directory_util_unittest.cc
@@ -0,0 +1,99 @@
+// Copyright 2016 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/extensions/api/file_handlers/directory_util.h"
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+namespace app_file_handler_util {
+namespace {
+
+const char kRandomPath[] = "/random/path";
+
+void OnEntryIsDirectoryResult(bool* output, bool is_directory) {
+ *output = is_directory;
+}
+
+void OnCollectForEntriesPath(
+ std::set<base::FilePath>* output,
+ scoped_ptr<std::set<base::FilePath>> path_directory_set) {
+ *output = *path_directory_set;
+}
+
+} // namespace
+
+class IsDirectoryUtilTest : public testing::Test {
+ protected:
+ IsDirectoryUtilTest() {}
+ ~IsDirectoryUtilTest() override {}
+
+ void SetUp() override {
+ EXPECT_TRUE(
+ base::CreateNewTempDirectory(base::FilePath::StringType(), &dir_path_));
+ EXPECT_TRUE(base::CreateTemporaryFile(&file_path_));
+ }
+
+ content::TestBrowserThreadBundle thread_bundle_;
+ TestingProfile profile_;
+ base::FilePath dir_path_;
+ base::FilePath file_path_;
+};
+
+TEST_F(IsDirectoryUtilTest, EntryIsDirectory) {
+ {
+ bool result = false;
+ EntryIsDirectory(&profile_, dir_path_,
+ base::Bind(&OnEntryIsDirectoryResult, &result));
+ content::RunAllBlockingPoolTasksUntilIdle();
+ EXPECT_TRUE(result);
+ }
+
+ {
+ bool result = true;
+ EntryIsDirectory(&profile_, base::FilePath::FromUTF8Unsafe(kRandomPath),
+ base::Bind(&OnEntryIsDirectoryResult, &result));
+ content::RunAllBlockingPoolTasksUntilIdle();
+ EXPECT_FALSE(result);
+ }
+
+ {
+ bool result = true;
+ EntryIsDirectory(&profile_, file_path_,
+ base::Bind(&OnEntryIsDirectoryResult, &result));
+ content::RunAllBlockingPoolTasksUntilIdle();
+ EXPECT_FALSE(result);
+ }
+}
+
+TEST_F(IsDirectoryUtilTest, CollectForEntriesPaths) {
+ std::vector<base::FilePath> paths;
+ paths.push_back(dir_path_);
+ paths.push_back(file_path_);
+ paths.push_back(base::FilePath::FromUTF8Unsafe(kRandomPath));
+
+ IsDirectoryCollector collector(&profile_);
+ std::set<base::FilePath> result;
+ collector.CollectForEntriesPaths(
+ paths, base::Bind(&OnCollectForEntriesPath, &result));
+ content::RunAllBlockingPoolTasksUntilIdle();
+
+ ASSERT_EQ(1u, result.size());
+ EXPECT_GT(result.count(dir_path_), 0u);
+}
+
+} // namespace app_file_handler_util
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/chrome/browser/extensions/api/file_system/file_system_api.cc
index 7968fdf..2e365c8 100644
--- a/chrome/browser/extensions/api/file_system/file_system_api.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_api.cc
@@ -508,13 +508,17 @@ FileSystemEntryFunction::FileSystemEntryFunction()
void FileSystemEntryFunction::PrepareFilesForWritableApp(
const std::vector<base::FilePath>& paths) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // TODO(cmihail): Path directory set should be initialized only with the
+ // paths that are actually directories, but for now we will consider
+ // all paths directories in case is_directory_ is true, otherwise
+ // all paths files, as this was the previous logic.
+ std::set<base::FilePath> path_directory_set_ =
+ is_directory_ ? std::set<base::FilePath>(paths.begin(), paths.end())
+ : std::set<base::FilePath>{};
app_file_handler_util::PrepareFilesForWritableApp(
- paths,
- GetProfile(),
- is_directory_,
+ paths, GetProfile(), path_directory_set_,
base::Bind(&FileSystemEntryFunction::RegisterFileSystemsAndSendResponse,
- this,
- paths),
+ this, paths),
base::Bind(&FileSystemEntryFunction::HandleWritableFileError, this));
}
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index f592441..d2d8349 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -299,6 +299,8 @@
'browser/extensions/api/feedback_private/feedback_service.h',
'browser/extensions/api/file_handlers/app_file_handler_util.cc',
'browser/extensions/api/file_handlers/app_file_handler_util.h',
+ 'browser/extensions/api/file_handlers/directory_util.cc',
+ 'browser/extensions/api/file_handlers/directory_util.h',
'browser/extensions/api/file_handlers/mime_util.cc',
'browser/extensions/api/file_handlers/mime_util.h',
'browser/extensions/api/file_system/file_system_api.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 491b995..3be1264 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -420,6 +420,7 @@
'browser/extensions/api/extension_action/browser_action_unittest.cc',
'browser/extensions/api/extension_action/extension_action_prefs_unittest.cc',
'browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc',
+ 'browser/extensions/api/file_handlers/directory_util_unittest.cc',
'browser/extensions/api/file_handlers/mime_util_unittest.cc',
'browser/extensions/api/file_system/file_system_api_unittest.cc',
'browser/extensions/api/identity/extension_token_key_unittest.cc',
diff --git a/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/manifest.json b/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/manifest.json
index 2642a752..8fde887 100644
--- a/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/manifest.json
+++ b/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/manifest.json
@@ -12,7 +12,8 @@
},
"file_handlers": {
"textAction": {
- "extensions": ["txt"]
+ "extensions": ["txt"],
+ "include_directories": true
}
},
"permissions": [
diff --git a/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/test.js b/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/test.js
index b37a663..4dd2c99 100644
--- a/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/test.js
+++ b/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/test.js
@@ -52,6 +52,22 @@ function prepareFile(filesystem, name, contents) {
}
/**
+ * Prepares a directory on the file system.
+ * @param {FileSystem} filesystem File system.
+ * @param {string} name Name of the directory.
+ * @param {Blob} contents Contents of the file.
+ * @return {Promise} Promise to be fulfilled with DirectoryEntry of the new
+ * directory.
+ */
+function prepareDirectory(filesystem, name) {
+ return new Promise(function(fulfill, reject) {
+ filesystem.root.getDirectory(name, {create: true}, function(dirEntry) {
+ fulfill(dirEntry);
+ }, reject);
+ });
+}
+
+/**
* Prepares two test files on the file system.
* @param {FileSystem} filesystem File system.
* @return {Promise} Promise to be fullfilled with an object {filesystem:
@@ -69,6 +85,21 @@ function prepareFiles(filesystem) {
}
/**
+ * Prepares two test directories on the file system.
+ * @param {FileSystem} filesystem File system.
+ * @return {Promise} Promise to be fullfilled with an object {filesystem:
+ * FileSystem, entries: Array<DirectoryEntry>} that contains the passed file
+ * system and the created entries.
+ */
+function prepareDirectories(filesystem) {
+ var testDirA = prepareDirectory(filesystem, 'dir1');
+ var testDirB = prepareDirectory(filesystem, 'dir2');
+ return Promise.all([testDirA, testDirB]).then(function(entries) {
+ return {filesystem: filesystem, entries: entries};
+ });
+}
+
+/**
* Contents of the test file.
* @type {Blob}
* @const
@@ -76,18 +107,30 @@ function prepareFiles(filesystem) {
var TEST_FILE_CONTENTS = new Blob(['This is a test file.']);
/**
- * File system of the drive volume.
+ * File system of the drive volume for files.
* @type {Promise}
*/
var driveFileSystemPromise = getFileSystem('drive').then(prepareFiles);
/**
- * File system of the local volume.
+ * File system of the local volume for files.
* @type {Promise}
*/
var localFileSystemPromise = getFileSystem('testing').then(prepareFiles);
/**
+ * File system of the drive volume for directories.
+ * @type {Promise}
+ */
+var driveDirSystemPromise = getFileSystem('drive').then(prepareDirectories);
+
+/**
+ * File system of the local volume for directories.
+ * @type {Promise}
+ */
+var localDirSystemPromise = getFileSystem('drive').then(prepareDirectories);
+
+/**
* Calls test functions depends on the result of the promise.
* @param {Promise} promise Promise to be fulfilled or to be rejected depends on
* the test results.
@@ -195,14 +238,34 @@ function testForDriveFiles() {
}
/**
- * Tests the file handler with entries both on the local and on the drive
- * volumes.
+ * Tests the directory handler feature with entries on the local volume.
+ */
+function testForLocalDirectories() {
+ testPromise(localDirSystemPromise.then(function(volume) {
+ return launchWithEntries(volume.entries);
+ }));
+}
+
+/**
+ * Tests the directory handler feature with entries on the local volume.
+ */
+function testForDriveDirectories() {
+ testPromise(driveDirSystemPromise.then(function(volume) {
+ return launchWithEntries(volume.entries);
+ }));
+}
+
+/**
+ * Tests the file and directory handler with entries both on the local and on
+ * the drive volumes.
*/
-function testForMixedFiles() {
+function testForMixedFilesAndDirectories() {
testPromise(
- Promise.all([localFileSystemPromise, driveFileSystemPromise]).then(
+ Promise.all([localFileSystemPromise, driveFileSystemPromise,
+ localDirSystemPromise, driveDirSystemPromise]).then(
function(args) {
- return launchWithEntries(args[0].entries.concat(args[1].entries));
+ return launchWithEntries(args[0].entries.concat(args[1].entries)
+ .concat(args[2].entries).concat(args[3].entries));
}));
}
@@ -210,5 +273,7 @@ function testForMixedFiles() {
chrome.test.runTests([
testForLocalFiles,
testForDriveFiles,
- testForMixedFiles
+ testForLocalDirectories,
+ testForDriveDirectories,
+ testForMixedFilesAndDirectories,
]);
diff --git a/extensions/browser/api/app_runtime/app_runtime_api.cc b/extensions/browser/api/app_runtime/app_runtime_api.cc
index 67f3ead..fca709b 100644
--- a/extensions/browser/api/app_runtime/app_runtime_api.cc
+++ b/extensions/browser/api/app_runtime/app_runtime_api.cc
@@ -11,6 +11,7 @@
#include "base/metrics/histogram.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "extensions/browser/entry_info.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extensions_browser_client.h"
@@ -162,7 +163,7 @@ void AppRuntimeEventRouter::DispatchOnLaunchedEventWithFileEntries(
BrowserContext* context,
const Extension* extension,
const std::string& handler_id,
- const std::vector<std::string>& mime_types,
+ const std::vector<EntryInfo>& entries,
const std::vector<GrantedFileEntry>& file_entries) {
// TODO(sergeygs): Use the same way of creating an event (using the generated
// boilerplate) as below in DispatchOnLaunchedEventWithUrl.
@@ -176,14 +177,15 @@ void AppRuntimeEventRouter::DispatchOnLaunchedEventWithFileEntries(
}
scoped_ptr<base::ListValue> items(new base::ListValue);
- DCHECK(file_entries.size() == mime_types.size());
+ DCHECK(file_entries.size() == entries.size());
for (size_t i = 0; i < file_entries.size(); ++i) {
scoped_ptr<base::DictionaryValue> launch_item(new base::DictionaryValue);
launch_item->SetString("fileSystemId", file_entries[i].filesystem_id);
launch_item->SetString("baseName", file_entries[i].registered_name);
- launch_item->SetString("mimeType", mime_types[i]);
+ launch_item->SetString("mimeType", entries[i].mime_type);
launch_item->SetString("entryId", file_entries[i].id);
+ launch_item->SetBoolean("isDirectory", entries[i].is_directory);
items->Append(launch_item.release());
}
launch_data->Set("items", items.release());
diff --git a/extensions/browser/api/app_runtime/app_runtime_api.h b/extensions/browser/api/app_runtime/app_runtime_api.h
index 38f6fd6..35a28d2 100644
--- a/extensions/browser/api/app_runtime/app_runtime_api.h
+++ b/extensions/browser/api/app_runtime/app_runtime_api.h
@@ -25,6 +25,7 @@ class WebContents;
namespace extensions {
class Extension;
+struct EntryInfo;
struct GrantedFileEntry;
class AppRuntimeEventRouter {
@@ -64,7 +65,7 @@ class AppRuntimeEventRouter {
content::BrowserContext* context,
const Extension* extension,
const std::string& handler_id,
- const std::vector<std::string>& mime_types,
+ const std::vector<EntryInfo>& entries,
const std::vector<GrantedFileEntry>& file_entries);
// |handler_id| corresponds to the id of the url_handlers item
diff --git a/extensions/browser/entry_info.h b/extensions/browser/entry_info.h
new file mode 100644
index 0000000..eb5f5d5
--- /dev/null
+++ b/extensions/browser/entry_info.h
@@ -0,0 +1,28 @@
+// Copyright 2016 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 EXTENSIONS_BROWSER_ENTRY_INFO_H_
+#define EXTENSIONS_BROWSER_ENTRY_INFO_H_
+
+#include <string>
+
+#include "base/files/file_path.h"
+
+namespace extensions {
+
+// Contains information about files and directories.
+struct EntryInfo {
+ EntryInfo(const base::FilePath& path,
+ const std::string& mime_type,
+ bool is_directory)
+ : path(path), mime_type(mime_type), is_directory(is_directory) {}
+
+ base::FilePath path;
+ std::string mime_type; // Useful only if is_directory = false.
+ bool is_directory;
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_ENTRY_INFO_H_
diff --git a/extensions/common/api/app_runtime.idl b/extensions/common/api/app_runtime.idl
index e3339bd..daf953c 100644
--- a/extensions/common/api/app_runtime.idl
+++ b/extensions/common/api/app_runtime.idl
@@ -8,11 +8,11 @@
namespace app.runtime {
[inline_doc] dictionary LaunchItem {
- // FileEntry for the file.
- [instanceOf=FileEntry] object entry;
+ // Entry for the item.
+ [instanceOf=Entry] object entry;
// The MIME type of the file.
- DOMString type;
+ DOMString? type;
};
// Enumeration of app launch sources.
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc
index 7195dda..85775ef 100644
--- a/extensions/common/manifest_constants.cc
+++ b/extensions/common/manifest_constants.cc
@@ -392,8 +392,11 @@ const char kInvalidFileHandlerExtension[] =
"Invalid value for 'file_handlers[*].extensions'.";
const char kInvalidFileHandlerExtensionElement[] =
"Invalid value for 'file_handlers[*].extensions[*]'.";
+const char kInvalidFileHandlerIncludeDirectories[] =
+ "Invalid value for 'include_directories'.";
const char kInvalidFileHandlerNoTypeOrExtension[] =
- "'file_handlers[*]' must contain a non-empty 'types' or 'extensions'.";
+ "'file_handlers[*]' must contain a non-empty 'types', 'extensions' "
+ "or 'include_directories'.";
const char kInvalidFileHandlerType[] =
"Invalid value for 'file_handlers[*].types'.";
const char kInvalidFileHandlerTypeElement[] =
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h
index 9051aa8..81f8fc5 100644
--- a/extensions/common/manifest_constants.h
+++ b/extensions/common/manifest_constants.h
@@ -318,6 +318,7 @@ extern const char kInvalidFileHandlers[];
extern const char kInvalidFileHandlersTooManyTypesAndExtensions[];
extern const char kInvalidFileHandlerExtension[];
extern const char kInvalidFileHandlerExtensionElement[];
+extern const char kInvalidFileHandlerIncludeDirectories[];
extern const char kInvalidFileHandlerNoTypeOrExtension[];
extern const char kInvalidFileHandlerType[];
extern const char kInvalidFileHandlerTypeElement[];
diff --git a/extensions/common/manifest_handlers/file_handler_info.cc b/extensions/common/manifest_handlers/file_handler_info.cc
index 9b0989a..b525c14 100644
--- a/extensions/common/manifest_handlers/file_handler_info.cc
+++ b/extensions/common/manifest_handlers/file_handler_info.cc
@@ -25,7 +25,7 @@ const int kMaxTypeAndExtensionHandlers = 200;
const char kNotRecognized[] = "'%s' is not a recognized file handler property.";
}
-FileHandlerInfo::FileHandlerInfo() {}
+FileHandlerInfo::FileHandlerInfo() : include_directories(false) {}
FileHandlerInfo::~FileHandlerInfo() {}
FileHandlers::FileHandlers() {}
@@ -71,8 +71,18 @@ bool LoadFileHandler(const std::string& handler_id,
return false;
}
+ handler.include_directories = false;
+ if (handler_info.HasKey("include_directories") &&
+ !handler_info.GetBoolean("include_directories",
+ &handler.include_directories)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidFileHandlerIncludeDirectories, handler_id);
+ return false;
+ }
+
if ((!mime_types || mime_types->empty()) &&
- (!file_extensions || file_extensions->empty())) {
+ (!file_extensions || file_extensions->empty()) &&
+ !handler.include_directories) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidFileHandlerNoTypeOrExtension,
handler_id);
diff --git a/extensions/common/manifest_handlers/file_handler_info.h b/extensions/common/manifest_handlers/file_handler_info.h
index ac458e1..ac9e51d 100644
--- a/extensions/common/manifest_handlers/file_handler_info.h
+++ b/extensions/common/manifest_handlers/file_handler_info.h
@@ -27,6 +27,9 @@ struct FileHandlerInfo {
// MIME types associated with this handler.
std::set<std::string> types;
+
+ // True if the handler can manage directories.
+ bool include_directories;
};
typedef std::vector<FileHandlerInfo> FileHandlersInfo;
diff --git a/extensions/renderer/resources/app_runtime_custom_bindings.js b/extensions/renderer/resources/app_runtime_custom_bindings.js
index 0364b66..3f0dbd2 100644
--- a/extensions/renderer/resources/app_runtime_custom_bindings.js
+++ b/extensions/renderer/resources/app_runtime_custom_bindings.js
@@ -57,12 +57,21 @@ eventBindings.registerArgumentMassager('app.runtime.onLaunched',
};
$Array.forEach(launchData.items, function(item) {
var fs = GetIsolatedFileSystem(item.fileSystemId);
- fs.root.getFile(item.baseName, {}, function(fileEntry) {
- entryIdManager.registerEntry(item.entryId, fileEntry);
- itemLoaded(null, { entry: fileEntry, type: item.mimeType });
- }, function(fileError) {
- itemLoaded(fileError);
- });
+ if (item.isDirectory) {
+ fs.root.getDirectory(item.baseName, {}, function(dirEntry) {
+ entryIdManager.registerEntry(item.entryId, dirEntry);
+ itemLoaded(null, {entry: dirEntry});
+ }, function(fileError) {
+ itemLoaded(fileError);
+ });
+ } else {
+ fs.root.getFile(item.baseName, {}, function(fileEntry) {
+ entryIdManager.registerEntry(item.entryId, fileEntry);
+ itemLoaded(null, {entry: fileEntry, type: item.mimeType});
+ }, function(fileError) {
+ itemLoaded(fileError);
+ });
+ }
});
} else {
// Default case. This currently covers an onLaunched corresponding to
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.js b/ui/file_manager/file_manager/foreground/js/file_tasks.js
index efa27d0..a1c2566 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -554,12 +554,16 @@ FileTasks.prototype.executeInternal_ = function(taskId) {
* @private
*/
FileTasks.prototype.checkAvailability_ = function(callback) {
- var areAll = function(props, name) {
- var isOne = function(e) {
+ var areAll = function(entries, props, name) {
+ // TODO(cmihail): Make files in directories available offline.
+ // See http://crbug.com/569767.
+ var okEntriesNum = 0;
+ for (var i = 0; i < entries.length; i++) {
// If got no properties, we safely assume that item is available.
- return !e || e[name];
- };
- return props.filter(isOne).length === props.length;
+ if (props[i] && (props[i][name] || entries[i].isDirectory))
+ okEntriesNum++;
+ }
+ return okEntriesNum === props.length;
};
var containsDriveEntries =
@@ -583,7 +587,7 @@ FileTasks.prototype.checkAvailability_ = function(callback) {
if (isDriveOffline) {
this.metadataModel_.get(this.entries_, ['availableOffline', 'hosted']).then(
function(props) {
- if (areAll(props, 'availableOffline')) {
+ if (areAll(this.entries_, props, 'availableOffline')) {
callback();
return;
}
@@ -611,7 +615,7 @@ FileTasks.prototype.checkAvailability_ = function(callback) {
if (isOnMetered) {
this.metadataModel_.get(this.entries_, ['availableWhenMetered', 'size'])
.then(function(props) {
- if (areAll(props, 'availableWhenMetered')) {
+ if (areAll(this.entries_, props, 'availableWhenMetered')) {
callback();
return;
}
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller.js b/ui/file_manager/file_manager/foreground/js/task_controller.js
index c38c41c..e011fa0 100644
--- a/ui/file_manager/file_manager/foreground/js/task_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/task_controller.js
@@ -263,7 +263,7 @@ TaskController.prototype.onSelectionChanged_ = function() {
// Caller of update context menu task items.
// FileSelectionHandler.EventType.CHANGE
if (this.dialogType_ === DialogType.FULL_PAGE &&
- selection.directoryCount === 0 && selection.fileCount > 0) {
+ (selection.directoryCount > 0 || selection.fileCount > 0)) {
// Show disabled items for position calculation of the menu. They will be
// overridden in this.updateFileSelectionAsync().
this.updateContextMenuTaskItems_(
@@ -281,7 +281,7 @@ TaskController.prototype.onSelectionChanged_ = function() {
TaskController.prototype.onSelectionChangeThrottled_ = function() {
var selection = this.selectionHandler_.selection;
if (this.dialogType_ === DialogType.FULL_PAGE &&
- selection.directoryCount === 0 && selection.fileCount > 0) {
+ (selection.directoryCount > 0 || selection.fileCount > 0)) {
this.getFileTasks()
.then(function(tasks) {
tasks.display(this.ui_.taskMenuButton);