Chromium Code Reviews| 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..00aac3e1a84f0924291b835a313efc8337e13e6a 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,43 @@ |
| #include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.h" |
| +#include "base/files/file.h" |
| #include "base/logging.h" |
| +#include "base/memory/ptr_util.h" |
| +#include "base/strings/string_util.h" |
| +#include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_document.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 "url/gurl.h" |
| using content::BrowserThread; |
| +using EntryList = storage::AsyncFileUtil::EntryList; |
| namespace arc { |
| +namespace { |
| + |
| +base::FilePath StripBaseName(const base::FilePath& path) { |
| + base::FilePath dirname = path.DirName(); |
| + // base::FilePath::DirName() returns kCurrentDirectory if the path does not |
| + // contain separators. In this case we want an empty path. |
| + if (dirname.value() == base::FilePath::kCurrentDirectory) { |
| + return base::FilePath(); |
| + } |
| + return dirname; |
| +} |
| + |
| +} // namespace |
| + |
| ArcDocumentsProviderRoot::ArcDocumentsProviderRoot( |
| const std::string& authority, |
| - const std::string& root_document_id) {} |
| + const std::string& root_document_id) |
| + : authority_(authority), |
| + root_directory_( |
| + base::MakeUnique<ArcDocumentsProviderDocument>(root_document_id, |
| + true)), |
| + weak_ptr_factory_(this) {} |
| ArcDocumentsProviderRoot::~ArcDocumentsProviderRoot() { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| @@ -23,14 +50,177 @@ void ArcDocumentsProviderRoot::GetFileInfo( |
| const base::FilePath& path, |
| const GetFileInfoCallback& callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| - NOTIMPLEMENTED(); // TODO(crbug.com/671511): Implement this function. |
| + // Skip a cache update if possible. |
| + ArcDocumentsProviderDocument* entry = root_directory_->Lookup(path); |
| + if (entry) { |
| + GetFileInfoAfterCacheUpdate(path, callback); |
| + return; |
| + } |
| + DCHECK(!path.empty()); |
| + UpdateDirectoryCacheUpTo( |
| + StripBaseName(path), |
| + base::Bind(&ArcDocumentsProviderRoot::GetFileInfoAfterCacheUpdate, |
|
Luis Héctor Chávez
2016/12/15 23:54:26
nit: #include "base/bind.h"
Shuhei Takahashi
2016/12/16 05:47:14
Done.
|
| + weak_ptr_factory_.GetWeakPtr(), path, callback)); |
| } |
| void ArcDocumentsProviderRoot::ReadDirectory( |
| const base::FilePath& path, |
| const ReadDirectoryCallback& callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| - NOTIMPLEMENTED(); // TODO(crbug.com/671511): Implement this function. |
| + if (path.empty()) { |
| + ReadDirectoryAfterCacheUpdate(path, callback); |
| + return; |
| + } |
| + UpdateDirectoryCacheUpTo( |
| + StripBaseName(path), |
| + base::Bind(&ArcDocumentsProviderRoot::ReadDirectoryAfterCacheUpdate, |
| + weak_ptr_factory_.GetWeakPtr(), path, callback)); |
| +} |
| + |
| +void ArcDocumentsProviderRoot::GetFileInfoAfterCacheUpdate( |
| + const base::FilePath& path, |
| + const GetFileInfoCallback& callback) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + ArcDocumentsProviderDocument* entry = root_directory_->Lookup(path); |
| + if (!entry) { |
| + callback.Run(base::File::FILE_ERROR_NOT_FOUND, base::File::Info()); |
| + return; |
| + } |
| + file_system_instance_util::GetDocumentOnIOThread( |
| + authority_, entry->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::FromDoubleT(document->last_modified / 1000.0); |
|
Luis Héctor Chávez
2016/12/15 23:54:26
nit: base::Time::FromJavaTime(document->last_modif
Shuhei Takahashi
2016/12/16 05:47:14
Thanks, that should be better.
|
| + callback.Run(base::File::FILE_OK, info); |
| +} |
| + |
| +void ArcDocumentsProviderRoot::ReadDirectoryAfterCacheUpdate( |
| + const base::FilePath& path, |
| + const ReadDirectoryCallback& callback) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + ArcDocumentsProviderDocument* parent_directory = |
| + root_directory_->Lookup(path); |
| + if (!parent_directory || !parent_directory->is_directory()) { |
| + callback.Run(base::File::FILE_ERROR_NOT_FOUND, EntryList(), |
| + false /* has_more */); |
| + return; |
| + } |
| + file_system_instance_util::GetChildDocumentsOnIOThread( |
| + authority_, parent_directory->document_id(), |
| + base::Bind(&ArcDocumentsProviderRoot::ReadDirectoryWithChildDocuments, |
| + weak_ptr_factory_.GetWeakPtr(), path, callback)); |
| +} |
| + |
| +void ArcDocumentsProviderRoot::ReadDirectoryWithChildDocuments( |
| + const base::FilePath& path, |
| + const ReadDirectoryCallback& callback, |
| + base::Optional<std::vector<mojom::DocumentPtr>> children) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + if (!children) { |
| + callback.Run(base::File::FILE_ERROR_NOT_FOUND, EntryList(), |
| + false /* has_more */); |
| + return; |
| + } |
| + |
| + ArcDocumentsProviderDocument* parent_directory = |
| + root_directory_->Lookup(path); |
| + if (!parent_directory || !parent_directory->is_directory()) { |
| + callback.Run(base::File::FILE_ERROR_NOT_FOUND, EntryList(), |
| + false /* has_more */); |
| + return; |
| + } |
| + parent_directory->UpdateWithChildDocuments(children.value()); |
| + |
| + std::vector<storage::DirectoryEntry> entry_list; |
| + for (const auto& pair : parent_directory->children()) { |
| + 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::UpdateDirectoryCacheUpTo( |
| + const base::FilePath& path, |
| + const base::Closure& callback) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + UpdateDirectoryCacheIter(base::FilePath(), path, callback); |
| +} |
| + |
| +void ArcDocumentsProviderRoot::UpdateDirectoryCacheIter( |
| + const base::FilePath& parent_directory_path, |
| + const base::FilePath& remaining_path, |
| + const base::Closure& callback) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + |
| + ArcDocumentsProviderDocument* parent_directory = |
| + root_directory_->Lookup(parent_directory_path); |
| + if (!parent_directory || !parent_directory->is_directory()) { |
| + callback.Run(); |
| + return; |
| + } |
| + |
| + file_system_instance_util::GetChildDocumentsOnIOThread( |
| + authority_, parent_directory->document_id(), |
| + base::Bind( |
| + &ArcDocumentsProviderRoot::UpdateDirectoryCacheIterWithChildDocuments, |
| + weak_ptr_factory_.GetWeakPtr(), parent_directory_path, remaining_path, |
| + callback)); |
| +} |
| + |
| +void ArcDocumentsProviderRoot::UpdateDirectoryCacheIterWithChildDocuments( |
| + const base::FilePath& parent_directory_path, |
| + const base::FilePath& remaining_path, |
| + const base::Closure& callback, |
| + base::Optional<std::vector<mojom::DocumentPtr>> children) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + if (!children) { |
| + callback.Run(); |
| + return; |
| + } |
| + |
| + ArcDocumentsProviderDocument* parent_directory = |
| + root_directory_->Lookup(parent_directory_path); |
| + if (!parent_directory || !parent_directory->is_directory()) { |
| + callback.Run(); |
| + return; |
| + } |
| + parent_directory->UpdateWithChildDocuments(children.value()); |
| + |
| + if (remaining_path.empty()) { |
| + callback.Run(); |
| + return; |
| + } |
| + |
| + using Components = std::vector<base::FilePath::StringType>; |
| + Components components; |
| + remaining_path.GetComponents(&components); |
| + DCHECK(!components.empty()); |
| + |
| + base::FilePath next_parent_directory_path = |
| + parent_directory_path.Append(components[0]); |
| + base::FilePath next_remaining_path = |
| + base::FilePath::FromUTF8Unsafe(base::JoinString( |
| + Components(components.begin() + 1, components.end()), "/")); |
| + |
| + UpdateDirectoryCacheIter(next_parent_directory_path, next_remaining_path, |
| + callback); |
| } |
| } // namespace arc |