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

Unified Diff: chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.cc

Issue 2574173002: mediaview: Implement ArcDocumentsProviderRoot. (Closed)
Patch Set: Revive unit tests & fixed build breakage. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.cc
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.cc b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.cc
index aa1b86890526123ae9f5168754b6ce218dc540b8..89159806a01476b873783259ed228ffe53344e6b 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.cc
+++ b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.cc
@@ -4,16 +4,75 @@
#include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.h"
+#include <algorithm>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/files/file.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.h"
+#include "chrome/browser/chromeos/arc/fileapi/arc_file_system_instance_util.h"
#include "content/public/browser/browser_thread.h"
+#include "net/base/mime_util.h"
using content::BrowserThread;
+using EntryList = storage::AsyncFileUtil::EntryList;
namespace arc {
+namespace {
+
+// Computes a file name for a document.
+base::FilePath::StringType GetFileNameForDocument(
+ const mojom::DocumentPtr& document) {
+ base::FilePath::StringType filename = document->display_name;
+
+ // Replace path separators appearing in the file name.
+ // Chrome OS is POSIX and kSeparators is "/".
+ base::ReplaceChars(filename, base::FilePath::kSeparators, "_", &filename);
+
+ // Do not allow an empty file name and all-dots file names.
+ if (filename.empty() ||
+ filename.find_first_not_of('.', 0) == std::string::npos) {
+ filename = "_";
+ }
+
+ // Since Chrome detects MIME type from file name extensions, we need to change
+ // the file name extension of the document if it does not match with its MIME
+ // type.
+ // For example, Audio Media Provider presents a music file with its title as
+ // the file name.
+ base::FilePath::StringType extension =
+ base::ToLowerASCII(base::FilePath(filename).Extension());
+ if (!extension.empty())
+ extension = extension.substr(1); // Strip the leading dot.
+ std::vector<base::FilePath::StringType> possible_extensions;
+ net::GetExtensionsForMimeType(document->mime_type, &possible_extensions);
+ if (!possible_extensions.empty() &&
+ std::find(possible_extensions.begin(), possible_extensions.end(),
+ extension) == possible_extensions.end()) {
+ std::string new_extension;
hashimoto 2016/12/20 04:55:07 This should be base::FilePath::StringType.
Shuhei Takahashi 2016/12/20 06:08:24 Done.
+ if (!net::GetPreferredExtensionForMimeType(document->mime_type,
+ &new_extension)) {
+ new_extension = possible_extensions[0];
+ }
+ filename = base::FilePath(filename).AddExtension(new_extension).value();
+ }
+
+ return filename;
+}
+
+} // namespace
+
ArcDocumentsProviderRoot::ArcDocumentsProviderRoot(
const std::string& authority,
- const std::string& root_document_id) {}
+ const std::string& root_document_id)
+ : authority_(authority),
+ root_document_id_(root_document_id),
+ weak_ptr_factory_(this) {}
ArcDocumentsProviderRoot::~ArcDocumentsProviderRoot() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -23,14 +82,174 @@ void ArcDocumentsProviderRoot::GetFileInfo(
const base::FilePath& path,
const GetFileInfoCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- NOTIMPLEMENTED(); // TODO(crbug.com/671511): Implement this function.
+ ResolveToDocumentId(
+ path, base::Bind(&ArcDocumentsProviderRoot::GetFileInfoWithDocumentId,
+ weak_ptr_factory_.GetWeakPtr(), callback));
}
void ArcDocumentsProviderRoot::ReadDirectory(
const base::FilePath& path,
const ReadDirectoryCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- NOTIMPLEMENTED(); // TODO(crbug.com/671511): Implement this function.
+ ResolveToDocumentId(
+ path, base::Bind(&ArcDocumentsProviderRoot::ReadDirectoryWithDocumentId,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void ArcDocumentsProviderRoot::GetFileInfoWithDocumentId(
+ const GetFileInfoCallback& callback,
+ const std::string& document_id) {
+ if (document_id.empty()) {
+ callback.Run(base::File::FILE_ERROR_NOT_FOUND, base::File::Info());
+ return;
+ }
+ file_system_instance_util::GetDocumentOnIOThread(
+ authority_, document_id,
+ base::Bind(&ArcDocumentsProviderRoot::GetFileInfoWithDocument,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void ArcDocumentsProviderRoot::GetFileInfoWithDocument(
+ const GetFileInfoCallback& callback,
+ mojom::DocumentPtr document) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (document.is_null()) {
+ callback.Run(base::File::FILE_ERROR_NOT_FOUND, base::File::Info());
+ return;
+ }
+ base::File::Info info;
+ info.size = document->size;
+ info.is_directory = document->mime_type == kAndroidDirectoryMimeType;
+ info.is_symbolic_link = false;
+ info.last_modified = info.last_accessed = info.creation_time =
+ base::Time::FromJavaTime(document->last_modified);
+ callback.Run(base::File::FILE_OK, info);
+}
+
+void ArcDocumentsProviderRoot::ReadDirectoryWithDocumentId(
+ const ReadDirectoryCallback& callback,
+ const std::string& document_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (document_id.empty()) {
+ callback.Run(base::File::FILE_ERROR_NOT_FOUND, EntryList(),
+ false /* has_more */);
+ return;
+ }
+ ReadDirectoryInternal(
+ document_id,
+ base::Bind(&ArcDocumentsProviderRoot::ReadDirectoryWithNameMapping,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void ArcDocumentsProviderRoot::ReadDirectoryWithNameMapping(
+ const ReadDirectoryCallback& callback,
+ NameMapping mapping) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ std::vector<storage::DirectoryEntry> entry_list;
+ for (const auto& pair : mapping) {
+ entry_list.emplace_back(pair.first, pair.second.is_directory
+ ? storage::DirectoryEntry::DIRECTORY
+ : storage::DirectoryEntry::FILE);
+ }
+ callback.Run(base::File::FILE_OK, entry_list, false /* has_more */);
+}
+
+void ArcDocumentsProviderRoot::ResolveToDocumentId(
+ const base::FilePath& path,
+ const ResolveToDocumentIdCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ std::vector<base::FilePath::StringType> components;
+ path.GetComponents(&components);
+ ResolveToDocumentIdRecursively(root_document_id_, components, callback);
+}
+
+void ArcDocumentsProviderRoot::ResolveToDocumentIdRecursively(
+ const std::string& document_id,
+ const std::vector<base::FilePath::StringType>& components,
+ const ResolveToDocumentIdCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (components.empty()) {
+ callback.Run(document_id);
+ return;
+ }
+ ReadDirectoryInternal(
+ document_id,
+ base::Bind(&ArcDocumentsProviderRoot::
+ ResolveToDocumentIdRecursivelyWithNameMapping,
+ weak_ptr_factory_.GetWeakPtr(), components, callback));
+}
+
+void ArcDocumentsProviderRoot::ResolveToDocumentIdRecursivelyWithNameMapping(
+ const std::vector<base::FilePath::StringType>& components,
+ const ResolveToDocumentIdCallback& callback,
+ NameMapping mapping) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!components.empty());
+ auto iter = mapping.find(components[0]);
+ if (iter == mapping.end()) {
+ callback.Run(std::string());
+ return;
+ }
+ ResolveToDocumentIdRecursively(iter->second.document_id,
+ std::vector<base::FilePath::StringType>(
+ components.begin() + 1, components.end()),
+ callback);
+}
+
+void ArcDocumentsProviderRoot::ReadDirectoryInternal(
+ const std::string& document_id,
+ const ReadDirectoryInternalCallback& callback) {
+ file_system_instance_util::GetChildDocumentsOnIOThread(
+ authority_, document_id,
+ base::Bind(
+ &ArcDocumentsProviderRoot::ReadDirectoryInternalWithChildDocuments,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void ArcDocumentsProviderRoot::ReadDirectoryInternalWithChildDocuments(
+ const ReadDirectoryInternalCallback& callback,
+ base::Optional<std::vector<mojom::DocumentPtr>> maybe_children) {
+ if (!maybe_children) {
+ callback.Run(NameMapping());
hashimoto 2016/12/20 04:55:07 ReadDirectoryInternal cannot return errors when th
Shuhei Takahashi 2016/12/20 06:08:24 Makes sense, let's return errors from ReadDirector
+ return;
+ }
+ std::vector<mojom::DocumentPtr>& children = maybe_children.value();
+
+ // Sort entries to keep the mapping stable as far as possible.
+ std::sort(children.begin(), children.end(),
+ [](const mojom::DocumentPtr& a, const mojom::DocumentPtr& b) {
+ return a->document_id < b->document_id;
+ });
+
+ NameMapping mapping;
+ std::map<base::FilePath::StringType, int> suffix_counters;
+
+ for (const mojom::DocumentPtr& document : children) {
+ base::FilePath::StringType filename = GetFileNameForDocument(document);
+
+ if (mapping.count(filename) > 0) {
+ // Resolve a conflict by adding a suffix.
+ int& suffix_counter = suffix_counters[filename];
+ while (true) {
+ ++suffix_counter;
+ std::string suffix = base::StringPrintf(" %d", suffix_counter);
hashimoto 2016/12/20 04:55:07 Drive code uses "(n)" instead of "n" as suffix. It
Shuhei Takahashi 2016/12/20 06:08:24 Changed to (n). Yes, it would be good if we can co
hashimoto 2016/12/20 06:24:18 Somewhere under components (probably a new directo
Shuhei Takahashi 2016/12/20 06:32:49 Thanks, filed crbug.com/675868.
+ base::FilePath::StringType new_filename =
+ base::FilePath(filename).InsertBeforeExtensionASCII(suffix).value();
+ if (mapping.count(new_filename) == 0) {
+ filename = new_filename;
+ break;
+ }
+ }
+ }
+
+ DCHECK_EQ(0u, mapping.count(filename));
+
+ mapping[filename] =
+ ThinDocument{document->document_id,
+ document->mime_type == kAndroidDirectoryMimeType};
+ }
+
+ callback.Run(std::move(mapping));
}
} // namespace arc

Powered by Google App Engine
This is Rietveld 408576698