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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.h" 5 #include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.h"
6 6
7 #include <algorithm>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/files/file.h"
7 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.h"
17 #include "chrome/browser/chromeos/arc/fileapi/arc_file_system_instance_util.h"
8 #include "content/public/browser/browser_thread.h" 18 #include "content/public/browser/browser_thread.h"
19 #include "net/base/mime_util.h"
9 20
10 using content::BrowserThread; 21 using content::BrowserThread;
22 using EntryList = storage::AsyncFileUtil::EntryList;
11 23
12 namespace arc { 24 namespace arc {
13 25
26 namespace {
27
28 // Computes a file name for a document.
29 base::FilePath::StringType GetFileNameForDocument(
30 const mojom::DocumentPtr& document) {
31 base::FilePath::StringType filename = document->display_name;
32
33 // Replace path separators appearing in the file name.
34 // Chrome OS is POSIX and kSeparators is "/".
35 base::ReplaceChars(filename, base::FilePath::kSeparators, "_", &filename);
36
37 // Do not allow an empty file name and all-dots file names.
38 if (filename.empty() ||
39 filename.find_first_not_of('.', 0) == std::string::npos) {
40 filename = "_";
41 }
42
43 // Since Chrome detects MIME type from file name extensions, we need to change
44 // the file name extension of the document if it does not match with its MIME
45 // type.
46 // For example, Audio Media Provider presents a music file with its title as
47 // the file name.
48 base::FilePath::StringType extension =
49 base::ToLowerASCII(base::FilePath(filename).Extension());
50 if (!extension.empty())
51 extension = extension.substr(1); // Strip the leading dot.
52 std::vector<base::FilePath::StringType> possible_extensions;
53 net::GetExtensionsForMimeType(document->mime_type, &possible_extensions);
54 if (!possible_extensions.empty() &&
55 std::find(possible_extensions.begin(), possible_extensions.end(),
56 extension) == possible_extensions.end()) {
57 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.
58 if (!net::GetPreferredExtensionForMimeType(document->mime_type,
59 &new_extension)) {
60 new_extension = possible_extensions[0];
61 }
62 filename = base::FilePath(filename).AddExtension(new_extension).value();
63 }
64
65 return filename;
66 }
67
68 } // namespace
69
14 ArcDocumentsProviderRoot::ArcDocumentsProviderRoot( 70 ArcDocumentsProviderRoot::ArcDocumentsProviderRoot(
15 const std::string& authority, 71 const std::string& authority,
16 const std::string& root_document_id) {} 72 const std::string& root_document_id)
73 : authority_(authority),
74 root_document_id_(root_document_id),
75 weak_ptr_factory_(this) {}
17 76
18 ArcDocumentsProviderRoot::~ArcDocumentsProviderRoot() { 77 ArcDocumentsProviderRoot::~ArcDocumentsProviderRoot() {
19 DCHECK_CURRENTLY_ON(BrowserThread::IO); 78 DCHECK_CURRENTLY_ON(BrowserThread::IO);
20 } 79 }
21 80
22 void ArcDocumentsProviderRoot::GetFileInfo( 81 void ArcDocumentsProviderRoot::GetFileInfo(
23 const base::FilePath& path, 82 const base::FilePath& path,
24 const GetFileInfoCallback& callback) { 83 const GetFileInfoCallback& callback) {
25 DCHECK_CURRENTLY_ON(BrowserThread::IO); 84 DCHECK_CURRENTLY_ON(BrowserThread::IO);
26 NOTIMPLEMENTED(); // TODO(crbug.com/671511): Implement this function. 85 ResolveToDocumentId(
86 path, base::Bind(&ArcDocumentsProviderRoot::GetFileInfoWithDocumentId,
87 weak_ptr_factory_.GetWeakPtr(), callback));
27 } 88 }
28 89
29 void ArcDocumentsProviderRoot::ReadDirectory( 90 void ArcDocumentsProviderRoot::ReadDirectory(
30 const base::FilePath& path, 91 const base::FilePath& path,
31 const ReadDirectoryCallback& callback) { 92 const ReadDirectoryCallback& callback) {
32 DCHECK_CURRENTLY_ON(BrowserThread::IO); 93 DCHECK_CURRENTLY_ON(BrowserThread::IO);
33 NOTIMPLEMENTED(); // TODO(crbug.com/671511): Implement this function. 94 ResolveToDocumentId(
95 path, base::Bind(&ArcDocumentsProviderRoot::ReadDirectoryWithDocumentId,
96 weak_ptr_factory_.GetWeakPtr(), callback));
97 }
98
99 void ArcDocumentsProviderRoot::GetFileInfoWithDocumentId(
100 const GetFileInfoCallback& callback,
101 const std::string& document_id) {
102 if (document_id.empty()) {
103 callback.Run(base::File::FILE_ERROR_NOT_FOUND, base::File::Info());
104 return;
105 }
106 file_system_instance_util::GetDocumentOnIOThread(
107 authority_, document_id,
108 base::Bind(&ArcDocumentsProviderRoot::GetFileInfoWithDocument,
109 weak_ptr_factory_.GetWeakPtr(), callback));
110 }
111
112 void ArcDocumentsProviderRoot::GetFileInfoWithDocument(
113 const GetFileInfoCallback& callback,
114 mojom::DocumentPtr document) {
115 DCHECK_CURRENTLY_ON(BrowserThread::IO);
116 if (document.is_null()) {
117 callback.Run(base::File::FILE_ERROR_NOT_FOUND, base::File::Info());
118 return;
119 }
120 base::File::Info info;
121 info.size = document->size;
122 info.is_directory = document->mime_type == kAndroidDirectoryMimeType;
123 info.is_symbolic_link = false;
124 info.last_modified = info.last_accessed = info.creation_time =
125 base::Time::FromJavaTime(document->last_modified);
126 callback.Run(base::File::FILE_OK, info);
127 }
128
129 void ArcDocumentsProviderRoot::ReadDirectoryWithDocumentId(
130 const ReadDirectoryCallback& callback,
131 const std::string& document_id) {
132 DCHECK_CURRENTLY_ON(BrowserThread::IO);
133 if (document_id.empty()) {
134 callback.Run(base::File::FILE_ERROR_NOT_FOUND, EntryList(),
135 false /* has_more */);
136 return;
137 }
138 ReadDirectoryInternal(
139 document_id,
140 base::Bind(&ArcDocumentsProviderRoot::ReadDirectoryWithNameMapping,
141 weak_ptr_factory_.GetWeakPtr(), callback));
142 }
143
144 void ArcDocumentsProviderRoot::ReadDirectoryWithNameMapping(
145 const ReadDirectoryCallback& callback,
146 NameMapping mapping) {
147 DCHECK_CURRENTLY_ON(BrowserThread::IO);
148 std::vector<storage::DirectoryEntry> entry_list;
149 for (const auto& pair : mapping) {
150 entry_list.emplace_back(pair.first, pair.second.is_directory
151 ? storage::DirectoryEntry::DIRECTORY
152 : storage::DirectoryEntry::FILE);
153 }
154 callback.Run(base::File::FILE_OK, entry_list, false /* has_more */);
155 }
156
157 void ArcDocumentsProviderRoot::ResolveToDocumentId(
158 const base::FilePath& path,
159 const ResolveToDocumentIdCallback& callback) {
160 DCHECK_CURRENTLY_ON(BrowserThread::IO);
161 std::vector<base::FilePath::StringType> components;
162 path.GetComponents(&components);
163 ResolveToDocumentIdRecursively(root_document_id_, components, callback);
164 }
165
166 void ArcDocumentsProviderRoot::ResolveToDocumentIdRecursively(
167 const std::string& document_id,
168 const std::vector<base::FilePath::StringType>& components,
169 const ResolveToDocumentIdCallback& callback) {
170 DCHECK_CURRENTLY_ON(BrowserThread::IO);
171 if (components.empty()) {
172 callback.Run(document_id);
173 return;
174 }
175 ReadDirectoryInternal(
176 document_id,
177 base::Bind(&ArcDocumentsProviderRoot::
178 ResolveToDocumentIdRecursivelyWithNameMapping,
179 weak_ptr_factory_.GetWeakPtr(), components, callback));
180 }
181
182 void ArcDocumentsProviderRoot::ResolveToDocumentIdRecursivelyWithNameMapping(
183 const std::vector<base::FilePath::StringType>& components,
184 const ResolveToDocumentIdCallback& callback,
185 NameMapping mapping) {
186 DCHECK_CURRENTLY_ON(BrowserThread::IO);
187 DCHECK(!components.empty());
188 auto iter = mapping.find(components[0]);
189 if (iter == mapping.end()) {
190 callback.Run(std::string());
191 return;
192 }
193 ResolveToDocumentIdRecursively(iter->second.document_id,
194 std::vector<base::FilePath::StringType>(
195 components.begin() + 1, components.end()),
196 callback);
197 }
198
199 void ArcDocumentsProviderRoot::ReadDirectoryInternal(
200 const std::string& document_id,
201 const ReadDirectoryInternalCallback& callback) {
202 file_system_instance_util::GetChildDocumentsOnIOThread(
203 authority_, document_id,
204 base::Bind(
205 &ArcDocumentsProviderRoot::ReadDirectoryInternalWithChildDocuments,
206 weak_ptr_factory_.GetWeakPtr(), callback));
207 }
208
209 void ArcDocumentsProviderRoot::ReadDirectoryInternalWithChildDocuments(
210 const ReadDirectoryInternalCallback& callback,
211 base::Optional<std::vector<mojom::DocumentPtr>> maybe_children) {
212 if (!maybe_children) {
213 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
214 return;
215 }
216 std::vector<mojom::DocumentPtr>& children = maybe_children.value();
217
218 // Sort entries to keep the mapping stable as far as possible.
219 std::sort(children.begin(), children.end(),
220 [](const mojom::DocumentPtr& a, const mojom::DocumentPtr& b) {
221 return a->document_id < b->document_id;
222 });
223
224 NameMapping mapping;
225 std::map<base::FilePath::StringType, int> suffix_counters;
226
227 for (const mojom::DocumentPtr& document : children) {
228 base::FilePath::StringType filename = GetFileNameForDocument(document);
229
230 if (mapping.count(filename) > 0) {
231 // Resolve a conflict by adding a suffix.
232 int& suffix_counter = suffix_counters[filename];
233 while (true) {
234 ++suffix_counter;
235 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.
236 base::FilePath::StringType new_filename =
237 base::FilePath(filename).InsertBeforeExtensionASCII(suffix).value();
238 if (mapping.count(new_filename) == 0) {
239 filename = new_filename;
240 break;
241 }
242 }
243 }
244
245 DCHECK_EQ(0u, mapping.count(filename));
246
247 mapping[filename] =
248 ThinDocument{document->document_id,
249 document->mime_type == kAndroidDirectoryMimeType};
250 }
251
252 callback.Run(std::move(mapping));
34 } 253 }
35 254
36 } // namespace arc 255 } // namespace arc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698