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

Side by Side Diff: chrome/browser/chromeos/extensions/file_manager/file_tasks.cc

Issue 23945002: file_manager: Move non-binding code to c/b/chromeos/file_manager (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 3 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/extensions/file_manager/file_tasks.h"
6
7 #include "apps/launcher.h"
8 #include "base/bind.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/stringprintf.h"
11 #include "chrome/browser/chromeos/drive/drive_app_registry.h"
12 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
13 #include "chrome/browser/chromeos/drive/file_system_util.h"
14 #include "chrome/browser/chromeos/drive/file_task_executor.h"
15 #include "chrome/browser/chromeos/extensions/file_manager/file_browser_handlers. h"
16 #include "chrome/browser/chromeos/extensions/file_manager/fileapi_util.h"
17 #include "chrome/browser/chromeos/extensions/file_manager/open_util.h"
18 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
19 #include "chrome/browser/extensions/extension_host.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/extension_service.h"
22 #include "chrome/browser/extensions/extension_system.h"
23 #include "chrome/browser/extensions/extension_system.h"
24 #include "chrome/browser/extensions/extension_tab_util.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
27 #include "chrome/common/extensions/api/file_browser_handlers/file_browser_handle r.h"
28 #include "chrome/common/pref_names.h"
29 #include "webkit/browser/fileapi/file_system_context.h"
30 #include "webkit/browser/fileapi/file_system_url.h"
31
32 using extensions::Extension;
33 using extensions::app_file_handler_util::FindFileHandlersForFiles;
34 using fileapi::FileSystemURL;
35
36 namespace file_manager {
37 namespace file_tasks {
38
39 namespace {
40
41 // The values "file" and "app" are confusing, but cannot be changed easily as
42 // these are used in default task IDs stored in preferences.
43 //
44 // TODO(satorux): We should rename them to "file_browser_handler" and
45 // "file_handler" respectively when switching from preferences to
46 // chrome.storage crbug.com/267359
47 const char kFileBrowserHandlerTaskType[] = "file";
48 const char kFileHandlerTaskType[] = "app";
49 const char kDriveAppTaskType[] = "drive";
50
51 // Drive apps always use the action ID.
52 const char kDriveAppActionID[] = "open-with";
53
54 // Default icon path for drive docs.
55 const char kDefaultIcon[] = "images/filetype_generic.png";
56
57 // Converts a TaskType to a string.
58 std::string TaskTypeToString(TaskType task_type) {
59 switch (task_type) {
60 case TASK_TYPE_FILE_BROWSER_HANDLER:
61 return kFileBrowserHandlerTaskType;
62 case TASK_TYPE_FILE_HANDLER:
63 return kFileHandlerTaskType;
64 case TASK_TYPE_DRIVE_APP:
65 return kDriveAppTaskType;
66 case TASK_TYPE_UNKNOWN:
67 break;
68 }
69 NOTREACHED();
70 return "";
71 }
72
73 // Converts a string to a TaskType. Returns TASK_TYPE_UNKNOWN on error.
74 TaskType StringToTaskType(const std::string& str) {
75 if (str == kFileBrowserHandlerTaskType)
76 return TASK_TYPE_FILE_BROWSER_HANDLER;
77 if (str == kFileHandlerTaskType)
78 return TASK_TYPE_FILE_HANDLER;
79 if (str == kDriveAppTaskType)
80 return TASK_TYPE_DRIVE_APP;
81 return TASK_TYPE_UNKNOWN;
82 }
83
84 // Legacy Drive task extension prefix, used by CrackTaskID.
85 const char kDriveTaskExtensionPrefix[] = "drive-app:";
86 const size_t kDriveTaskExtensionPrefixLength =
87 arraysize(kDriveTaskExtensionPrefix) - 1;
88
89 // Checks if the file browser extension has permissions for the files in its
90 // file system context.
91 bool FileBrowserHasAccessPermissionForFiles(
92 Profile* profile,
93 const GURL& source_url,
94 const std::string& file_browser_id,
95 const std::vector<FileSystemURL>& files) {
96 fileapi::ExternalFileSystemBackend* backend =
97 util::GetFileSystemContextForExtensionId(
98 profile, file_browser_id)->external_backend();
99 if (!backend)
100 return false;
101
102 for (size_t i = 0; i < files.size(); ++i) {
103 // Make sure this url really being used by the right caller extension.
104 if (source_url.GetOrigin() != files[i].origin())
105 return false;
106
107 if (!chromeos::FileSystemBackend::CanHandleURL(files[i]) ||
108 !backend->IsAccessAllowed(files[i])) {
109 return false;
110 }
111 }
112
113 return true;
114 }
115
116 } // namespace
117
118 FullTaskDescriptor::FullTaskDescriptor(
119 const TaskDescriptor& task_descriptor,
120 const std::string& task_title,
121 const GURL& icon_url,
122 bool is_default)
123 : task_descriptor_(task_descriptor),
124 task_title_(task_title),
125 icon_url_(icon_url),
126 is_default_(is_default){
127 }
128
129 scoped_ptr<base::DictionaryValue>
130 FullTaskDescriptor::AsDictionaryValue() const {
131 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue);
132 dictionary->SetString("taskId", TaskDescriptorToId(task_descriptor_));
133 if (!icon_url_.is_empty())
134 dictionary->SetString("iconUrl", icon_url_.spec());
135 dictionary->SetString("title", task_title_);
136 dictionary->SetBoolean("isDefault", is_default_);
137 return dictionary.Pass();
138 }
139
140 void UpdateDefaultTask(PrefService* pref_service,
141 const std::string& task_id,
142 const std::set<std::string>& suffixes,
143 const std::set<std::string>& mime_types) {
144 if (!pref_service)
145 return;
146
147 if (!mime_types.empty()) {
148 DictionaryPrefUpdate mime_type_pref(pref_service,
149 prefs::kDefaultTasksByMimeType);
150 for (std::set<std::string>::const_iterator iter = mime_types.begin();
151 iter != mime_types.end(); ++iter) {
152 base::StringValue* value = new base::StringValue(task_id);
153 mime_type_pref->SetWithoutPathExpansion(*iter, value);
154 }
155 }
156
157 if (!suffixes.empty()) {
158 DictionaryPrefUpdate mime_type_pref(pref_service,
159 prefs::kDefaultTasksBySuffix);
160 for (std::set<std::string>::const_iterator iter = suffixes.begin();
161 iter != suffixes.end(); ++iter) {
162 base::StringValue* value = new base::StringValue(task_id);
163 // Suffixes are case insensitive.
164 std::string lower_suffix = StringToLowerASCII(*iter);
165 mime_type_pref->SetWithoutPathExpansion(lower_suffix, value);
166 }
167 }
168 }
169
170 std::string GetDefaultTaskIdFromPrefs(const PrefService& pref_service,
171 const std::string& mime_type,
172 const std::string& suffix) {
173 VLOG(1) << "Looking for default for MIME type: " << mime_type
174 << " and suffix: " << suffix;
175 std::string task_id;
176 if (!mime_type.empty()) {
177 const DictionaryValue* mime_task_prefs =
178 pref_service.GetDictionary(prefs::kDefaultTasksByMimeType);
179 DCHECK(mime_task_prefs);
180 LOG_IF(ERROR, !mime_task_prefs) << "Unable to open MIME type prefs";
181 if (mime_task_prefs &&
182 mime_task_prefs->GetStringWithoutPathExpansion(mime_type, &task_id)) {
183 VLOG(1) << "Found MIME default handler: " << task_id;
184 return task_id;
185 }
186 }
187
188 const DictionaryValue* suffix_task_prefs =
189 pref_service.GetDictionary(prefs::kDefaultTasksBySuffix);
190 DCHECK(suffix_task_prefs);
191 LOG_IF(ERROR, !suffix_task_prefs) << "Unable to open suffix prefs";
192 std::string lower_suffix = StringToLowerASCII(suffix);
193 if (suffix_task_prefs)
194 suffix_task_prefs->GetStringWithoutPathExpansion(lower_suffix, &task_id);
195 VLOG_IF(1, !task_id.empty()) << "Found suffix default handler: " << task_id;
196 return task_id;
197 }
198
199 std::string MakeTaskID(const std::string& app_id,
200 TaskType task_type,
201 const std::string& action_id) {
202 return base::StringPrintf("%s|%s|%s",
203 app_id.c_str(),
204 TaskTypeToString(task_type).c_str(),
205 action_id.c_str());
206 }
207
208 std::string MakeDriveAppTaskId(const std::string& app_id) {
209 return MakeTaskID(app_id, TASK_TYPE_DRIVE_APP, kDriveAppActionID);
210 }
211
212 std::string TaskDescriptorToId(const TaskDescriptor& task_descriptor) {
213 return MakeTaskID(task_descriptor.app_id,
214 task_descriptor.task_type,
215 task_descriptor.action_id);
216 }
217
218 bool ParseTaskID(const std::string& task_id, TaskDescriptor* task) {
219 DCHECK(task);
220
221 std::vector<std::string> result;
222 int count = Tokenize(task_id, std::string("|"), &result);
223
224 // Parse a legacy task ID that only contain two parts. Drive tasks are
225 // identified by a prefix "drive-app:" on the extension ID. The legacy task
226 // IDs can be stored in preferences.
227 // TODO(satorux): We should get rid of this code: crbug.com/267359.
228 if (count == 2) {
229 if (StartsWithASCII(result[0], kDriveTaskExtensionPrefix, true)) {
230 task->task_type = TASK_TYPE_DRIVE_APP;
231 task->app_id = result[0].substr(kDriveTaskExtensionPrefixLength);
232 } else {
233 task->task_type = TASK_TYPE_FILE_BROWSER_HANDLER;
234 task->app_id = result[0];
235 }
236
237 task->action_id = result[1];
238
239 return true;
240 }
241
242 if (count != 3)
243 return false;
244
245 TaskType task_type = StringToTaskType(result[1]);
246 if (task_type == TASK_TYPE_UNKNOWN)
247 return false;
248
249 task->app_id = result[0];
250 task->task_type = task_type;
251 task->action_id = result[2];
252
253 return true;
254 }
255
256 bool ExecuteFileTask(Profile* profile,
257 const GURL& source_url,
258 const std::string& app_id,
259 int32 tab_id,
260 const TaskDescriptor& task,
261 const std::vector<FileSystemURL>& file_urls,
262 const FileTaskFinishedCallback& done) {
263 if (!FileBrowserHasAccessPermissionForFiles(profile, source_url,
264 app_id, file_urls))
265 return false;
266
267 // drive::FileTaskExecutor is responsible to handle drive tasks.
268 if (task.task_type == TASK_TYPE_DRIVE_APP) {
269 DCHECK_EQ(kDriveAppActionID, task.action_id);
270 drive::FileTaskExecutor* executor =
271 new drive::FileTaskExecutor(profile, task.app_id);
272 executor->Execute(file_urls, done);
273 return true;
274 }
275
276 // Get the extension.
277 ExtensionService* service =
278 extensions::ExtensionSystem::Get(profile)->extension_service();
279 const Extension* extension = service ?
280 service->GetExtensionById(task.app_id, false) : NULL;
281 if (!extension)
282 return false;
283
284 // Execute the task.
285 if (task.task_type == TASK_TYPE_FILE_BROWSER_HANDLER) {
286 return file_browser_handlers::ExecuteFileBrowserHandler(
287 profile,
288 extension,
289 tab_id,
290 task.action_id,
291 file_urls,
292 done);
293 } else if (task.task_type == TASK_TYPE_FILE_HANDLER) {
294 for (size_t i = 0; i != file_urls.size(); ++i) {
295 apps::LaunchPlatformAppWithFileHandler(
296 profile, extension, task.action_id, file_urls[i].path());
297 }
298
299 if (!done.is_null())
300 done.Run(true);
301 return true;
302 }
303 NOTREACHED();
304 return false;
305 }
306
307 void FindDriveAppTasks(
308 const drive::DriveAppRegistry& drive_app_registry,
309 const PathAndMimeTypeSet& path_mime_set,
310 std::vector<FullTaskDescriptor>* result_list) {
311 DCHECK(result_list);
312
313 bool is_first = true;
314 typedef std::map<std::string, drive::DriveAppInfo> DriveAppInfoMap;
315 DriveAppInfoMap drive_app_map;
316
317 for (PathAndMimeTypeSet::const_iterator it = path_mime_set.begin();
318 it != path_mime_set.end(); ++it) {
319 const base::FilePath& file_path = it->first;
320 const std::string& mime_type = it->second;
321 // Return immediately if a file not on Drive is found, as Drive app tasks
322 // work only if all files are on Drive.
323 if (!drive::util::IsUnderDriveMountPoint(file_path))
324 return;
325
326 ScopedVector<drive::DriveAppInfo> app_info_list;
327 drive_app_registry.GetAppsForFile(file_path.Extension(),
328 mime_type,
329 &app_info_list);
330
331 if (is_first) {
332 // For the first file, we store all the info.
333 for (size_t j = 0; j < app_info_list.size(); ++j) {
334 const drive::DriveAppInfo& app_info = *app_info_list[j];
335 drive_app_map[app_info.app_id] = app_info;
336 }
337 } else {
338 // For remaining files, take the intersection with the current
339 // result, based on the app id.
340 std::set<std::string> app_id_set;
341 for (size_t j = 0; j < app_info_list.size(); ++j)
342 app_id_set.insert(app_info_list[j]->app_id);
343 for (DriveAppInfoMap::iterator iter = drive_app_map.begin();
344 iter != drive_app_map.end();) {
345 if (app_id_set.count(iter->first) == 0) {
346 drive_app_map.erase(iter++);
347 } else {
348 ++iter;
349 }
350 }
351 }
352
353 is_first = false;
354 }
355
356 for (DriveAppInfoMap::const_iterator iter = drive_app_map.begin();
357 iter != drive_app_map.end(); ++iter) {
358 const drive::DriveAppInfo& app_info = iter->second;
359 TaskDescriptor descriptor(app_info.app_id,
360 TASK_TYPE_DRIVE_APP,
361 kDriveAppActionID);
362 GURL icon_url = drive::util::FindPreferredIcon(
363 app_info.app_icons,
364 drive::util::kPreferredIconSize);
365 result_list->push_back(
366 FullTaskDescriptor(descriptor,
367 app_info.app_name,
368 icon_url,
369 false /* is_default */));
370 }
371 }
372
373 void FindFileHandlerTasks(
374 Profile* profile,
375 const PathAndMimeTypeSet& path_mime_set,
376 std::vector<FullTaskDescriptor>* result_list) {
377 DCHECK(!path_mime_set.empty());
378 DCHECK(result_list);
379
380 ExtensionService* service = profile->GetExtensionService();
381 if (!service)
382 return;
383
384 for (ExtensionSet::const_iterator iter = service->extensions()->begin();
385 iter != service->extensions()->end();
386 ++iter) {
387 const Extension* extension = iter->get();
388
389 // We don't support using hosted apps to open files.
390 if (!extension->is_platform_app())
391 continue;
392
393 if (profile->IsOffTheRecord() &&
394 !service->IsIncognitoEnabled(extension->id()))
395 continue;
396
397 typedef std::vector<const extensions::FileHandlerInfo*> FileHandlerList;
398 FileHandlerList file_handlers =
399 FindFileHandlersForFiles(*extension, path_mime_set);
400 if (file_handlers.empty())
401 continue;
402
403 for (FileHandlerList::iterator i = file_handlers.begin();
404 i != file_handlers.end(); ++i) {
405 std::string task_id = file_tasks::MakeTaskID(
406 extension->id(), file_tasks::TASK_TYPE_FILE_HANDLER, (*i)->id);
407
408 GURL best_icon = extensions::ExtensionIconSource::GetIconURL(
409 extension,
410 drive::util::kPreferredIconSize,
411 ExtensionIconSet::MATCH_BIGGER,
412 false, // grayscale
413 NULL); // exists
414
415 result_list->push_back(FullTaskDescriptor(
416 TaskDescriptor(extension->id(),
417 file_tasks::TASK_TYPE_FILE_HANDLER,
418 (*i)->id),
419 (*i)->title,
420 best_icon,
421 false /* is_default */));
422 }
423 }
424 }
425
426 void FindFileBrowserHandlerTasks(
427 Profile* profile,
428 const std::vector<GURL>& file_urls,
429 std::vector<FullTaskDescriptor>* result_list) {
430 DCHECK(!file_urls.empty());
431 DCHECK(result_list);
432
433 file_browser_handlers::FileBrowserHandlerList common_tasks =
434 file_browser_handlers::FindCommonFileBrowserHandlers(profile, file_urls);
435 if (common_tasks.empty())
436 return;
437
438 ExtensionService* service =
439 extensions::ExtensionSystem::Get(profile)->extension_service();
440 for (file_browser_handlers::FileBrowserHandlerList::const_iterator iter =
441 common_tasks.begin();
442 iter != common_tasks.end();
443 ++iter) {
444 const FileBrowserHandler* handler = *iter;
445 const std::string extension_id = handler->extension_id();
446 const Extension* extension = service->GetExtensionById(extension_id, false);
447 DCHECK(extension);
448
449 // TODO(zelidrag): Figure out how to expose icon URL that task defined in
450 // manifest instead of the default extension icon.
451 const GURL icon_url = extensions::ExtensionIconSource::GetIconURL(
452 extension,
453 extension_misc::EXTENSION_ICON_BITTY,
454 ExtensionIconSet::MATCH_BIGGER,
455 false, // grayscale
456 NULL); // exists
457
458 result_list->push_back(FullTaskDescriptor(
459 TaskDescriptor(extension_id,
460 file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER,
461 handler->id()),
462 handler->title(),
463 icon_url,
464 false /* is_default */));
465 }
466 }
467
468 void FindAllTypesOfTasks(
469 Profile* profile,
470 const PathAndMimeTypeSet& path_mime_set,
471 const std::vector<GURL>& file_urls,
472 std::vector<FullTaskDescriptor>* result_list) {
473 DCHECK(profile);
474 DCHECK(result_list);
475
476 // Check if file_paths contain a google document.
477 bool has_google_document = false;
478 for (PathAndMimeTypeSet::const_iterator iter = path_mime_set.begin();
479 iter != path_mime_set.end(); ++iter) {
480 if (google_apis::ResourceEntry::ClassifyEntryKindByFileExtension(
481 iter->first) &
482 google_apis::ResourceEntry::KIND_OF_GOOGLE_DOCUMENT) {
483 has_google_document = true;
484 break;
485 }
486 }
487
488 // Google document are not opened by drive apps but file manager.
489 if (!has_google_document) {
490 drive::DriveIntegrationService* integration_service =
491 drive::DriveIntegrationServiceFactory::GetForProfile(profile);
492 // |integration_service| is NULL if Drive is disabled.
493 if (!integration_service || !integration_service->drive_app_registry())
494 return;
495
496 FindDriveAppTasks(*integration_service->drive_app_registry(),
497 path_mime_set,
498 result_list);
499 }
500
501 // Find and append file handler tasks. We know there aren't duplicates
502 // because Drive apps and platform apps are entirely different kinds of
503 // tasks.
504 FindFileHandlerTasks(profile,
505 path_mime_set,
506 result_list);
507
508 // Find and append file browser handler tasks. We know there aren't
509 // duplicates because "file_browser_handlers" and "file_handlers" shouldn't
510 // be used in the same manifest.json.
511 FindFileBrowserHandlerTasks(profile,
512 file_urls,
513 result_list);
514
515 ChooseAndSetDefaultTask(*profile->GetPrefs(),
516 path_mime_set,
517 result_list);
518 }
519
520 void ChooseAndSetDefaultTask(const PrefService& pref_service,
521 const PathAndMimeTypeSet& path_mime_set,
522 std::vector<FullTaskDescriptor>* tasks) {
523 // Collect the task IDs of default tasks from the preferences into a set.
524 std::set<std::string> default_task_ids;
525 for (PathAndMimeTypeSet::const_iterator it = path_mime_set.begin();
526 it != path_mime_set.end(); ++it) {
527 const base::FilePath& file_path = it->first;
528 const std::string& mime_type = it->second;
529 std::string task_id = file_tasks::GetDefaultTaskIdFromPrefs(
530 pref_service, mime_type, file_path.Extension());
531 default_task_ids.insert(task_id);
532 }
533
534 // Go through all the tasks from the beginning and see if there is any
535 // default task. If found, pick and set it as default and return.
536 for (size_t i = 0; i < tasks->size(); ++i) {
537 FullTaskDescriptor* task = &tasks->at(i);
538 DCHECK(!task->is_default());
539 const std::string task_id = TaskDescriptorToId(task->task_descriptor());
540 if (ContainsKey(default_task_ids, task_id)) {
541 task->set_is_default(true);
542 return;
543 }
544 }
545
546 // No default tasks found. If there is any fallback file browser handler,
547 // make it as default task, so it's selected by default.
548 for (size_t i = 0; i < tasks->size(); ++i) {
549 FullTaskDescriptor* task = &tasks->at(i);
550 DCHECK(!task->is_default());
551 if (file_browser_handlers::IsFallbackFileBrowserHandler(
552 task->task_descriptor())) {
553 task->set_is_default(true);
554 return;
555 }
556 }
557 }
558
559 } // namespace file_tasks
560 } // namespace file_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698