| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 #include "chrome/browser/chromeos/extensions/file_manager_util.h" | |
| 5 | |
| 6 #include "base/bind.h" | |
| 7 #include "base/json/json_writer.h" | |
| 8 #include "base/logging.h" | |
| 9 #include "base/metrics/histogram.h" | |
| 10 #include "base/path_service.h" | |
| 11 #include "base/string_util.h" | |
| 12 #include "base/utf_string_conversions.h" | |
| 13 #include "base/values.h" | |
| 14 #include "chrome/browser/plugin_prefs.h" | |
| 15 #include "chrome/browser/profiles/profile.h" | |
| 16 #include "chrome/browser/simple_message_box.h" | |
| 17 #include "chrome/browser/ui/browser.h" | |
| 18 #include "chrome/browser/ui/browser_list.h" | |
| 19 #include "chrome/browser/ui/browser_window.h" | |
| 20 #include "chrome/common/chrome_paths.h" | |
| 21 #include "chrome/common/url_constants.h" | |
| 22 #include "content/browser/plugin_service.h" | |
| 23 #include "content/browser/user_metrics.h" | |
| 24 #include "content/public/browser/browser_thread.h" | |
| 25 #include "grit/generated_resources.h" | |
| 26 #include "net/base/escape.h" | |
| 27 #include "ui/base/l10n/l10n_util.h" | |
| 28 #include "webkit/fileapi/file_system_context.h" | |
| 29 #include "webkit/fileapi/file_system_mount_point_provider.h" | |
| 30 #include "webkit/fileapi/file_system_util.h" | |
| 31 | |
| 32 #if defined(OS_CHROMEOS) | |
| 33 #include "chrome/browser/chromeos/media/media_player.h" | |
| 34 #endif | |
| 35 | |
| 36 using content::BrowserThread; | |
| 37 | |
| 38 #define FILEBROWSER_DOMAIN "hhaomjibdihmijegdhdafkllkbggdgoj" | |
| 39 const char kFileBrowserDomain[] = FILEBROWSER_DOMAIN; | |
| 40 | |
| 41 namespace file_manager_util { | |
| 42 namespace { | |
| 43 | |
| 44 #define FILEBROWSER_URL(PATH) \ | |
| 45 ("chrome-extension://" FILEBROWSER_DOMAIN "/" PATH) | |
| 46 // This is the "well known" url for the file manager extension from | |
| 47 // browser/resources/file_manager. In the future we may provide a way to swap | |
| 48 // out this file manager for an aftermarket part, but not yet. | |
| 49 const char kFileBrowserExtensionUrl[] = FILEBROWSER_URL(""); | |
| 50 const char kBaseFileBrowserUrl[] = FILEBROWSER_URL("main.html"); | |
| 51 const char kMediaPlayerUrl[] = FILEBROWSER_URL("mediaplayer.html"); | |
| 52 const char kMediaPlayerPlaylistUrl[] = FILEBROWSER_URL("playlist.html"); | |
| 53 #undef FILEBROWSER_URL | |
| 54 #undef FILEBROWSER_DOMAIN | |
| 55 | |
| 56 const char kPdfExtension[] = ".pdf"; | |
| 57 // List of file extension we can open in tab. | |
| 58 const char* kBrowserSupportedExtensions[] = { | |
| 59 #if defined(GOOGLE_CHROME_BUILD) | |
| 60 ".pdf", | |
| 61 #endif | |
| 62 ".bmp", ".jpg", ".jpeg", ".png", ".webp", ".gif", ".txt", ".html", ".htm" | |
| 63 }; | |
| 64 // List of file extension that can be handled with the media player. | |
| 65 const char* kAVExtensions[] = { | |
| 66 #if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS) | |
| 67 ".3gp", ".avi", ".mp3", ".mp4", ".m4v", ".mov", ".m4a", | |
| 68 #endif | |
| 69 ".flac", ".ogm", ".ogv", ".ogx", ".ogg", ".oga", ".wav", ".webm", | |
| 70 /* TODO(zelidrag): Add unsupported ones as we enable them: | |
| 71 ".mkv", ".divx", ".xvid", ".wmv", ".asf", ".mpeg", ".mpg", | |
| 72 ".wma", ".aiff", | |
| 73 */ | |
| 74 }; | |
| 75 | |
| 76 // List of all extensions we want to be shown in histogram that keep track of | |
| 77 // files that were unsuccessfully tried to be opened. | |
| 78 // The list has to be synced with histogram values. | |
| 79 const char* kUMATrackingExtensions[] = { | |
| 80 "other", ".doc", ".docx", ".odt", ".rtf", ".pdf", ".ppt", ".pptx", ".odp", | |
| 81 ".xls", ".xlsx", ".ods", ".csv", ".odf", ".rar", ".asf", ".wma", ".wmv", | |
| 82 ".mov", ".mpg", ".log" | |
| 83 }; | |
| 84 | |
| 85 bool IsSupportedBrowserExtension(const char* ext) { | |
| 86 for (size_t i = 0; i < arraysize(kBrowserSupportedExtensions); i++) { | |
| 87 if (base::strcasecmp(ext, kBrowserSupportedExtensions[i]) == 0) { | |
| 88 return true; | |
| 89 } | |
| 90 } | |
| 91 return false; | |
| 92 } | |
| 93 | |
| 94 bool IsSupportedAVExtension(const char* ext) { | |
| 95 for (size_t i = 0; i < arraysize(kAVExtensions); i++) { | |
| 96 if (base::strcasecmp(ext, kAVExtensions[i]) == 0) { | |
| 97 return true; | |
| 98 } | |
| 99 } | |
| 100 return false; | |
| 101 } | |
| 102 | |
| 103 // If pdf plugin is enabled, we should open pdf files in a tab. | |
| 104 bool ShouldBeOpenedWithPdfPlugin(const char* ext) { | |
| 105 if (base::strcasecmp(ext, kPdfExtension) != 0) | |
| 106 return false; | |
| 107 | |
| 108 Browser* browser = BrowserList::GetLastActive(); | |
| 109 if (!browser) | |
| 110 return false; | |
| 111 | |
| 112 FilePath pdf_path; | |
| 113 PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path); | |
| 114 | |
| 115 webkit::WebPluginInfo plugin; | |
| 116 if (!PluginService::GetInstance()->GetPluginInfoByPath(pdf_path, &plugin)) | |
| 117 return false; | |
| 118 | |
| 119 PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(browser->profile()); | |
| 120 if (!plugin_prefs) | |
| 121 return false; | |
| 122 | |
| 123 return plugin_prefs->IsPluginEnabled(plugin); | |
| 124 } | |
| 125 | |
| 126 // Returns index |ext| has in the |array|. If there is no |ext| in |array|, last | |
| 127 // element's index is return (last element should have irrelevant value). | |
| 128 int UMAExtensionIndex(const char *ext, | |
| 129 const char** array, | |
| 130 size_t array_size) { | |
| 131 for (size_t i = 0; i < array_size; i++) { | |
| 132 if (base::strcasecmp(ext, array[i]) == 0) { | |
| 133 return i; | |
| 134 } | |
| 135 } | |
| 136 return 0; | |
| 137 } | |
| 138 | |
| 139 // Convert numeric dialog type to a string. | |
| 140 std::string GetDialogTypeAsString( | |
| 141 SelectFileDialog::Type dialog_type) { | |
| 142 std::string type_str; | |
| 143 switch (dialog_type) { | |
| 144 case SelectFileDialog::SELECT_NONE: | |
| 145 type_str = "full-page"; | |
| 146 break; | |
| 147 | |
| 148 case SelectFileDialog::SELECT_FOLDER: | |
| 149 type_str = "folder"; | |
| 150 break; | |
| 151 | |
| 152 case SelectFileDialog::SELECT_SAVEAS_FILE: | |
| 153 type_str = "saveas-file"; | |
| 154 break; | |
| 155 | |
| 156 case SelectFileDialog::SELECT_OPEN_FILE: | |
| 157 type_str = "open-file"; | |
| 158 break; | |
| 159 | |
| 160 case SelectFileDialog::SELECT_OPEN_MULTI_FILE: | |
| 161 type_str = "open-multi-file"; | |
| 162 break; | |
| 163 | |
| 164 default: | |
| 165 NOTREACHED(); | |
| 166 } | |
| 167 | |
| 168 return type_str; | |
| 169 } | |
| 170 | |
| 171 } // namespace | |
| 172 | |
| 173 GURL GetFileBrowserExtensionUrl() { | |
| 174 return GURL(kFileBrowserExtensionUrl); | |
| 175 } | |
| 176 | |
| 177 GURL GetFileBrowserUrl() { | |
| 178 return GURL(kBaseFileBrowserUrl); | |
| 179 } | |
| 180 | |
| 181 GURL GetMediaPlayerUrl() { | |
| 182 return GURL(kMediaPlayerUrl); | |
| 183 } | |
| 184 | |
| 185 GURL GetMediaPlayerPlaylistUrl() { | |
| 186 return GURL(kMediaPlayerPlaylistUrl); | |
| 187 } | |
| 188 | |
| 189 bool ConvertFileToFileSystemUrl( | |
| 190 Profile* profile, const FilePath& full_file_path, const GURL& origin_url, | |
| 191 GURL* url) { | |
| 192 FilePath virtual_path; | |
| 193 if (!ConvertFileToRelativeFileSystemPath(profile, full_file_path, | |
| 194 &virtual_path)) { | |
| 195 return false; | |
| 196 } | |
| 197 | |
| 198 GURL base_url = fileapi::GetFileSystemRootURI(origin_url, | |
| 199 fileapi::kFileSystemTypeExternal); | |
| 200 *url = GURL(base_url.spec() + virtual_path.value()); | |
| 201 return true; | |
| 202 } | |
| 203 | |
| 204 bool ConvertFileToRelativeFileSystemPath( | |
| 205 Profile* profile, const FilePath& full_file_path, FilePath* virtual_path) { | |
| 206 fileapi::FileSystemPathManager* path_manager = | |
| 207 profile->GetFileSystemContext()->path_manager(); | |
| 208 fileapi::ExternalFileSystemMountPointProvider* provider = | |
| 209 path_manager->external_provider(); | |
| 210 if (!provider) | |
| 211 return false; | |
| 212 | |
| 213 // Find if this file path is managed by the external provider. | |
| 214 if (!provider->GetVirtualPath(full_file_path, virtual_path)) | |
| 215 return false; | |
| 216 | |
| 217 return true; | |
| 218 } | |
| 219 | |
| 220 GURL GetFileBrowserUrlWithParams( | |
| 221 SelectFileDialog::Type type, | |
| 222 const string16& title, | |
| 223 const FilePath& default_virtual_path, | |
| 224 const SelectFileDialog::FileTypeInfo* file_types, | |
| 225 int file_type_index, | |
| 226 const FilePath::StringType& default_extension) { | |
| 227 DictionaryValue arg_value; | |
| 228 arg_value.SetString("type", GetDialogTypeAsString(type)); | |
| 229 arg_value.SetString("title", title); | |
| 230 arg_value.SetString("defaultPath", default_virtual_path.value()); | |
| 231 arg_value.SetString("defaultExtension", default_extension); | |
| 232 | |
| 233 if (file_types) { | |
| 234 ListValue* types_list = new ListValue(); | |
| 235 for (size_t i = 0; i < file_types->extensions.size(); ++i) { | |
| 236 ListValue* extensions_list = new ListValue(); | |
| 237 for (size_t j = 0; j < file_types->extensions[i].size(); ++j) { | |
| 238 extensions_list->Set( | |
| 239 i, Value::CreateStringValue(file_types->extensions[i][j])); | |
| 240 } | |
| 241 | |
| 242 DictionaryValue* dict = new DictionaryValue(); | |
| 243 dict->Set("extensions", extensions_list); | |
| 244 | |
| 245 if (i < file_types->extension_description_overrides.size()) { | |
| 246 string16 desc = file_types->extension_description_overrides[i]; | |
| 247 dict->SetString("description", desc); | |
| 248 } | |
| 249 | |
| 250 dict->SetBoolean("selected", | |
| 251 (static_cast<size_t>(file_type_index) == i)); | |
| 252 | |
| 253 types_list->Set(i, dict); | |
| 254 } | |
| 255 arg_value.Set("typeList", types_list); | |
| 256 } | |
| 257 | |
| 258 std::string json_args; | |
| 259 base::JSONWriter::Write(&arg_value, false, &json_args); | |
| 260 | |
| 261 // kChromeUIFileManagerURL could not be used since query parameters are not | |
| 262 // supported for it. | |
| 263 std::string url = GetFileBrowserUrl().spec() + | |
| 264 '?' + net::EscapeUrlEncodedData(json_args, false); | |
| 265 return GURL(url); | |
| 266 } | |
| 267 | |
| 268 void ViewFolder(const FilePath& dir) { | |
| 269 Browser* browser = BrowserList::GetLastActive(); | |
| 270 if (!browser) | |
| 271 return; | |
| 272 | |
| 273 FilePath virtual_path; | |
| 274 if (!ConvertFileToRelativeFileSystemPath(browser->profile(), dir, | |
| 275 &virtual_path)) { | |
| 276 return; | |
| 277 } | |
| 278 | |
| 279 std::string url = chrome::kChromeUIFileManagerURL; | |
| 280 url += "#/" + net::EscapeUrlEncodedData(virtual_path.value(), false); | |
| 281 | |
| 282 UserMetrics::RecordAction(UserMetricsAction("ShowFileBrowserFullTab")); | |
| 283 browser->ShowSingletonTabRespectRef(GURL(url)); | |
| 284 } | |
| 285 | |
| 286 void ViewItem(const FilePath& full_path, bool enqueue) { | |
| 287 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
| 288 bool result = BrowserThread::PostTask( | |
| 289 BrowserThread::UI, FROM_HERE, | |
| 290 base::Bind(&ViewItem, full_path, enqueue)); | |
| 291 DCHECK(result); | |
| 292 return; | |
| 293 } | |
| 294 | |
| 295 // There is nothing we can do if the browser is not present. | |
| 296 Browser* browser = BrowserList::GetLastActive(); | |
| 297 if (!browser) | |
| 298 return; | |
| 299 | |
| 300 std::string ext = full_path.Extension(); | |
| 301 // For things supported natively by the browser, we should open it | |
| 302 // in a tab. | |
| 303 if (IsSupportedBrowserExtension(ext.data()) || | |
| 304 ShouldBeOpenedWithPdfPlugin(ext.data())) { | |
| 305 std::string path; | |
| 306 path = "file://"; | |
| 307 path.append(net::EscapeUrlEncodedData(full_path.value(), false)); | |
| 308 browser->AddSelectedTabWithURL(GURL(path), content::PAGE_TRANSITION_LINK); | |
| 309 return; | |
| 310 } | |
| 311 #if defined(OS_CHROMEOS) | |
| 312 if (IsSupportedAVExtension(ext.data())) { | |
| 313 MediaPlayer* mediaplayer = MediaPlayer::GetInstance(); | |
| 314 | |
| 315 if (mediaplayer->GetPlaylist().empty()) | |
| 316 enqueue = false; // Force to start playback if current playlist is | |
| 317 // empty. | |
| 318 | |
| 319 if (enqueue) { | |
| 320 mediaplayer->PopupPlaylist(browser); | |
| 321 mediaplayer->EnqueueMediaFile(browser->profile(), full_path); | |
| 322 } else { | |
| 323 mediaplayer->PopupMediaPlayer(browser); | |
| 324 mediaplayer->ForcePlayMediaFile(browser->profile(), full_path); | |
| 325 } | |
| 326 return; | |
| 327 } | |
| 328 #endif // OS_CHROMEOS | |
| 329 | |
| 330 // Unknown file type. Record UMA and show an error message. | |
| 331 size_t extension_index = UMAExtensionIndex(ext.data(), | |
| 332 kUMATrackingExtensions, | |
| 333 arraysize(kUMATrackingExtensions)); | |
| 334 UMA_HISTOGRAM_ENUMERATION("FileBrowser.OpeningFileType", | |
| 335 extension_index, | |
| 336 arraysize(kUMATrackingExtensions) - 1); | |
| 337 | |
| 338 browser::ShowErrorBox( | |
| 339 browser->window()->GetNativeHandle(), | |
| 340 l10n_util::GetStringFUTF16( | |
| 341 IDS_FILEBROWSER_ERROR_VIEWING_FILE_TITLE, | |
| 342 UTF8ToUTF16(full_path.BaseName().value())), | |
| 343 l10n_util::GetStringUTF16( | |
| 344 IDS_FILEBROWSER_ERROR_VIEWING_FILE)); | |
| 345 } | |
| 346 | |
| 347 } // namespace file_manager_util | |
| OLD | NEW |