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

Side by Side Diff: chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.cc

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

Powered by Google App Engine
This is Rietveld 408576698