Home | History | Annotate | Download | only in file_manager
      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/file_manager/open_util.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/files/file_path.h"
      9 #include "base/logging.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "chrome/browser/chromeos/drive/file_system_util.h"
     12 #include "chrome/browser/chromeos/file_manager/app_id.h"
     13 #include "chrome/browser/chromeos/file_manager/file_browser_handlers.h"
     14 #include "chrome/browser/chromeos/file_manager/file_tasks.h"
     15 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
     16 #include "chrome/browser/chromeos/file_manager/mime_util.h"
     17 #include "chrome/browser/chromeos/file_manager/url_util.h"
     18 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
     19 #include "chrome/browser/extensions/extension_service.h"
     20 #include "chrome/browser/extensions/extension_system.h"
     21 #include "chrome/browser/profiles/profile.h"
     22 #include "chrome/browser/profiles/profile_manager.h"
     23 #include "chrome/browser/ui/browser.h"
     24 #include "chrome/browser/ui/browser_finder.h"
     25 #include "chrome/browser/ui/browser_tabstrip.h"
     26 #include "chrome/browser/ui/browser_window.h"
     27 #include "chrome/browser/ui/extensions/application_launch.h"
     28 #include "chrome/browser/ui/simple_message_box.h"
     29 #include "chrome/common/extensions/api/file_browser_handlers/file_browser_handler.h"
     30 #include "content/public/browser/browser_thread.h"
     31 #include "content/public/browser/storage_partition.h"
     32 #include "content/public/browser/user_metrics.h"
     33 #include "google_apis/drive/task_util.h"
     34 #include "grit/generated_resources.h"
     35 #include "ui/base/l10n/l10n_util.h"
     36 #include "webkit/browser/fileapi/file_system_backend.h"
     37 #include "webkit/browser/fileapi/file_system_context.h"
     38 #include "webkit/browser/fileapi/file_system_operation_runner.h"
     39 #include "webkit/browser/fileapi/file_system_url.h"
     40 
     41 using content::BrowserContext;
     42 using content::BrowserThread;
     43 using content::UserMetricsAction;
     44 using extensions::Extension;
     45 using extensions::app_file_handler_util::FindFileHandlersForFiles;
     46 using extensions::app_file_handler_util::PathAndMimeTypeSet;
     47 using fileapi::FileSystemURL;
     48 
     49 namespace file_manager {
     50 namespace util {
     51 namespace {
     52 
     53 // Shows a warning message box saying that the file could not be opened.
     54 void ShowWarningMessageBox(Profile* profile, const base::FilePath& file_path) {
     55   Browser* browser = chrome::FindTabbedBrowser(
     56       profile, false, chrome::HOST_DESKTOP_TYPE_ASH);
     57   chrome::ShowMessageBox(
     58       browser ? browser->window()->GetNativeWindow() : NULL,
     59       l10n_util::GetStringFUTF16(
     60           IDS_FILE_BROWSER_ERROR_VIEWING_FILE_TITLE,
     61           UTF8ToUTF16(file_path.BaseName().value())),
     62       l10n_util::GetStringUTF16(IDS_FILE_BROWSER_ERROR_VIEWING_FILE),
     63       chrome::MESSAGE_BOX_TYPE_WARNING);
     64 }
     65 
     66 // Grants file system access to the file manager.
     67 bool GrantFileSystemAccessToFileBrowser(Profile* profile) {
     68   // The file manager always runs in the site for its extension id, so that
     69   // is the site for which file access permissions should be granted.
     70   fileapi::ExternalFileSystemBackend* backend =
     71       GetFileSystemContextForExtensionId(
     72           profile, kFileManagerAppId)->external_backend();
     73   if (!backend)
     74     return false;
     75   backend->GrantFullAccessToExtension(kFileManagerAppId);
     76   return true;
     77 }
     78 
     79 // Executes the |task| for the file specified by |url|.
     80 void ExecuteFileTaskForUrl(Profile* profile,
     81                            const file_tasks::TaskDescriptor& task,
     82                            const GURL& url) {
     83   // If the file manager has not been open yet then it did not request access
     84   // to the file system. Do it now.
     85   if (!GrantFileSystemAccessToFileBrowser(profile))
     86     return;
     87 
     88   fileapi::FileSystemContext* file_system_context =
     89       GetFileSystemContextForExtensionId(
     90           profile, kFileManagerAppId);
     91 
     92   // We are executing the task on behalf of the file manager.
     93   const GURL source_url = GetFileManagerMainPageUrl();
     94   std::vector<FileSystemURL> urls;
     95   urls.push_back(file_system_context->CrackURL(url));
     96 
     97   file_tasks::ExecuteFileTask(
     98       profile,
     99       source_url,
    100       kFileManagerAppId,
    101       task,
    102       urls,
    103       file_tasks::FileTaskFinishedCallback());
    104 }
    105 
    106 // Opens the file manager for the specified |file_path|. Used to implement
    107 // internal handlers of special action IDs:
    108 //
    109 // "open" - Open the file manager for the given folder.
    110 // "auto-open" - Open the file manager for the given removal drive and close
    111 //               the file manager when the removal drive is unmounted.
    112 // "select" - Open the file manager for the given file. The folder containing
    113 //            the file will be opened with the file selected.
    114 void OpenFileManagerWithInternalActionId(Profile* profile,
    115                                          const base::FilePath& file_path,
    116                                          const std::string& action_id) {
    117   DCHECK(action_id == "auto-open" ||
    118          action_id == "open" ||
    119          action_id == "select");
    120 
    121   content::RecordAction(UserMetricsAction("ShowFileBrowserFullTab"));
    122 
    123   GURL url;
    124   if (!ConvertAbsoluteFilePathToFileSystemUrl(
    125           profile, file_path, kFileManagerAppId, &url))
    126     return;
    127 
    128   file_tasks::TaskDescriptor task(kFileManagerAppId,
    129                                   file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER,
    130                                   action_id);
    131   ExecuteFileTaskForUrl(profile, task, url);
    132 }
    133 
    134 // Opens the file specified by |file_path| by finding and executing a file
    135 // task for the file. Returns false if failed to open the file (i.e. no file
    136 // task is found).
    137 bool OpenFile(Profile* profile, const base::FilePath& file_path) {
    138   GURL url;
    139   if (!ConvertAbsoluteFilePathToFileSystemUrl(
    140           profile, file_path, kFileManagerAppId, &url))
    141     return false;
    142 
    143   // The file is opened per the file extension, hence extension-less files
    144   // cannot be opened properly.
    145   std::string mime_type = GetMimeTypeForPath(file_path);
    146   extensions::app_file_handler_util::PathAndMimeTypeSet path_mime_set;
    147   path_mime_set.insert(std::make_pair(file_path, mime_type));
    148 
    149   std::vector<GURL> file_urls;
    150   file_urls.push_back(url);
    151 
    152   std::vector<file_tasks::FullTaskDescriptor> tasks;
    153   file_tasks::FindAllTypesOfTasks(
    154       profile,
    155       drive::util::GetDriveAppRegistryByProfile(profile),
    156       path_mime_set,
    157       file_urls,
    158       &tasks);
    159   if (tasks.empty())
    160     return false;
    161 
    162   const file_tasks::FullTaskDescriptor* chosen_task = &tasks[0];
    163   for (size_t i = 0; i < tasks.size(); ++i) {
    164     if (tasks[i].is_default()) {
    165       chosen_task = &tasks[i];
    166       break;
    167     }
    168   }
    169 
    170   ExecuteFileTaskForUrl(profile, chosen_task->task_descriptor(), url);
    171   return true;
    172 }
    173 
    174 // Used to implement OpenItem().
    175 void ContinueOpenItem(Profile* profile,
    176                       const base::FilePath& file_path,
    177                       base::PlatformFileError error) {
    178   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    179 
    180   if (error == base::PLATFORM_FILE_OK) {
    181     // A directory exists at |file_path|. Open it with the file manager.
    182     OpenFileManagerWithInternalActionId(profile, file_path, "open");
    183   } else {
    184     // |file_path| should be a file. Open it.
    185     if (!OpenFile(profile, file_path))
    186       ShowWarningMessageBox(profile, file_path);
    187   }
    188 }
    189 
    190 // Used to implement CheckIfDirectoryExists().
    191 void CheckIfDirectoryExistsOnIOThread(
    192     scoped_refptr<fileapi::FileSystemContext> file_system_context,
    193     const GURL& url,
    194     const fileapi::FileSystemOperationRunner::StatusCallback& callback) {
    195   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    196 
    197   fileapi::FileSystemURL file_system_url = file_system_context->CrackURL(url);
    198   file_system_context->operation_runner()->DirectoryExists(
    199       file_system_url, callback);
    200 }
    201 
    202 // Checks if a directory exists at |url|.
    203 void CheckIfDirectoryExists(
    204     scoped_refptr<fileapi::FileSystemContext> file_system_context,
    205     const GURL& url,
    206     const fileapi::FileSystemOperationRunner::StatusCallback& callback) {
    207   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    208 
    209   BrowserThread::PostTask(
    210       BrowserThread::IO, FROM_HERE,
    211       base::Bind(&CheckIfDirectoryExistsOnIOThread,
    212                  file_system_context,
    213                  url,
    214                  google_apis::CreateRelayCallback(callback)));
    215 }
    216 
    217 }  // namespace
    218 
    219 void OpenRemovableDrive(Profile* profile, const base::FilePath& file_path) {
    220   OpenFileManagerWithInternalActionId(profile, file_path, "auto-open");
    221 }
    222 
    223 void OpenItem(Profile* profile, const base::FilePath& file_path) {
    224   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    225 
    226   GURL url;
    227   if (!ConvertAbsoluteFilePathToFileSystemUrl(
    228           profile, file_path, kFileManagerAppId, &url) ||
    229       !GrantFileSystemAccessToFileBrowser(profile)) {
    230     ShowWarningMessageBox(profile, file_path);
    231     return;
    232   }
    233 
    234   scoped_refptr<fileapi::FileSystemContext> file_system_context =
    235       GetFileSystemContextForExtensionId(
    236           profile, kFileManagerAppId);
    237 
    238   CheckIfDirectoryExists(file_system_context, url,
    239                          base::Bind(&ContinueOpenItem, profile, file_path));
    240 }
    241 
    242 void ShowItemInFolder(Profile* profile, const base::FilePath& file_path) {
    243   // This action changes the selection so we do not reuse existing tabs.
    244   OpenFileManagerWithInternalActionId(profile, file_path, "select");
    245 }
    246 
    247 }  // namespace util
    248 }  // namespace file_manager
    249