Chromium Code Reviews| 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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 153 std::string EscapedUtf8ToLower(const std::string& str) { | 151 std::string EscapedUtf8ToLower(const std::string& str) { |
| 154 string16 utf16 = UTF8ToUTF16( | 152 string16 utf16 = UTF8ToUTF16( |
| 155 net::UnescapeURLComponent(str, net::UnescapeRule::NORMAL)); | 153 net::UnescapeURLComponent(str, net::UnescapeRule::NORMAL)); |
| 156 return net::EscapeUrlEncodedData( | 154 return net::EscapeUrlEncodedData( |
| 157 UTF16ToUTF8(base::i18n::ToLower(utf16)), | 155 UTF16ToUTF8(base::i18n::ToLower(utf16)), |
| 158 false /* do not replace space with plus */); | 156 false /* do not replace space with plus */); |
| 159 } | 157 } |
| 160 | 158 |
| 161 bool GetFileBrowserHandlers(Profile* profile, | 159 bool GetFileBrowserHandlers(Profile* profile, |
| 162 const GURL& selected_file_url, | 160 const GURL& selected_file_url, |
| 163 FileBrowserHandlerSet* results) { | 161 FileBrowserHandlerList* results) { |
| 164 ExtensionService* service = | 162 ExtensionService* service = |
| 165 extensions::ExtensionSystem::Get(profile)->extension_service(); | 163 extensions::ExtensionSystem::Get(profile)->extension_service(); |
| 166 if (!service) | 164 if (!service) |
| 167 return false; // In unit-tests, we may not have an ExtensionService. | 165 return false; // In unit-tests, we may not have an ExtensionService. |
| 168 | 166 |
| 169 // We need case-insensitive matching, and pattern in the handler is already | 167 // We need case-insensitive matching, and pattern in the handler is already |
| 170 // in lower case. | 168 // in lower case. |
| 171 const GURL lowercase_url(EscapedUtf8ToLower(selected_file_url.spec())); | 169 const GURL lowercase_url(EscapedUtf8ToLower(selected_file_url.spec())); |
| 172 | 170 |
| 173 for (ExtensionSet::const_iterator iter = service->extensions()->begin(); | 171 for (ExtensionSet::const_iterator iter = service->extensions()->begin(); |
| 174 iter != service->extensions()->end(); | 172 iter != service->extensions()->end(); |
| 175 ++iter) { | 173 ++iter) { |
| 176 const Extension* extension = *iter; | 174 const Extension* extension = *iter; |
| 177 if (profile->IsOffTheRecord() && | 175 if (profile->IsOffTheRecord() && |
| 178 !service->IsIncognitoEnabled(extension->id())) | 176 !service->IsIncognitoEnabled(extension->id())) |
| 179 continue; | 177 continue; |
| 180 | 178 |
| 181 FileBrowserHandler::List* handler_list = | 179 FileBrowserHandler::List* handler_list = |
| 182 FileBrowserHandler::GetHandlers(extension); | 180 FileBrowserHandler::GetHandlers(extension); |
| 183 if (!handler_list) | 181 if (!handler_list) |
| 184 continue; | 182 continue; |
| 185 for (FileBrowserHandler::List::const_iterator action_iter = | 183 for (FileBrowserHandler::List::const_iterator action_iter = |
| 186 handler_list->begin(); | 184 handler_list->begin(); |
| 187 action_iter != handler_list->end(); | 185 action_iter != handler_list->end(); |
| 188 ++action_iter) { | 186 ++action_iter) { |
| 189 const FileBrowserHandler* action = action_iter->get(); | 187 const FileBrowserHandler* action = action_iter->get(); |
| 190 if (!action->MatchesURL(lowercase_url)) | 188 if (!action->MatchesURL(lowercase_url)) |
| 191 continue; | 189 continue; |
| 192 | 190 |
| 193 results->insert(action_iter->get()); | 191 results->push_back(action_iter->get()); |
| 194 } | 192 } |
| 195 } | 193 } |
| 196 return true; | 194 return true; |
| 197 } | 195 } |
| 198 | 196 |
| 199 } // namespace | 197 } // namespace |
| 200 | 198 |
| 201 void UpdateDefaultTask(Profile* profile, | 199 void UpdateDefaultTask(Profile* profile, |
| 202 const std::string& task_id, | 200 const std::string& task_id, |
| 203 const std::set<std::string>& suffixes, | 201 const std::set<std::string>& suffixes, |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 323 *task_type == kTaskApp); | 321 *task_type == kTaskApp); |
| 324 } | 322 } |
| 325 | 323 |
| 326 if (action_id) | 324 if (action_id) |
| 327 *action_id = result[2]; | 325 *action_id = result[2]; |
| 328 | 326 |
| 329 return true; | 327 return true; |
| 330 } | 328 } |
| 331 | 329 |
| 332 // Find a specific handler in the handler list. | 330 // Find a specific handler in the handler list. |
| 333 FileBrowserHandlerSet::iterator FindHandler( | 331 FileBrowserHandlerList::iterator FindHandler( |
| 334 FileBrowserHandlerSet* handler_set, | 332 FileBrowserHandlerList* handler_list, |
| 335 const std::string& extension_id, | 333 const std::string& extension_id, |
| 336 const std::string& id) { | 334 const std::string& id) { |
| 337 FileBrowserHandlerSet::iterator iter = handler_set->begin(); | 335 FileBrowserHandlerList::iterator iter = handler_list->begin(); |
| 338 while (iter != handler_set->end() && | 336 while (iter != handler_list->end() && |
| 339 !((*iter)->extension_id() == extension_id && | 337 !((*iter)->extension_id() == extension_id && |
| 340 (*iter)->id() == id)) { | 338 (*iter)->id() == id)) { |
| 341 iter++; | 339 iter++; |
| 342 } | 340 } |
| 343 return iter; | 341 return iter; |
| 344 } | 342 } |
| 345 | 343 |
| 346 // Given the list of selected files, returns array of file action tasks | 344 // Given the list of selected files, returns array of file action tasks |
| 347 // that are shared between them. | 345 // that are shared between them. |
| 348 void FindDefaultTasks(Profile* profile, | 346 void FindDefaultTasks(Profile* profile, |
| 349 const std::vector<base::FilePath>& files_list, | 347 const std::vector<base::FilePath>& files_list, |
| 350 const FileBrowserHandlerSet& common_tasks, | 348 const FileBrowserHandlerList& common_tasks, |
| 351 FileBrowserHandlerSet* default_tasks) { | 349 FileBrowserHandlerList* default_tasks) { |
| 352 DCHECK(default_tasks); | 350 DCHECK(default_tasks); |
| 353 default_tasks->clear(); | 351 default_tasks->clear(); |
| 354 | 352 |
| 355 std::set<std::string> default_ids; | 353 std::set<std::string> default_ids; |
| 356 for (std::vector<base::FilePath>::const_iterator it = files_list.begin(); | 354 for (std::vector<base::FilePath>::const_iterator it = files_list.begin(); |
| 357 it != files_list.end(); ++it) { | 355 it != files_list.end(); ++it) { |
| 358 std::string task_id = file_handler_util::GetDefaultTaskIdFromPrefs( | 356 std::string task_id = file_handler_util::GetDefaultTaskIdFromPrefs( |
| 359 profile, "", it->Extension()); | 357 profile, "", it->Extension()); |
| 360 if (!task_id.empty()) | 358 if (!task_id.empty()) |
| 361 default_ids.insert(task_id); | 359 default_ids.insert(task_id); |
| 362 } | 360 } |
| 363 | 361 |
| 364 const FileBrowserHandler* builtin_task = NULL; | 362 const FileBrowserHandler* builtin_task = NULL; |
| 365 // Convert the default task IDs collected above to one of the handler pointers | 363 // Convert the default task IDs collected above to one of the handler pointers |
| 366 // from common_tasks. | 364 // from common_tasks. |
| 367 for (FileBrowserHandlerSet::const_iterator task_iter = common_tasks.begin(); | 365 for (FileBrowserHandlerList::const_iterator task_iter = common_tasks.begin(); |
| 368 task_iter != common_tasks.end(); ++task_iter) { | 366 task_iter != common_tasks.end(); ++task_iter) { |
| 369 std::string task_id = MakeTaskID((*task_iter)->extension_id(), kTaskFile, | 367 std::string task_id = MakeTaskID((*task_iter)->extension_id(), kTaskFile, |
| 370 (*task_iter)->id()); | 368 (*task_iter)->id()); |
| 371 std::set<std::string>::iterator default_iter = default_ids.find(task_id); | 369 std::set<std::string>::iterator default_iter = default_ids.find(task_id); |
| 372 if (default_iter != default_ids.end()) { | 370 if (default_iter != default_ids.end()) { |
| 373 default_tasks->insert(*task_iter); | 371 default_tasks->push_back(*task_iter); |
| 374 continue; | 372 continue; |
| 375 } | 373 } |
| 376 | 374 |
| 377 // If it's a built in task, remember it. If there are no default tasks among | 375 // If it's a built in task, remember it. If there are no default tasks among |
| 378 // common tasks, builtin task will be used as a fallback. | 376 // common tasks, builtin task will be used as a fallback. |
| 379 // Note that builtin tasks are not overlapping, so there can be at most one | 377 // Note that builtin tasks are not overlapping, so there can be at most one |
| 380 // builtin tasks for each set of files. | 378 // builtin tasks for each set of files. |
| 381 if (IsBuiltinTask(*task_iter)) | 379 if (IsBuiltinTask(*task_iter)) |
| 382 builtin_task = *task_iter; | 380 builtin_task = *task_iter; |
| 383 } | 381 } |
| 384 | 382 |
| 385 // If there are no default tasks found, use builtin task (if found) as a | 383 // If there are no default tasks found, use builtin task (if found) as a |
| 386 // default. | 384 // default. |
| 387 if (builtin_task && default_tasks->empty()) | 385 if (builtin_task && default_tasks->empty()) |
| 388 default_tasks->insert(builtin_task); | 386 default_tasks->push_back(builtin_task); |
| 389 } | 387 } |
| 390 | 388 |
| 391 // Given the list of selected files, returns array of context menu tasks | 389 // Given the list of selected files, returns array of context menu tasks |
| 392 // that are shared | 390 // that are shared |
| 393 bool FindCommonTasks(Profile* profile, | 391 bool FindCommonTasks(Profile* profile, |
| 394 const std::vector<GURL>& files_list, | 392 const std::vector<GURL>& files_list, |
| 395 FileBrowserHandlerSet* common_tasks) { | 393 FileBrowserHandlerList* common_tasks) { |
| 396 DCHECK(common_tasks); | 394 DCHECK(common_tasks); |
| 397 common_tasks->clear(); | 395 common_tasks->clear(); |
| 398 | 396 |
| 399 FileBrowserHandlerSet common_task_set; | 397 FileBrowserHandlerList common_task_list; |
| 400 std::set<std::string> default_task_ids; | 398 std::set<std::string> default_task_ids; |
| 401 for (std::vector<GURL>::const_iterator it = files_list.begin(); | 399 for (std::vector<GURL>::const_iterator it = files_list.begin(); |
| 402 it != files_list.end(); ++it) { | 400 it != files_list.end(); ++it) { |
| 403 FileBrowserHandlerSet file_actions; | 401 FileBrowserHandlerList file_actions; |
| 404 if (!GetFileBrowserHandlers(profile, *it, &file_actions)) | 402 if (!GetFileBrowserHandlers(profile, *it, &file_actions)) |
| 405 return false; | 403 return false; |
| 406 // If there is nothing to do for one file, the intersection of tasks for all | 404 // 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. | 405 // files will be empty at the end, and so will the default tasks. |
| 408 if (file_actions.empty()) | 406 if (file_actions.empty()) |
| 409 return true; | 407 return true; |
| 410 | 408 |
| 411 // For the very first file, just copy all the elements. | 409 // For the very first file, just copy all the elements. |
| 412 if (it == files_list.begin()) { | 410 if (it == files_list.begin()) { |
| 413 common_task_set = file_actions; | 411 common_task_list = file_actions; |
| 414 } else { | 412 } else { |
| 415 // For all additional files, find intersection between the accumulated and | 413 // For all additional files, find intersection between the accumulated and |
| 416 // file specific set. | 414 // file specific set. |
| 417 FileBrowserHandlerSet intersection; | 415 FileBrowserHandlerList intersection; |
| 418 std::set_intersection(common_task_set.begin(), common_task_set.end(), | 416 std::set_intersection(common_task_list.begin(), common_task_list.end(), |
| 419 file_actions.begin(), file_actions.end(), | 417 file_actions.begin(), file_actions.end(), |
| 420 std::inserter(intersection, | 418 std::inserter(intersection, |
|
kinaba
2013/05/24 07:34:13
std::back_inserter(intersection)
mtomasz
2013/05/24 07:49:45
Done.
| |
| 421 intersection.begin())); | 419 intersection.begin())); |
| 422 common_task_set = intersection; | 420 common_task_list = intersection; |
| 423 if (common_task_set.empty()) | 421 if (common_task_list.empty()) |
| 424 return true; | 422 return true; |
| 425 } | 423 } |
| 426 } | 424 } |
| 427 | 425 |
| 428 FileBrowserHandlerSet::iterator watch_iter = FindHandler( | 426 FileBrowserHandlerList::iterator watch_iter = FindHandler( |
| 429 &common_task_set, kFileBrowserDomain, kFileBrowserWatchTaskId); | 427 &common_task_list, kFileBrowserDomain, kFileBrowserWatchTaskId); |
| 430 FileBrowserHandlerSet::iterator gallery_iter = FindHandler( | 428 FileBrowserHandlerList::iterator gallery_iter = FindHandler( |
| 431 &common_task_set, kFileBrowserDomain, kFileBrowserGalleryTaskId); | 429 &common_task_list, kFileBrowserDomain, kFileBrowserGalleryTaskId); |
| 432 if (watch_iter != common_task_set.end() && | 430 if (watch_iter != common_task_list.end() && |
| 433 gallery_iter != common_task_set.end()) { | 431 gallery_iter != common_task_list.end()) { |
| 434 // Both "watch" and "gallery" actions are applicable which means that the | 432 // 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 | 433 // 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" | 434 // the one that makes more sense ("watch" for single selection, "gallery" |
| 437 // for multiple selection). | 435 // for multiple selection). |
| 438 if (files_list.size() == 1) | 436 if (files_list.size() == 1) |
| 439 common_task_set.erase(gallery_iter); | 437 common_task_list.erase(gallery_iter); |
| 440 else | 438 else |
| 441 common_task_set.erase(watch_iter); | 439 common_task_list.erase(watch_iter); |
| 442 } | 440 } |
| 443 | 441 |
| 444 common_tasks->swap(common_task_set); | 442 common_tasks->swap(common_task_list); |
| 445 return true; | 443 return true; |
| 446 } | 444 } |
| 447 | 445 |
| 448 bool GetTaskForURLAndPath(Profile* profile, | 446 bool GetTaskForURLAndPath(Profile* profile, |
| 449 const GURL& url, | 447 const GURL& url, |
| 450 const base::FilePath& file_path, | 448 const base::FilePath& file_path, |
| 451 const FileBrowserHandler** handler) { | 449 const FileBrowserHandler** handler) { |
| 452 std::vector<GURL> file_urls; | 450 std::vector<GURL> file_urls; |
| 453 file_urls.push_back(url); | 451 file_urls.push_back(url); |
| 454 | 452 |
| 455 FileBrowserHandlerSet default_tasks; | 453 FileBrowserHandlerList default_tasks; |
| 456 FileBrowserHandlerSet common_tasks; | 454 FileBrowserHandlerList common_tasks; |
| 457 if (!FindCommonTasks(profile, file_urls, &common_tasks)) | 455 if (!FindCommonTasks(profile, file_urls, &common_tasks)) |
| 458 return false; | 456 return false; |
| 459 | 457 |
| 460 if (common_tasks.empty()) | 458 if (common_tasks.empty()) |
| 461 return false; | 459 return false; |
| 462 | 460 |
| 463 std::vector<base::FilePath> file_paths; | 461 std::vector<base::FilePath> file_paths; |
| 464 file_paths.push_back(file_path); | 462 file_paths.push_back(file_path); |
| 465 | 463 |
| 466 FindDefaultTasks(profile, file_paths, common_tasks, &default_tasks); | 464 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(), | 986 extensions::LaunchPlatformAppWithFileHandler(profile(), GetExtension(), |
| 989 action_id_, file_urls[i].path()); | 987 action_id_, file_urls[i].path()); |
| 990 } | 988 } |
| 991 | 989 |
| 992 if (!done.is_null()) | 990 if (!done.is_null()) |
| 993 done.Run(true); | 991 done.Run(true); |
| 994 return true; | 992 return true; |
| 995 } | 993 } |
| 996 | 994 |
| 997 } // namespace file_handler_util | 995 } // namespace file_handler_util |
| OLD | NEW |