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

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

Issue 14670023: ChromeOS: Support opening files with apps from the downloads page. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 7 years, 7 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
« no previous file with comments | « chrome/browser/chromeos/extensions/file_manager/file_manager_util.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h" 4 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
5 5
6 #include "ash/shell.h" 6 #include "ash/shell.h"
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/json/json_file_value_serializer.h" 10 #include "base/json/json_file_value_serializer.h"
11 #include "base/json/json_writer.h" 11 #include "base/json/json_writer.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
14 #include "base/path_service.h" 14 #include "base/path_service.h"
15 #include "base/string_util.h" 15 #include "base/string_util.h"
16 #include "base/utf_string_conversions.h" 16 #include "base/utf_string_conversions.h"
17 #include "base/values.h" 17 #include "base/values.h"
18 #include "chrome/browser/chromeos/drive/drive.pb.h" 18 #include "chrome/browser/chromeos/drive/drive.pb.h"
19 #include "chrome/browser/chromeos/drive/drive_system_service.h" 19 #include "chrome/browser/chromeos/drive/drive_system_service.h"
20 #include "chrome/browser/chromeos/drive/file_system.h" 20 #include "chrome/browser/chromeos/drive/file_system.h"
21 #include "chrome/browser/chromeos/drive/file_system_util.h" 21 #include "chrome/browser/chromeos/drive/file_system_util.h"
22 #include "chrome/browser/chromeos/extensions/file_manager/file_browser_handler.h " 22 #include "chrome/browser/chromeos/extensions/file_manager/file_browser_handler.h "
23 #include "chrome/browser/chromeos/extensions/file_manager/file_handler_util.h" 23 #include "chrome/browser/chromeos/extensions/file_manager/file_handler_util.h"
24 #include "chrome/browser/chromeos/media/media_player.h" 24 #include "chrome/browser/chromeos/media/media_player.h"
25 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
25 #include "chrome/browser/extensions/crx_installer.h" 26 #include "chrome/browser/extensions/crx_installer.h"
26 #include "chrome/browser/extensions/extension_install_prompt.h" 27 #include "chrome/browser/extensions/extension_install_prompt.h"
27 #include "chrome/browser/extensions/extension_service.h" 28 #include "chrome/browser/extensions/extension_service.h"
28 #include "chrome/browser/extensions/extension_system.h" 29 #include "chrome/browser/extensions/extension_system.h"
29 #include "chrome/browser/google_apis/task_util.h" 30 #include "chrome/browser/google_apis/task_util.h"
30 #include "chrome/browser/plugins/plugin_prefs.h" 31 #include "chrome/browser/plugins/plugin_prefs.h"
31 #include "chrome/browser/profiles/profile.h" 32 #include "chrome/browser/profiles/profile.h"
32 #include "chrome/browser/profiles/profile_manager.h" 33 #include "chrome/browser/profiles/profile_manager.h"
33 #include "chrome/browser/ui/browser.h" 34 #include "chrome/browser/ui/browser.h"
34 #include "chrome/browser/ui/browser_finder.h" 35 #include "chrome/browser/ui/browser_finder.h"
35 #include "chrome/browser/ui/browser_iterator.h" 36 #include "chrome/browser/ui/browser_iterator.h"
36 #include "chrome/browser/ui/browser_tabstrip.h" 37 #include "chrome/browser/ui/browser_tabstrip.h"
37 #include "chrome/browser/ui/browser_window.h" 38 #include "chrome/browser/ui/browser_window.h"
38 #include "chrome/browser/ui/extensions/application_launch.h" 39 #include "chrome/browser/ui/extensions/application_launch.h"
39 #include "chrome/browser/ui/host_desktop.h" 40 #include "chrome/browser/ui/host_desktop.h"
40 #include "chrome/browser/ui/simple_message_box.h" 41 #include "chrome/browser/ui/simple_message_box.h"
41 #include "chrome/browser/ui/tabs/tab_strip_model.h" 42 #include "chrome/browser/ui/tabs/tab_strip_model.h"
42 #include "chrome/common/chrome_paths.h" 43 #include "chrome/common/chrome_paths.h"
43 #include "chrome/common/chrome_switches.h" 44 #include "chrome/common/chrome_switches.h"
44 #include "chrome/common/url_constants.h" 45 #include "chrome/common/url_constants.h"
45 #include "content/public/browser/browser_thread.h" 46 #include "content/public/browser/browser_thread.h"
46 #include "content/public/browser/plugin_service.h" 47 #include "content/public/browser/plugin_service.h"
47 #include "content/public/browser/storage_partition.h" 48 #include "content/public/browser/storage_partition.h"
48 #include "content/public/browser/user_metrics.h" 49 #include "content/public/browser/user_metrics.h"
49 #include "content/public/browser/web_contents.h" 50 #include "content/public/browser/web_contents.h"
50 #include "content/public/common/pepper_plugin_info.h" 51 #include "content/public/common/pepper_plugin_info.h"
51 #include "grit/generated_resources.h" 52 #include "grit/generated_resources.h"
52 #include "net/base/escape.h" 53 #include "net/base/escape.h"
54 #include "net/base/mime_util.h"
53 #include "net/base/net_util.h" 55 #include "net/base/net_util.h"
54 #include "ui/base/l10n/l10n_util.h" 56 #include "ui/base/l10n/l10n_util.h"
55 #include "ui/gfx/screen.h" 57 #include "ui/gfx/screen.h"
56 #include "webkit/fileapi/file_system_context.h" 58 #include "webkit/fileapi/file_system_context.h"
57 #include "webkit/fileapi/file_system_mount_point_provider.h" 59 #include "webkit/fileapi/file_system_mount_point_provider.h"
58 #include "webkit/fileapi/file_system_operation.h" 60 #include "webkit/fileapi/file_system_operation.h"
59 #include "webkit/fileapi/file_system_url.h" 61 #include "webkit/fileapi/file_system_url.h"
60 #include "webkit/fileapi/file_system_util.h" 62 #include "webkit/fileapi/file_system_util.h"
61 #include "webkit/plugins/webplugininfo.h" 63 #include "webkit/plugins/webplugininfo.h"
62 64
63 using base::DictionaryValue; 65 using base::DictionaryValue;
64 using base::ListValue; 66 using base::ListValue;
65 using content::BrowserContext; 67 using content::BrowserContext;
66 using content::BrowserThread; 68 using content::BrowserThread;
67 using content::PluginService; 69 using content::PluginService;
68 using content::UserMetricsAction; 70 using content::UserMetricsAction;
71 using extensions::app_file_handler_util::FindFileHandlersForFiles;
72 using extensions::app_file_handler_util::PathAndMimeTypeSet;
69 using extensions::Extension; 73 using extensions::Extension;
70 using file_handler_util::FileTaskExecutor; 74 using file_handler_util::FileTaskExecutor;
71 using fileapi::FileSystemURL; 75 using fileapi::FileSystemURL;
72 76
73 #define FILEBROWSER_EXTENSON_ID "hhaomjibdihmijegdhdafkllkbggdgoj" 77 #define FILEBROWSER_EXTENSON_ID "hhaomjibdihmijegdhdafkllkbggdgoj"
74 const char kFileBrowserDomain[] = FILEBROWSER_EXTENSON_ID; 78 const char kFileBrowserDomain[] = FILEBROWSER_EXTENSON_ID;
75 79
76 const char kFileBrowserGalleryTaskId[] = "gallery"; 80 const char kFileBrowserGalleryTaskId[] = "gallery";
77 const char kFileBrowserMountArchiveTaskId[] = "mount-archive"; 81 const char kFileBrowserMountArchiveTaskId[] = "mount-archive";
78 const char kFileBrowserWatchTaskId[] = "watch"; 82 const char kFileBrowserWatchTaskId[] = "watch";
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 if (!external_provider) 333 if (!external_provider)
330 return false; 334 return false;
331 external_provider->GrantFullAccessToExtension(GetFileBrowserUrl().host()); 335 external_provider->GrantFullAccessToExtension(GetFileBrowserUrl().host());
332 return true; 336 return true;
333 } 337 }
334 338
335 // Executes handler specifed with |extension_id| and |action_id| for |url|. 339 // Executes handler specifed with |extension_id| and |action_id| for |url|.
336 void ExecuteHandler(Profile* profile, 340 void ExecuteHandler(Profile* profile,
337 std::string extension_id, 341 std::string extension_id,
338 std::string action_id, 342 std::string action_id,
339 const GURL& url) { 343 const GURL& url,
344 const std::string& task_type) {
340 // If File Browser has not been open yet then it did not request access 345 // If File Browser has not been open yet then it did not request access
341 // to the file system. Do it now. 346 // to the file system. Do it now.
342 if (!GrantFileSystemAccessToFileBrowser(profile)) 347 if (!GrantFileSystemAccessToFileBrowser(profile))
343 return; 348 return;
344 349
345 GURL site = extensions::ExtensionSystem::Get(profile)->extension_service()-> 350 GURL site = extensions::ExtensionSystem::Get(profile)->extension_service()->
346 GetSiteForExtensionId(kFileBrowserDomain); 351 GetSiteForExtensionId(kFileBrowserDomain);
347 fileapi::FileSystemContext* file_system_context = 352 fileapi::FileSystemContext* file_system_context =
348 BrowserContext::GetStoragePartitionForSite(profile, site)-> 353 BrowserContext::GetStoragePartitionForSite(profile, site)->
349 GetFileSystemContext(); 354 GetFileSystemContext();
350 355
351 // We are executing the task on behalf of File Browser extension. 356 // We are executing the task on behalf of File Browser extension.
352 const GURL source_url = GetFileBrowserUrl(); 357 const GURL source_url = GetFileBrowserUrl();
353 std::vector<FileSystemURL> urls; 358 std::vector<FileSystemURL> urls;
354 urls.push_back(file_system_context->CrackURL(url)); 359 urls.push_back(file_system_context->CrackURL(url));
355 scoped_refptr<FileTaskExecutor> executor = FileTaskExecutor::Create(profile, 360 scoped_refptr<FileTaskExecutor> executor = FileTaskExecutor::Create(profile,
356 source_url, kFileBrowserDomain, 0 /* no tab id */, extension_id, 361 source_url, kFileBrowserDomain, 0 /* no tab id */, extension_id,
357 file_handler_util::kTaskFile, action_id); 362 task_type, action_id);
358 executor->Execute(urls); 363 executor->Execute(urls);
359 } 364 }
360 365
361 void OpenFileBrowserImpl(const base::FilePath& path, 366 void OpenFileBrowserImpl(const base::FilePath& path,
362 TAB_REUSE_MODE mode, 367 TAB_REUSE_MODE mode,
363 const std::string& action_id) { 368 const std::string& action_id) {
364 content::RecordAction(UserMetricsAction("ShowFileBrowserFullTab")); 369 content::RecordAction(UserMetricsAction("ShowFileBrowserFullTab"));
365 370
366 if (FileManageTabExists(path, mode)) 371 if (FileManageTabExists(path, mode))
367 return; 372 return;
368 373
369 Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord(); 374 Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
370 375
371 if (IsFileManagerPackaged() && !path.value().empty()) { 376 if (IsFileManagerPackaged() && !path.value().empty()) {
372 GURL url; 377 GURL url;
373 if (!ConvertFileToFileSystemUrl(profile, path, kFileBrowserDomain, &url)) 378 if (!ConvertFileToFileSystemUrl(profile, path, kFileBrowserDomain, &url))
374 return; 379 return;
375 380
376 // Some values of |action_id| are not listed in the manifest and are used 381 // Some values of |action_id| are not listed in the manifest and are used
377 // to parametrize the behavior when opening the Files app window. 382 // to parametrize the behavior when opening the Files app window.
378 ExecuteHandler(profile, kFileBrowserDomain, action_id, url); 383 ExecuteHandler(profile, kFileBrowserDomain, action_id, url,
384 file_handler_util::kTaskFile);
379 return; 385 return;
380 } 386 }
381 387
382 std::string url = chrome::kChromeUIFileManagerURL; 388 std::string url = chrome::kChromeUIFileManagerURL;
383 if (action_id.size()) { 389 if (action_id.size()) {
384 DictionaryValue arg_value; 390 DictionaryValue arg_value;
385 arg_value.SetString("action", action_id); 391 arg_value.SetString("action", action_id);
386 std::string query; 392 std::string query;
387 base::JSONWriter::Write(&arg_value, &query); 393 base::JSONWriter::Write(&arg_value, &query);
388 url += "?" + 394 url += "?" +
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 for (int idx = 0; idx < tab_strip->count(); idx++) { 429 for (int idx = 0; idx < tab_strip->count(); idx++) {
424 content::WebContents* web_contents = tab_strip->GetWebContentsAt(idx); 430 content::WebContents* web_contents = tab_strip->GetWebContentsAt(idx);
425 const GURL& url = web_contents->GetURL(); 431 const GURL& url = web_contents->GetURL();
426 if (url == target_url) 432 if (url == target_url)
427 return browser; 433 return browser;
428 } 434 }
429 } 435 }
430 return NULL; 436 return NULL;
431 } 437 }
432 438
439 bool ExecuteDefaultAppHandler(Profile* profile,
440 const base::FilePath& path,
441 const GURL& url,
442 const std::string& mime_type,
443 const std::string& default_task_id) {
444 ExtensionService* service = profile->GetExtensionService();
445 if (!service)
446 return false;
447
448 PathAndMimeTypeSet files;
449 files.insert(std::make_pair(path, mime_type));
450 const extensions::FileHandlerInfo* first_handler = NULL;
451 const extensions::Extension* extension_for_first_handler = NULL;
452
453 for (ExtensionSet::const_iterator iter = service->extensions()->begin();
Matt Giuca 2013/05/09 04:58:22 Explain the algorithm overall. // If we find the
Sam McNally 2013/05/09 07:31:35 Done.
454 iter != service->extensions()->end();
455 ++iter) {
456 const Extension* extension = *iter;
457
458 // We don't support using hosted apps to open files.
459 if (!extension->is_platform_app())
460 continue;
461
462 if (profile->IsOffTheRecord() &&
Matt Giuca 2013/05/09 04:58:22 What does this mean? Can you add a comment?
Sam McNally 2013/05/09 07:31:35 Done.
Matt Giuca 2013/05/09 08:56:58 Can you put quotes around "incognito: split". It's
Sam McNally 2013/05/09 23:27:44 Done.
463 !service->IsIncognitoEnabled(extension->id()))
464 continue;
465
466 typedef std::vector<const extensions::FileHandlerInfo*> FileHandlerList;
467 FileHandlerList file_handlers = FindFileHandlersForFiles(*extension, files);
468 for (FileHandlerList::iterator i = file_handlers.begin();
469 i != file_handlers.end(); ++i) {
470 const extensions::FileHandlerInfo* handler = *i;
471 std::string task_id = file_handler_util::MakeTaskID(extension->id(),
472 file_handler_util::kTaskApp, handler->id);
473 if (task_id == default_task_id) {
474 ExecuteHandler(profile, extension->id(), handler->id, url,
475 file_handler_util::kTaskApp);
476 return true;
477
478 } else if (!first_handler) {
479 first_handler = handler;
480 extension_for_first_handler = extension;
481 }
482 }
483 }
484 if (first_handler) {
485 ExecuteHandler(profile, extension_for_first_handler->id(),
486 first_handler->id, url, file_handler_util::kTaskApp);
487 return true;
488 }
489 return false;
490 }
491
433 bool ExecuteDefaultHandler(Profile* profile, const base::FilePath& path) { 492 bool ExecuteDefaultHandler(Profile* profile, const base::FilePath& path) {
434 GURL url; 493 GURL url;
435 if (!ConvertFileToFileSystemUrl(profile, path, kFileBrowserDomain, &url)) 494 if (!ConvertFileToFileSystemUrl(profile, path, kFileBrowserDomain, &url))
436 return false; 495 return false;
437 496
497 std::string mime_type = GetMimeTypeForPath(path);
Matt Giuca 2013/05/09 04:58:22 Explain the approach you are taking in comments he
Sam McNally 2013/05/09 07:31:35 Done.
498 std::string default_task_id = file_handler_util::GetDefaultTaskIdFromPrefs(
499 profile, mime_type, path.Extension());
438 const FileBrowserHandler* handler; 500 const FileBrowserHandler* handler;
439 if (!file_handler_util::GetTaskForURLAndPath(profile, url, path, &handler)) 501 if (!file_handler_util::GetTaskForURLAndPath(profile, url, path, &handler)) {
Matt Giuca 2013/05/09 04:58:22 I think this could be clearer. It seems as though
Sam McNally 2013/05/09 07:31:35 Done.
440 return false; 502 return ExecuteDefaultAppHandler(
503 profile, path, url, mime_type, default_task_id);
504 }
505
506 std::string handler_task_id = file_handler_util::MakeTaskID(
507 handler->extension_id(), file_handler_util::kTaskFile, handler->id());
508 if (handler_task_id != default_task_id && ExecuteDefaultAppHandler(
509 profile, path, url, mime_type, default_task_id)) {
510 return true;
511 }
441 512
442 std::string extension_id = handler->extension_id(); 513 std::string extension_id = handler->extension_id();
443 std::string action_id = handler->id(); 514 std::string action_id = handler->id();
444 Browser* browser = chrome::FindLastActiveWithProfile(profile, 515 Browser* browser = chrome::FindLastActiveWithProfile(profile,
445 chrome::HOST_DESKTOP_TYPE_ASH); 516 chrome::HOST_DESKTOP_TYPE_ASH);
446 517
447 // If there is no browsers for the profile, bail out. Return true so warning 518 // If there is no browsers for the profile, bail out. Return true so warning
448 // about file type not being supported is not displayed. 519 // about file type not being supported is not displayed.
449 if (!browser) 520 if (!browser)
450 return true; 521 return true;
451 522
452 if (extension_id == kFileBrowserDomain) { 523 if (extension_id == kFileBrowserDomain) {
453 if (IsFileManagerPackaged()) { 524 if (IsFileManagerPackaged()) {
454 if (action_id == kFileBrowserGalleryTaskId || 525 if (action_id == kFileBrowserGalleryTaskId ||
455 action_id == kFileBrowserMountArchiveTaskId || 526 action_id == kFileBrowserMountArchiveTaskId ||
456 action_id == kFileBrowserPlayTaskId || 527 action_id == kFileBrowserPlayTaskId ||
457 action_id == kFileBrowserWatchTaskId) { 528 action_id == kFileBrowserWatchTaskId) {
458 ExecuteHandler(profile, extension_id, action_id, url); 529 ExecuteHandler(profile, extension_id, action_id, url,
530 file_handler_util::kTaskFile);
459 return true; 531 return true;
460 } 532 }
461 return ExecuteBuiltinHandler(browser, path, action_id); 533 return ExecuteBuiltinHandler(browser, path, action_id);
462 } 534 }
463 535
464 // Only two of the built-in File Browser tasks require opening the File 536 // Only two of the built-in File Browser tasks require opening the File
465 // Browser tab. 537 // Browser tab.
466 if (action_id == kFileBrowserGalleryTaskId || 538 if (action_id == kFileBrowserGalleryTaskId ||
467 action_id == kFileBrowserMountArchiveTaskId) { 539 action_id == kFileBrowserMountArchiveTaskId) {
468 // Tab reuse currently does not work for these two tasks. 540 // Tab reuse currently does not work for these two tasks.
469 // |gallery| tries to put the file url into the tab url but it does not 541 // |gallery| tries to put the file url into the tab url but it does not
470 // work on Chrome OS. 542 // work on Chrome OS.
471 // |mount-archive| does not even try. 543 // |mount-archive| does not even try.
472 OpenFileBrowserImpl(path, REUSE_SAME_PATH, ""); 544 OpenFileBrowserImpl(path, REUSE_SAME_PATH, "");
473 return true; 545 return true;
474 } 546 }
475 return ExecuteBuiltinHandler(browser, path, action_id); 547 return ExecuteBuiltinHandler(browser, path, action_id);
476 } 548 }
477 549
478 ExecuteHandler(profile, extension_id, action_id, url); 550 ExecuteHandler(profile, extension_id, action_id, url,
551 file_handler_util::kTaskFile);
479 return true; 552 return true;
480 } 553 }
481 554
482 // Reads JSON from a Google Docs file and extracts a document url. When the file 555 // Reads JSON from a Google Docs file and extracts a document url. When the file
483 // is not in GDoc format, returns a file URL for |file_path| as fallback. 556 // is not in GDoc format, returns a file URL for |file_path| as fallback.
484 GURL ReadUrlFromGDocOnBlockingPool(const base::FilePath& file_path) { 557 GURL ReadUrlFromGDocOnBlockingPool(const base::FilePath& file_path) {
485 const int64 kMaxGDocSize = 4096; 558 const int64 kMaxGDocSize = 4096;
486 int64 file_size = 0; 559 int64 file_size = 0;
487 if (!file_util::GetFileSize(file_path, &file_size) || 560 if (!file_util::GetFileSize(file_path, &file_size) ||
488 file_size > kMaxGDocSize) { 561 file_size > kMaxGDocSize) {
(...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after
918 991
919 // If a bundled plugin is enabled, we should open pdf/swf files in a tab. 992 // If a bundled plugin is enabled, we should open pdf/swf files in a tab.
920 bool ShouldBeOpenedWithPlugin(Profile* profile, const char* file_extension) { 993 bool ShouldBeOpenedWithPlugin(Profile* profile, const char* file_extension) {
921 if (LowerCaseEqualsASCII(file_extension, kPdfExtension)) 994 if (LowerCaseEqualsASCII(file_extension, kPdfExtension))
922 return IsPdfPluginEnabled(profile); 995 return IsPdfPluginEnabled(profile);
923 if (LowerCaseEqualsASCII(file_extension, kSwfExtension)) 996 if (LowerCaseEqualsASCII(file_extension, kSwfExtension))
924 return IsFlashPluginEnabled(profile); 997 return IsFlashPluginEnabled(profile);
925 return false; 998 return false;
926 } 999 }
927 1000
1001 std::string GetMimeTypeForPath(const base::FilePath& file_path) {
1002 const base::FilePath::StringType file_extension =
1003 StringToLowerASCII(file_path.Extension());
1004
1005 // TODO(thorogood): Rearchitect this call so it can run on the File thread;
1006 // GetMimeTypeFromFile requires this on Linux. Right now, we use
1007 // Chrome-level knowledge only.
1008 std::string mime_type;
1009 if (file_extension.empty() ||
1010 !net::GetWellKnownMimeTypeFromExtension(file_extension.substr(1),
1011 &mime_type)) {
1012 // If the file doesn't have an extension or its mime-type cannot be
1013 // determined, then indicate that it has the empty mime-type. This will
1014 // only be matched if the Web Intents accepts "*" or "*/*".
1015 return "";
1016 } else {
1017 return mime_type;
1018 }
1019 }
1020
928 } // namespace file_manager_util 1021 } // namespace file_manager_util
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/extensions/file_manager/file_manager_util.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698