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_tasks.h"
14 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
15 #include "chrome/browser/chromeos/file_manager/path_util.h"
16 #include "chrome/browser/chromeos/file_manager/url_util.h"
17 #include "chrome/browser/extensions/api/file_handlers/mime_util.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_finder.h"
20 #include "chrome/browser/ui/browser_window.h"
21 #include "chrome/browser/ui/simple_message_box.h"
22 #include "chrome/grit/generated_resources.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/user_metrics.h"
25 #include "storage/browser/fileapi/file_system_backend.h"
26 #include "storage/browser/fileapi/file_system_context.h"
27 #include "storage/browser/fileapi/file_system_operation_runner.h"
28 #include "storage/browser/fileapi/file_system_url.h"
29 #include "ui/base/l10n/l10n_util.h"
31 using content::BrowserThread;
32 using storage::FileSystemURL;
34 namespace file_manager {
38 // Shows a warning message box saying that the file could not be opened.
39 void ShowWarningMessageBox(Profile* profile,
40 const base::FilePath& file_path,
42 Browser* browser = chrome::FindTabbedBrowser(
43 profile, false, chrome::HOST_DESKTOP_TYPE_ASH);
44 chrome::ShowMessageBox(
45 browser ? browser->window()->GetNativeWindow() : NULL,
46 l10n_util::GetStringFUTF16(
47 IDS_FILE_BROWSER_ERROR_VIEWING_FILE_TITLE,
48 base::UTF8ToUTF16(file_path.BaseName().AsUTF8Unsafe())),
49 l10n_util::GetStringUTF16(message_id),
50 chrome::MESSAGE_BOX_TYPE_WARNING);
53 // Executes the |task| for the file specified by |url|.
54 void ExecuteFileTaskForUrl(Profile* profile,
55 const file_tasks::TaskDescriptor& task,
57 storage::FileSystemContext* file_system_context =
58 GetFileSystemContextForExtensionId(profile, kFileManagerAppId);
60 file_tasks::ExecuteFileTask(
62 GetFileManagerMainPageUrl(), // Executing the task on behalf of Files.app.
64 std::vector<FileSystemURL>(1, file_system_context->CrackURL(url)),
65 file_tasks::FileTaskFinishedCallback());
68 // Opens the file manager for the specified |url|. Used to implement
69 // internal handlers of special action IDs:
71 // "open" - Open the file manager for the given folder.
72 // "auto-open" - Open the file manager for the given removal drive and close
73 // the file manager when the removal drive is unmounted.
74 // "select" - Open the file manager for the given file. The folder containing
75 // the file will be opened with the file selected.
76 void OpenFileManagerWithInternalActionId(Profile* profile,
78 const std::string& action_id) {
79 DCHECK(action_id == "auto-open" ||
80 action_id == "open" ||
81 action_id == "select");
82 content::RecordAction(base::UserMetricsAction("ShowFileBrowserFullTab"));
84 file_tasks::TaskDescriptor task(kFileManagerAppId,
85 file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER,
87 ExecuteFileTaskForUrl(profile, task, url);
90 // Opens the file with fetched MIME type and calls the callback.
91 void OpenFileWithMimeType(Profile* profile,
92 const base::FilePath& path,
94 const base::Callback<void(bool)>& callback,
95 const std::string& mime_type) {
96 extensions::app_file_handler_util::PathAndMimeTypeSet path_mime_set;
97 path_mime_set.insert(std::make_pair(path, mime_type));
99 std::vector<GURL> file_urls;
100 file_urls.push_back(url);
102 std::vector<file_tasks::FullTaskDescriptor> tasks;
103 file_tasks::FindAllTypesOfTasks(
105 drive::util::GetDriveAppRegistryByProfile(profile),
115 const file_tasks::FullTaskDescriptor* chosen_task = &tasks[0];
116 for (size_t i = 0; i < tasks.size(); ++i) {
117 if (tasks[i].is_default()) {
118 chosen_task = &tasks[i];
123 ExecuteFileTaskForUrl(profile, chosen_task->task_descriptor(), url);
127 // Opens the file specified by |url| by finding and executing a file task for
128 // the file. In case of success, calls |callback| with true. Otherwise the
129 // returned value is false.
130 void OpenFile(Profile* profile,
131 const base::FilePath& path,
133 const base::Callback<void(bool)>& callback) {
134 extensions::app_file_handler_util::GetMimeTypeForLocalPath(
137 base::Bind(&OpenFileWithMimeType, profile, path, url, callback));
140 // Called when execution of ContinueOpenItem() is completed.
141 void OnContinueOpenItemCompleted(Profile* profile,
142 const base::FilePath& file_path,
146 if (file_path.Extension() == FILE_PATH_LITERAL(".dmg"))
147 message = IDS_FILE_BROWSER_ERROR_VIEWING_FILE_FOR_DMG;
148 else if (file_path.Extension() == FILE_PATH_LITERAL(".exe") ||
149 file_path.Extension() == FILE_PATH_LITERAL(".msi"))
150 message = IDS_FILE_BROWSER_ERROR_VIEWING_FILE_FOR_EXECUTABLE;
152 message = IDS_FILE_BROWSER_ERROR_VIEWING_FILE;
153 ShowWarningMessageBox(profile, file_path, message);
157 // Used to implement OpenItem().
158 void ContinueOpenItem(Profile* profile,
159 const base::FilePath& file_path,
161 base::File::Error error) {
162 DCHECK_CURRENTLY_ON(BrowserThread::UI);
164 if (error == base::File::FILE_OK) {
165 // A directory exists at |url|. Open it with the file manager.
166 OpenFileManagerWithInternalActionId(profile, url, "open");
168 // |url| should be a file. Open it.
172 base::Bind(&OnContinueOpenItemCompleted, profile, file_path));
176 // Converts the |given_path| passed from external callers to the form that the
177 // file manager can correctly handle. It first migrates old Drive/Download
178 // folder path to the new formats, and then converts path to filesystem URL.
180 // When conversion fails, it shows a warning dialog UI and returns false.
181 bool ConvertPath(Profile* profile,
182 const base::FilePath& given_path,
183 base::FilePath* path,
185 // The path may have been stored in preferences in old versions.
186 // We need migration here.
187 // TODO(kinaba): crbug.com/313539 remove it in the future.
188 if (!util::MigratePathFromOldFormat(profile, given_path, path))
191 if (!ConvertAbsoluteFilePathToFileSystemUrl(
192 profile, *path, kFileManagerAppId, url)) {
193 ShowWarningMessageBox(profile, *path,
194 IDS_FILE_BROWSER_ERROR_UNRESOLVABLE_FILE);
202 void OpenRemovableDrive(Profile* profile, const base::FilePath& file_path) {
203 DCHECK_CURRENTLY_ON(BrowserThread::UI);
205 base::FilePath converted_path;
207 if (!ConvertPath(profile, file_path, &converted_path, &url))
210 OpenFileManagerWithInternalActionId(profile, url, "auto-open");
213 void OpenItem(Profile* profile, const base::FilePath& file_path) {
214 DCHECK_CURRENTLY_ON(BrowserThread::UI);
216 base::FilePath converted_path;
218 if (!ConvertPath(profile, file_path, &converted_path, &url))
221 CheckIfDirectoryExists(
222 GetFileSystemContextForExtensionId(profile, kFileManagerAppId),
224 base::Bind(&ContinueOpenItem, profile, converted_path, url));
227 void ShowItemInFolder(Profile* profile, const base::FilePath& file_path) {
228 DCHECK_CURRENTLY_ON(BrowserThread::UI);
230 base::FilePath converted_path;
232 if (!ConvertPath(profile, file_path, &converted_path, &url))
235 // This action changes the selection so we do not reuse existing tabs.
236 OpenFileManagerWithInternalActionId(profile, url, "select");
240 } // namespace file_manager