OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/extensions/file_manager/file_handler_util.h" | 5 #include "chrome/browser/chromeos/extensions/file_manager/file_handler_util.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
9 #include "base/i18n/case_conversion.h" | 9 #include "base/i18n/case_conversion.h" |
10 #include "base/json/json_writer.h" | 10 #include "base/json/json_writer.h" |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 const char kTaskDrive[] = "drive"; | 58 const char kTaskDrive[] = "drive"; |
59 const char kTaskApp[] = "app"; | 59 const char kTaskApp[] = "app"; |
60 | 60 |
61 namespace { | 61 namespace { |
62 | 62 |
63 // Legacy Drive task extension prefix, used by CrackTaskID. | 63 // Legacy Drive task extension prefix, used by CrackTaskID. |
64 const char kDriveTaskExtensionPrefix[] = "drive-app:"; | 64 const char kDriveTaskExtensionPrefix[] = "drive-app:"; |
65 const size_t kDriveTaskExtensionPrefixLength = | 65 const size_t kDriveTaskExtensionPrefixLength = |
66 arraysize(kDriveTaskExtensionPrefix) - 1; | 66 arraysize(kDriveTaskExtensionPrefix) - 1; |
67 | 67 |
68 typedef std::set<const FileBrowserHandler*> FileBrowserHandlerSet; | |
69 | |
70 const int kReadWriteFilePermissions = base::PLATFORM_FILE_OPEN | | 68 const int kReadWriteFilePermissions = base::PLATFORM_FILE_OPEN | |
71 base::PLATFORM_FILE_CREATE | | 69 base::PLATFORM_FILE_CREATE | |
72 base::PLATFORM_FILE_OPEN_ALWAYS | | 70 base::PLATFORM_FILE_OPEN_ALWAYS | |
73 base::PLATFORM_FILE_CREATE_ALWAYS | | 71 base::PLATFORM_FILE_CREATE_ALWAYS | |
74 base::PLATFORM_FILE_OPEN_TRUNCATED | | 72 base::PLATFORM_FILE_OPEN_TRUNCATED | |
75 base::PLATFORM_FILE_READ | | 73 base::PLATFORM_FILE_READ | |
76 base::PLATFORM_FILE_WRITE | | 74 base::PLATFORM_FILE_WRITE | |
77 base::PLATFORM_FILE_EXCLUSIVE_READ | | 75 base::PLATFORM_FILE_EXCLUSIVE_READ | |
78 base::PLATFORM_FILE_EXCLUSIVE_WRITE | | 76 base::PLATFORM_FILE_EXCLUSIVE_WRITE | |
79 base::PLATFORM_FILE_ASYNC | | 77 base::PLATFORM_FILE_ASYNC | |
(...skipping 13 matching lines...) Expand all Loading... |
93 extensions::ExtensionSystem::Get(profile)->process_manager(); | 91 extensions::ExtensionSystem::Get(profile)->process_manager(); |
94 | 92 |
95 SiteInstance* site_instance = manager->GetSiteInstanceForURL(extension_url); | 93 SiteInstance* site_instance = manager->GetSiteInstanceForURL(extension_url); |
96 if (!site_instance || !site_instance->HasProcess()) | 94 if (!site_instance || !site_instance->HasProcess()) |
97 return -1; | 95 return -1; |
98 content::RenderProcessHost* process = site_instance->GetProcess(); | 96 content::RenderProcessHost* process = site_instance->GetProcess(); |
99 | 97 |
100 return process->GetID(); | 98 return process->GetID(); |
101 } | 99 } |
102 | 100 |
103 bool IsBuiltinTask(const FileBrowserHandler* task) { | 101 // Returns true if the task should be used as a fallback. Such tasks are |
| 102 // Files.app's internal handlers as well as quick office extensions. |
| 103 bool IsFallbackTask(const FileBrowserHandler* task) { |
104 return (task->extension_id() == kFileBrowserDomain || | 104 return (task->extension_id() == kFileBrowserDomain || |
105 task->extension_id() == | 105 task->extension_id() == |
106 extension_misc::kQuickOfficeComponentExtensionId || | 106 extension_misc::kQuickOfficeComponentExtensionId || |
107 task->extension_id() == extension_misc::kQuickOfficeDevExtensionId || | 107 task->extension_id() == extension_misc::kQuickOfficeDevExtensionId || |
108 task->extension_id() == extension_misc::kQuickOfficeExtensionId); | 108 task->extension_id() == extension_misc::kQuickOfficeExtensionId); |
109 } | 109 } |
110 | 110 |
111 bool MatchesAllURLs(const FileBrowserHandler* handler) { | |
112 const std::set<URLPattern>& patterns = | |
113 handler->file_url_patterns().patterns(); | |
114 for (std::set<URLPattern>::const_iterator it = patterns.begin(); | |
115 it != patterns.end(); | |
116 ++it) { | |
117 if (it->match_all_urls()) | |
118 return true; | |
119 } | |
120 return false; | |
121 } | |
122 | |
123 const FileBrowserHandler* FindFileBrowserHandler(const Extension* extension, | 111 const FileBrowserHandler* FindFileBrowserHandler(const Extension* extension, |
124 const std::string& action_id) { | 112 const std::string& action_id) { |
125 FileBrowserHandler::List* handler_list = | 113 FileBrowserHandler::List* handler_list = |
126 FileBrowserHandler::GetHandlers(extension); | 114 FileBrowserHandler::GetHandlers(extension); |
127 for (FileBrowserHandler::List::const_iterator action_iter = | 115 for (FileBrowserHandler::List::const_iterator action_iter = |
128 handler_list->begin(); | 116 handler_list->begin(); |
129 action_iter != handler_list->end(); | 117 action_iter != handler_list->end(); |
130 ++action_iter) { | 118 ++action_iter) { |
131 if (action_iter->get()->id() == action_id) | 119 if (action_iter->get()->id() == action_id) |
132 return action_iter->get(); | 120 return action_iter->get(); |
(...skipping 20 matching lines...) Expand all Loading... |
153 std::string EscapedUtf8ToLower(const std::string& str) { | 141 std::string EscapedUtf8ToLower(const std::string& str) { |
154 string16 utf16 = UTF8ToUTF16( | 142 string16 utf16 = UTF8ToUTF16( |
155 net::UnescapeURLComponent(str, net::UnescapeRule::NORMAL)); | 143 net::UnescapeURLComponent(str, net::UnescapeRule::NORMAL)); |
156 return net::EscapeUrlEncodedData( | 144 return net::EscapeUrlEncodedData( |
157 UTF16ToUTF8(base::i18n::ToLower(utf16)), | 145 UTF16ToUTF8(base::i18n::ToLower(utf16)), |
158 false /* do not replace space with plus */); | 146 false /* do not replace space with plus */); |
159 } | 147 } |
160 | 148 |
161 bool GetFileBrowserHandlers(Profile* profile, | 149 bool GetFileBrowserHandlers(Profile* profile, |
162 const GURL& selected_file_url, | 150 const GURL& selected_file_url, |
163 FileBrowserHandlerSet* results) { | 151 FileBrowserHandlerList* results) { |
164 ExtensionService* service = | 152 ExtensionService* service = |
165 extensions::ExtensionSystem::Get(profile)->extension_service(); | 153 extensions::ExtensionSystem::Get(profile)->extension_service(); |
166 if (!service) | 154 if (!service) |
167 return false; // In unit-tests, we may not have an ExtensionService. | 155 return false; // In unit-tests, we may not have an ExtensionService. |
168 | 156 |
169 // We need case-insensitive matching, and pattern in the handler is already | 157 // We need case-insensitive matching, and pattern in the handler is already |
170 // in lower case. | 158 // in lower case. |
171 const GURL lowercase_url(EscapedUtf8ToLower(selected_file_url.spec())); | 159 const GURL lowercase_url(EscapedUtf8ToLower(selected_file_url.spec())); |
172 | 160 |
173 for (ExtensionSet::const_iterator iter = service->extensions()->begin(); | 161 for (ExtensionSet::const_iterator iter = service->extensions()->begin(); |
174 iter != service->extensions()->end(); | 162 iter != service->extensions()->end(); |
175 ++iter) { | 163 ++iter) { |
176 const Extension* extension = *iter; | 164 const Extension* extension = *iter; |
177 if (profile->IsOffTheRecord() && | 165 if (profile->IsOffTheRecord() && |
178 !service->IsIncognitoEnabled(extension->id())) | 166 !service->IsIncognitoEnabled(extension->id())) |
179 continue; | 167 continue; |
180 | 168 |
181 FileBrowserHandler::List* handler_list = | 169 FileBrowserHandler::List* handler_list = |
182 FileBrowserHandler::GetHandlers(extension); | 170 FileBrowserHandler::GetHandlers(extension); |
183 if (!handler_list) | 171 if (!handler_list) |
184 continue; | 172 continue; |
185 for (FileBrowserHandler::List::const_iterator action_iter = | 173 for (FileBrowserHandler::List::const_iterator action_iter = |
186 handler_list->begin(); | 174 handler_list->begin(); |
187 action_iter != handler_list->end(); | 175 action_iter != handler_list->end(); |
188 ++action_iter) { | 176 ++action_iter) { |
189 const FileBrowserHandler* action = action_iter->get(); | 177 const FileBrowserHandler* action = action_iter->get(); |
190 if (!action->MatchesURL(lowercase_url)) | 178 if (!action->MatchesURL(lowercase_url)) |
191 continue; | 179 continue; |
192 | 180 |
193 results->insert(action_iter->get()); | 181 results->push_back(action_iter->get()); |
194 } | 182 } |
195 } | 183 } |
196 return true; | 184 return true; |
197 } | 185 } |
198 | 186 |
199 } // namespace | 187 } // namespace |
200 | 188 |
201 void UpdateDefaultTask(Profile* profile, | 189 void UpdateDefaultTask(Profile* profile, |
202 const std::string& task_id, | 190 const std::string& task_id, |
203 const std::set<std::string>& suffixes, | 191 const std::set<std::string>& suffixes, |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
323 *task_type == kTaskApp); | 311 *task_type == kTaskApp); |
324 } | 312 } |
325 | 313 |
326 if (action_id) | 314 if (action_id) |
327 *action_id = result[2]; | 315 *action_id = result[2]; |
328 | 316 |
329 return true; | 317 return true; |
330 } | 318 } |
331 | 319 |
332 // Find a specific handler in the handler list. | 320 // Find a specific handler in the handler list. |
333 FileBrowserHandlerSet::iterator FindHandler( | 321 FileBrowserHandlerList::iterator FindHandler( |
334 FileBrowserHandlerSet* handler_set, | 322 FileBrowserHandlerList* handler_list, |
335 const std::string& extension_id, | 323 const std::string& extension_id, |
336 const std::string& id) { | 324 const std::string& id) { |
337 FileBrowserHandlerSet::iterator iter = handler_set->begin(); | 325 FileBrowserHandlerList::iterator iter = handler_list->begin(); |
338 while (iter != handler_set->end() && | 326 while (iter != handler_list->end() && |
339 !((*iter)->extension_id() == extension_id && | 327 !((*iter)->extension_id() == extension_id && |
340 (*iter)->id() == id)) { | 328 (*iter)->id() == id)) { |
341 iter++; | 329 ++iter; |
342 } | 330 } |
343 return iter; | 331 return iter; |
344 } | 332 } |
345 | 333 |
346 // Given the list of selected files, returns array of file action tasks | 334 // Given the list of selected files, returns array of file action tasks |
347 // that are shared between them. | 335 // that are shared between them. |
348 void FindDefaultTasks(Profile* profile, | 336 void FindDefaultTasks(Profile* profile, |
349 const std::vector<base::FilePath>& files_list, | 337 const std::vector<base::FilePath>& files_list, |
350 const FileBrowserHandlerSet& common_tasks, | 338 const FileBrowserHandlerList& common_tasks, |
351 FileBrowserHandlerSet* default_tasks) { | 339 FileBrowserHandlerList* default_tasks) { |
352 DCHECK(default_tasks); | 340 DCHECK(default_tasks); |
353 default_tasks->clear(); | 341 default_tasks->clear(); |
354 | 342 |
355 std::set<std::string> default_ids; | 343 std::set<std::string> default_ids; |
356 for (std::vector<base::FilePath>::const_iterator it = files_list.begin(); | 344 for (std::vector<base::FilePath>::const_iterator it = files_list.begin(); |
357 it != files_list.end(); ++it) { | 345 it != files_list.end(); ++it) { |
358 std::string task_id = file_handler_util::GetDefaultTaskIdFromPrefs( | 346 std::string task_id = file_handler_util::GetDefaultTaskIdFromPrefs( |
359 profile, "", it->Extension()); | 347 profile, "", it->Extension()); |
360 if (!task_id.empty()) | 348 if (!task_id.empty()) |
361 default_ids.insert(task_id); | 349 default_ids.insert(task_id); |
362 } | 350 } |
363 | 351 |
364 const FileBrowserHandler* builtin_task = NULL; | 352 const FileBrowserHandler* fallback_task = NULL; |
365 // Convert the default task IDs collected above to one of the handler pointers | 353 // Convert the default task IDs collected above to one of the handler pointers |
366 // from common_tasks. | 354 // from common_tasks. |
367 for (FileBrowserHandlerSet::const_iterator task_iter = common_tasks.begin(); | 355 for (FileBrowserHandlerList::const_iterator task_iter = common_tasks.begin(); |
368 task_iter != common_tasks.end(); ++task_iter) { | 356 task_iter != common_tasks.end(); ++task_iter) { |
369 std::string task_id = MakeTaskID((*task_iter)->extension_id(), kTaskFile, | 357 std::string task_id = MakeTaskID((*task_iter)->extension_id(), kTaskFile, |
370 (*task_iter)->id()); | 358 (*task_iter)->id()); |
371 std::set<std::string>::iterator default_iter = default_ids.find(task_id); | 359 std::set<std::string>::iterator default_iter = default_ids.find(task_id); |
372 if (default_iter != default_ids.end()) { | 360 if (default_iter != default_ids.end()) { |
373 default_tasks->insert(*task_iter); | 361 default_tasks->push_back(*task_iter); |
374 continue; | 362 continue; |
375 } | 363 } |
376 | 364 |
377 // If it's a built in task, remember it. If there are no default tasks among | 365 // Remember the first fallback task. |
378 // common tasks, builtin task will be used as a fallback. | 366 if (!fallback_task && IsFallbackTask(*task_iter)) |
379 // Note that builtin tasks are not overlapping, so there can be at most one | 367 fallback_task = *task_iter; |
380 // builtin tasks for each set of files. | |
381 if (IsBuiltinTask(*task_iter)) | |
382 builtin_task = *task_iter; | |
383 } | 368 } |
384 | 369 |
385 // If there are no default tasks found, use builtin task (if found) as a | 370 // If there are no default tasks found, use fallback as default. |
386 // default. | 371 if (fallback_task && default_tasks->empty()) |
387 if (builtin_task && default_tasks->empty()) | 372 default_tasks->push_back(fallback_task); |
388 default_tasks->insert(builtin_task); | |
389 } | 373 } |
390 | 374 |
391 // Given the list of selected files, returns array of context menu tasks | 375 // Given the list of selected files, returns array of context menu tasks |
392 // that are shared | 376 // that are shared |
393 bool FindCommonTasks(Profile* profile, | 377 bool FindCommonTasks(Profile* profile, |
394 const std::vector<GURL>& files_list, | 378 const std::vector<GURL>& files_list, |
395 FileBrowserHandlerSet* common_tasks) { | 379 FileBrowserHandlerList* common_tasks) { |
396 DCHECK(common_tasks); | 380 DCHECK(common_tasks); |
397 common_tasks->clear(); | 381 common_tasks->clear(); |
398 | 382 |
399 FileBrowserHandlerSet common_task_set; | 383 FileBrowserHandlerList common_task_list; |
400 std::set<std::string> default_task_ids; | 384 std::set<std::string> default_task_ids; |
401 for (std::vector<GURL>::const_iterator it = files_list.begin(); | 385 for (std::vector<GURL>::const_iterator it = files_list.begin(); |
402 it != files_list.end(); ++it) { | 386 it != files_list.end(); ++it) { |
403 FileBrowserHandlerSet file_actions; | 387 FileBrowserHandlerList file_actions; |
404 if (!GetFileBrowserHandlers(profile, *it, &file_actions)) | 388 if (!GetFileBrowserHandlers(profile, *it, &file_actions)) |
405 return false; | 389 return false; |
406 // If there is nothing to do for one file, the intersection of tasks for all | 390 // If there is nothing to do for one file, the intersection of tasks for all |
407 // files will be empty at the end, and so will the default tasks. | 391 // files will be empty at the end, and so will the default tasks. |
408 if (file_actions.empty()) | 392 if (file_actions.empty()) |
409 return true; | 393 return true; |
410 | 394 |
411 // For the very first file, just copy all the elements. | 395 // For the very first file, just copy all the elements. |
412 if (it == files_list.begin()) { | 396 if (it == files_list.begin()) { |
413 common_task_set = file_actions; | 397 common_task_list = file_actions; |
414 } else { | 398 } else { |
415 // For all additional files, find intersection between the accumulated and | 399 // For all additional files, find intersection between the accumulated and |
416 // file specific set. | 400 // file specific set. |
417 FileBrowserHandlerSet intersection; | 401 FileBrowserHandlerList intersection; |
418 std::set_intersection(common_task_set.begin(), common_task_set.end(), | 402 std::set_intersection(common_task_list.begin(), common_task_list.end(), |
419 file_actions.begin(), file_actions.end(), | 403 file_actions.begin(), file_actions.end(), |
420 std::inserter(intersection, | 404 std::back_inserter(intersection)); |
421 intersection.begin())); | 405 common_task_list = intersection; |
422 common_task_set = intersection; | 406 if (common_task_list.empty()) |
423 if (common_task_set.empty()) | |
424 return true; | 407 return true; |
425 } | 408 } |
426 } | 409 } |
427 | 410 |
428 FileBrowserHandlerSet::iterator watch_iter = FindHandler( | 411 FileBrowserHandlerList::iterator watch_iter = FindHandler( |
429 &common_task_set, kFileBrowserDomain, kFileBrowserWatchTaskId); | 412 &common_task_list, kFileBrowserDomain, kFileBrowserWatchTaskId); |
430 FileBrowserHandlerSet::iterator gallery_iter = FindHandler( | 413 FileBrowserHandlerList::iterator gallery_iter = FindHandler( |
431 &common_task_set, kFileBrowserDomain, kFileBrowserGalleryTaskId); | 414 &common_task_list, kFileBrowserDomain, kFileBrowserGalleryTaskId); |
432 if (watch_iter != common_task_set.end() && | 415 if (watch_iter != common_task_list.end() && |
433 gallery_iter != common_task_set.end()) { | 416 gallery_iter != common_task_list.end()) { |
434 // Both "watch" and "gallery" actions are applicable which means that the | 417 // Both "watch" and "gallery" actions are applicable which means that the |
435 // selection is all videos. Showing them both is confusing, so we only keep | 418 // selection is all videos. Showing them both is confusing, so we only keep |
436 // the one that makes more sense ("watch" for single selection, "gallery" | 419 // the one that makes more sense ("watch" for single selection, "gallery" |
437 // for multiple selection). | 420 // for multiple selection). |
438 if (files_list.size() == 1) | 421 if (files_list.size() == 1) |
439 common_task_set.erase(gallery_iter); | 422 common_task_list.erase(gallery_iter); |
440 else | 423 else |
441 common_task_set.erase(watch_iter); | 424 common_task_list.erase(watch_iter); |
442 } | 425 } |
443 | 426 |
444 common_tasks->swap(common_task_set); | 427 common_tasks->swap(common_task_list); |
445 return true; | 428 return true; |
446 } | 429 } |
447 | 430 |
448 bool GetTaskForURLAndPath(Profile* profile, | 431 bool GetTaskForURLAndPath(Profile* profile, |
449 const GURL& url, | 432 const GURL& url, |
450 const base::FilePath& file_path, | 433 const base::FilePath& file_path, |
451 const FileBrowserHandler** handler) { | 434 const FileBrowserHandler** handler) { |
452 std::vector<GURL> file_urls; | 435 std::vector<GURL> file_urls; |
453 file_urls.push_back(url); | 436 file_urls.push_back(url); |
454 | 437 |
455 FileBrowserHandlerSet default_tasks; | 438 FileBrowserHandlerList default_tasks; |
456 FileBrowserHandlerSet common_tasks; | 439 FileBrowserHandlerList common_tasks; |
457 if (!FindCommonTasks(profile, file_urls, &common_tasks)) | 440 if (!FindCommonTasks(profile, file_urls, &common_tasks)) |
458 return false; | 441 return false; |
459 | 442 |
460 if (common_tasks.empty()) | 443 if (common_tasks.empty()) |
461 return false; | 444 return false; |
462 | 445 |
463 std::vector<base::FilePath> file_paths; | 446 std::vector<base::FilePath> file_paths; |
464 file_paths.push_back(file_path); | 447 file_paths.push_back(file_path); |
465 | 448 |
466 FindDefaultTasks(profile, file_paths, common_tasks, &default_tasks); | 449 FindDefaultTasks(profile, file_paths, common_tasks, &default_tasks); |
(...skipping 521 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
988 extensions::LaunchPlatformAppWithFileHandler(profile(), GetExtension(), | 971 extensions::LaunchPlatformAppWithFileHandler(profile(), GetExtension(), |
989 action_id_, file_urls[i].path()); | 972 action_id_, file_urls[i].path()); |
990 } | 973 } |
991 | 974 |
992 if (!done.is_null()) | 975 if (!done.is_null()) |
993 done.Run(true); | 976 done.Run(true); |
994 return true; | 977 return true; |
995 } | 978 } |
996 | 979 |
997 } // namespace file_handler_util | 980 } // namespace file_handler_util |
OLD | NEW |