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.
5 #include "chrome/browser/chromeos/file_manager/open_util.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/path_util.h"
18 #include "chrome/browser/chromeos/file_manager/url_util.h"
19 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/browser_finder.h"
24 #include "chrome/browser/ui/browser_tabstrip.h"
25 #include "chrome/browser/ui/browser_window.h"
26 #include "chrome/browser/ui/extensions/application_launch.h"
27 #include "chrome/browser/ui/simple_message_box.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/storage_partition.h"
30 #include "content/public/browser/user_metrics.h"
31 #include "extensions/browser/extension_system.h"
32 #include "google_apis/drive/task_util.h"
33 #include "grit/generated_resources.h"
34 #include "ui/base/l10n/l10n_util.h"
35 #include "webkit/browser/fileapi/file_system_backend.h"
36 #include "webkit/browser/fileapi/file_system_context.h"
37 #include "webkit/browser/fileapi/file_system_operation_runner.h"
38 #include "webkit/browser/fileapi/file_system_url.h"
40 using content::BrowserThread;
41 using extensions::Extension;
42 using extensions::app_file_handler_util::FindFileHandlersForFiles;
43 using extensions::app_file_handler_util::PathAndMimeTypeSet;
44 using fileapi::FileSystemURL;
46 namespace file_manager {
50 // Shows a warning message box saying that the file could not be opened.
51 void ShowWarningMessageBox(Profile* profile, const base::FilePath& file_path) {
52 Browser* browser = chrome::FindTabbedBrowser(
53 profile, false, chrome::HOST_DESKTOP_TYPE_ASH);
54 chrome::ShowMessageBox(
55 browser ? browser->window()->GetNativeWindow() : NULL,
56 l10n_util::GetStringFUTF16(
57 IDS_FILE_BROWSER_ERROR_VIEWING_FILE_TITLE,
58 base::UTF8ToUTF16(file_path.BaseName().AsUTF8Unsafe())),
59 l10n_util::GetStringUTF16(IDS_FILE_BROWSER_ERROR_VIEWING_FILE),
60 chrome::MESSAGE_BOX_TYPE_WARNING);
63 // Grants file system access to the file manager.
64 bool GrantFileSystemAccessToFileBrowser(Profile* profile) {
65 // The file manager always runs in the site for its extension id, so that
66 // is the site for which file access permissions should be granted.
67 fileapi::ExternalFileSystemBackend* backend =
68 GetFileSystemContextForExtensionId(
69 profile, kFileManagerAppId)->external_backend();
72 backend->GrantFullAccessToExtension(kFileManagerAppId);
76 // Executes the |task| for the file specified by |url|.
77 void ExecuteFileTaskForUrl(Profile* profile,
78 const file_tasks::TaskDescriptor& task,
80 fileapi::FileSystemContext* file_system_context =
81 GetFileSystemContextForExtensionId(profile, kFileManagerAppId);
83 file_tasks::ExecuteFileTask(
85 GetFileManagerMainPageUrl(), // Executing the task on behalf of Files.app.
87 std::vector<FileSystemURL>(1, file_system_context->CrackURL(url)),
88 file_tasks::FileTaskFinishedCallback());
91 // Opens the file manager for the specified |file_path|. Used to implement
92 // internal handlers of special action IDs:
94 // "open" - Open the file manager for the given folder.
95 // "auto-open" - Open the file manager for the given removal drive and close
96 // the file manager when the removal drive is unmounted.
97 // "select" - Open the file manager for the given file. The folder containing
98 // the file will be opened with the file selected.
99 void OpenFileManagerWithInternalActionId(Profile* profile,
100 const base::FilePath& file_path,
101 const std::string& action_id) {
102 DCHECK(action_id == "auto-open" ||
103 action_id == "open" ||
104 action_id == "select");
106 content::RecordAction(base::UserMetricsAction("ShowFileBrowserFullTab"));
109 if (!ConvertAbsoluteFilePathToFileSystemUrl(
110 profile, file_path, kFileManagerAppId, &url))
113 file_tasks::TaskDescriptor task(kFileManagerAppId,
114 file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER,
116 ExecuteFileTaskForUrl(profile, task, url);
119 // Opens the file specified by |file_path| by finding and executing a file
120 // task for the file. Returns false if failed to open the file (i.e. no file
122 bool OpenFile(Profile* profile, const base::FilePath& file_path) {
124 if (!ConvertAbsoluteFilePathToFileSystemUrl(
125 profile, file_path, kFileManagerAppId, &url))
128 // The file is opened per the file extension, hence extension-less files
129 // cannot be opened properly.
130 std::string mime_type = GetMimeTypeForPath(file_path);
131 extensions::app_file_handler_util::PathAndMimeTypeSet path_mime_set;
132 path_mime_set.insert(std::make_pair(file_path, mime_type));
134 std::vector<GURL> file_urls;
135 file_urls.push_back(url);
137 std::vector<file_tasks::FullTaskDescriptor> tasks;
138 file_tasks::FindAllTypesOfTasks(
140 drive::util::GetDriveAppRegistryByProfile(profile),
147 const file_tasks::FullTaskDescriptor* chosen_task = &tasks[0];
148 for (size_t i = 0; i < tasks.size(); ++i) {
149 if (tasks[i].is_default()) {
150 chosen_task = &tasks[i];
155 ExecuteFileTaskForUrl(profile, chosen_task->task_descriptor(), url);
159 // Used to implement OpenItem().
160 void ContinueOpenItem(Profile* profile,
161 const base::FilePath& file_path,
162 base::File::Error error) {
163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
165 if (error == base::File::FILE_OK) {
166 // A directory exists at |file_path|. Open it with the file manager.
167 OpenFileManagerWithInternalActionId(profile, file_path, "open");
169 // |file_path| should be a file. Open it.
170 if (!OpenFile(profile, file_path))
171 ShowWarningMessageBox(profile, file_path);
175 // Used to implement CheckIfDirectoryExists().
176 void CheckIfDirectoryExistsOnIOThread(
177 scoped_refptr<fileapi::FileSystemContext> file_system_context,
179 const fileapi::FileSystemOperationRunner::StatusCallback& callback) {
180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
182 fileapi::FileSystemURL file_system_url = file_system_context->CrackURL(url);
183 file_system_context->operation_runner()->DirectoryExists(
184 file_system_url, callback);
187 // Checks if a directory exists at |url|.
188 void CheckIfDirectoryExists(
189 scoped_refptr<fileapi::FileSystemContext> file_system_context,
191 const fileapi::FileSystemOperationRunner::StatusCallback& callback) {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
194 BrowserThread::PostTask(
195 BrowserThread::IO, FROM_HERE,
196 base::Bind(&CheckIfDirectoryExistsOnIOThread,
199 google_apis::CreateRelayCallback(callback)));
204 void OpenRemovableDrive(Profile* profile, const base::FilePath& file_path) {
205 OpenFileManagerWithInternalActionId(profile, file_path, "auto-open");
208 void OpenItem(Profile* profile, const base::FilePath& file_path) {
209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
211 // The path may have been stored in preferences in old versions.
212 // We need migration here.
213 // TODO(kinaba): crbug.com/313539 remove it in the future.
215 if (!util::MigratePathFromOldFormat(profile, file_path, &path))
219 if (!ConvertAbsoluteFilePathToFileSystemUrl(
220 profile, path, kFileManagerAppId, &url) ||
221 !GrantFileSystemAccessToFileBrowser(profile)) {
222 ShowWarningMessageBox(profile, path);
226 scoped_refptr<fileapi::FileSystemContext> file_system_context =
227 GetFileSystemContextForExtensionId(
228 profile, kFileManagerAppId);
230 CheckIfDirectoryExists(file_system_context, url,
231 base::Bind(&ContinueOpenItem, profile, path));
234 void ShowItemInFolder(Profile* profile, const base::FilePath& file_path) {
235 // The path may have been stored in preferences in old versions.
236 // We need migration here.
237 // TODO(kinaba): crbug.com/313539 remove it in the future.
239 if (!util::MigratePathFromOldFormat(profile, file_path, &path))
242 // This action changes the selection so we do not reuse existing tabs.
243 OpenFileManagerWithInternalActionId(profile, path, "select");
247 } // namespace file_manager