| 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 |