diff options
author | hirono@chromium.org <hirono@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-04 09:40:29 +0000 |
---|---|---|
committer | hirono@chromium.org <hirono@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-04 09:40:29 +0000 |
commit | 3113a232cc1ca764298b3eca4e062d10982c2672 (patch) | |
tree | e2ff0c2f53e6b28e977fe74f753016fd7c22b6b9 /apps/launcher.cc | |
parent | c2b43dbac2d7feff547cf7e1caf0689b713d6195 (diff) | |
download | chromium_src-3113a232cc1ca764298b3eca4e062d10982c2672.zip chromium_src-3113a232cc1ca764298b3eca4e062d10982c2672.tar.gz chromium_src-3113a232cc1ca764298b3eca4e062d10982c2672.tar.bz2 |
Files.app: Let Files.app pass mutliple files to file handlers.
Previously if multiple files are selected for launching a file handler,
Files.app sends multiple launch events for each file. But according to the
specification of the launch event, we can put multiple entries in a single
launch event. This CL lets Files.app follow the specificaiton.
BUG=358694
TEST=manually
R=benwells@chromium.org, kinaba@chromium.org
Review URL: https://codereview.chromium.org/300063006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274755 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'apps/launcher.cc')
-rw-r--r-- | apps/launcher.cc | 245 |
1 files changed, 162 insertions, 83 deletions
diff --git a/apps/launcher.cc b/apps/launcher.cc index f357881..8cfbee9 100644 --- a/apps/launcher.cc +++ b/apps/launcher.cc @@ -89,7 +89,7 @@ void LaunchPlatformAppWithNoData(Profile* profile, const Extension* extension) { AppEventRouter::DispatchOnLaunchedEvent(profile, extension); } -// Class to handle launching of platform apps to open a specific path. +// Class to handle launching of platform apps to open specific paths. // An instance of this class is created for each launch. The lifetime of these // instances is managed by reference counted pointers. As long as an instance // has outstanding tasks on a message queue it will be retained; once all @@ -99,23 +99,31 @@ class PlatformAppPathLauncher public: PlatformAppPathLauncher(Profile* profile, const Extension* extension, + const std::vector<base::FilePath>& file_paths) + : profile_(profile), extension_(extension), file_paths_(file_paths) {} + + PlatformAppPathLauncher(Profile* profile, + const Extension* extension, const base::FilePath& file_path) - : profile_(profile), extension_(extension), file_path_(file_path) {} + : profile_(profile), extension_(extension) { + if (!file_path.empty()) + file_paths_.push_back(file_path); + } void Launch() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (file_path_.empty()) { + if (file_paths_.empty()) { LaunchPlatformAppWithNoData(profile_, extension_); return; } - DCHECK(file_path_.IsAbsolute()); + for (size_t i = 0; i < file_paths_.size(); ++i) { + DCHECK(file_paths_[i].IsAbsolute()); + } if (HasFileSystemWritePermission(extension_)) { - std::vector<base::FilePath> paths; - paths.push_back(file_path_); PrepareFilesForWritableApp( - paths, + file_paths_, profile_, false, base::Bind(&PlatformAppPathLauncher::OnFileValid, this), @@ -148,9 +156,17 @@ class PlatformAppPathLauncher void MakePathAbsolute(const base::FilePath& current_directory) { DCHECK_CURRENTLY_ON(BrowserThread::FILE); - if (!DoMakePathAbsolute(current_directory, &file_path_)) { - LOG(WARNING) << "Cannot make absolute path from " << file_path_.value(); - file_path_ = base::FilePath(); + for (std::vector<base::FilePath>::iterator it = file_paths_.begin(); + it != file_paths_.end(); + ++it) { + if (!DoMakePathAbsolute(current_directory, &*it)) { + LOG(WARNING) << "Cannot make absolute path from " << it->value(); + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&PlatformAppPathLauncher::LaunchWithNoLaunchData, this)); + return; + } } BrowserThread::PostTask(BrowserThread::UI, @@ -159,93 +175,149 @@ class PlatformAppPathLauncher } void OnFileValid() { + mime_types_.resize(file_paths_.size()); #if defined(OS_CHROMEOS) - if (file_manager::util::IsUnderNonNativeLocalPath(profile_, file_path_)) { - file_manager::util::GetNonNativeLocalPathMimeType( - profile_, - file_path_, - base::Bind(&PlatformAppPathLauncher::OnGotMimeType, this)); - return; - } -#endif - + GetNextNonNativeMimeType(); +#else BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, - base::Bind(&PlatformAppPathLauncher::GetMimeTypeAndLaunch, this)); + base::Bind(&PlatformAppPathLauncher::GetMimeTypesAndLaunch, this)); +#endif } void OnFileInvalid(const base::FilePath& /* error_path */) { LaunchWithNoLaunchData(); } - void GetMimeTypeAndLaunch() { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); +#if defined(OS_CHROMEOS) + void GetNextNonNativeMimeType() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); - // If the file doesn't exist, or is a directory, launch with no launch data. - if (!base::PathExists(file_path_) || - base::DirectoryExists(file_path_)) { - LOG(WARNING) << "No file exists with path " << file_path_.value(); - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( - &PlatformAppPathLauncher::LaunchWithNoLaunchData, this)); - return; + bool any_native_files = false; + for (size_t i = 0; i < mime_types_.size(); ++i) { + if (!mime_types_[i].empty()) + continue; + const base::FilePath& file_path = file_paths_[i]; + if (file_manager::util::IsUnderNonNativeLocalPath(profile_, file_path)) { + file_manager::util::GetNonNativeLocalPathMimeType( + profile_, + file_path, + base::Bind(&PlatformAppPathLauncher::OnGotMimeType, this, i)); + return; + } + any_native_files = true; } - std::string mime_type; - if (!net::GetMimeTypeFromFile(file_path_, &mime_type)) { - // If MIME type of the file can't be determined by its path, - // try to sniff it by its content. - std::vector<char> content(net::kMaxBytesToSniff); - int bytes_read = base::ReadFile(file_path_, &content[0], content.size()); - if (bytes_read >= 0) { - net::SniffMimeType(&content[0], - bytes_read, - net::FilePathToFileURL(file_path_), - std::string(), // type_hint (passes no hint) - &mime_type); - } - if (mime_type.empty()) - mime_type = kFallbackMimeType; + // If there are any native files, we need to call GetMimeTypesAndLaunch to + // obtain mime types for the files. + if (any_native_files) { + BrowserThread::PostTask( + BrowserThread::FILE, + FROM_HERE, + base::Bind(&PlatformAppPathLauncher::GetMimeTypesAndLaunch, this)); + return; } - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( - &PlatformAppPathLauncher::LaunchWithMimeType, this, mime_type)); + // Otherwise, we can call LaunchWithMimeTypes directly. + LaunchWithMimeTypes(); } -#if defined(OS_CHROMEOS) - void OnGotMimeType(bool success, const std::string& mime_type) { + void OnGotMimeType(size_t index, bool success, const std::string& mime_type) { if (!success) { LaunchWithNoLaunchData(); return; } - LaunchWithMimeType(mime_type.empty() ? kFallbackMimeType : mime_type); + mime_types_[index] = mime_type.empty() ? kFallbackMimeType : mime_type; + GetNextNonNativeMimeType(); } #endif + void GetMimeTypesAndLaunch() { + DCHECK_CURRENTLY_ON(BrowserThread::FILE); + + for (size_t i = 0; i < mime_types_.size(); ++i) { + if (!this->mime_types_[i].empty()) + continue; + const base::FilePath& file_path = file_paths_[i]; + + // If the file doesn't exist, or is a directory, launch with no launch + // data. + if (!base::PathExists(file_path) || base::DirectoryExists(file_path)) { + LOG(WARNING) << "No file exists with path " << file_path.value(); + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&PlatformAppPathLauncher::LaunchWithNoLaunchData, this)); + return; + } + + std::string mime_type; + if (!net::GetMimeTypeFromFile(file_path, &mime_type)) { + // If MIME type of the file can't be determined by its path, + // try to sniff it by its content. + std::vector<char> content(net::kMaxBytesToSniff); + int bytes_read = base::ReadFile(file_path, &content[0], content.size()); + if (bytes_read >= 0) { + net::SniffMimeType(&content[0], + bytes_read, + net::FilePathToFileURL(file_path), + std::string(), // type_hint (passes no hint) + &mime_type); + } + if (mime_type.empty()) + mime_type = kFallbackMimeType; + } + mime_types_[i] = mime_type; + } + + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&PlatformAppPathLauncher::LaunchWithMimeTypes, this)); + } + void LaunchWithNoLaunchData() { // This method is required as an entry point on the UI thread. LaunchPlatformAppWithNoData(profile_, extension_); } - void LaunchWithMimeType(const std::string& mime_type) { + void LaunchWithMimeTypes() { + DCHECK(file_paths_.size() == mime_types_.size()); + // Find file handler from the platform app for the file being opened. const extensions::FileHandlerInfo* handler = NULL; - if (!handler_id_.empty()) + if (!handler_id_.empty()) { handler = FileHandlerForId(*extension_, handler_id_); - else - handler = FirstFileHandlerForFile(*extension_, mime_type, file_path_); - if (handler && !FileHandlerCanHandleFile(*handler, mime_type, file_path_)) { - LOG(WARNING) << "Extension does not provide a valid file handler for " - << file_path_.value(); - LaunchWithNoLaunchData(); - return; + if (handler) { + for (size_t i = 0; i < file_paths_.size(); ++i) { + if (!FileHandlerCanHandleFile( + *handler, mime_types_[i], file_paths_[i])) { + LOG(WARNING) + << "Extension does not provide a valid file handler for " + << file_paths_[i].value(); + handler = NULL; + break; + } + } + } + } else { + std::set<std::pair<base::FilePath, std::string> > path_and_file_type_set; + for (size_t i = 0; i < file_paths_.size(); ++i) { + path_and_file_type_set.insert( + std::make_pair(file_paths_[i], mime_types_[i])); + } + const std::vector<const extensions::FileHandlerInfo*>& handlers = + extensions::app_file_handler_util::FindFileHandlersForFiles( + *extension_, path_and_file_type_set); + if (!handlers.empty()) + handler = handlers[0]; } // If this app doesn't have a file handler that supports the file, launch // with no launch data. if (!handler) { - LOG(WARNING) << "Extension does not provide a valid file handler for " - << file_path_.value(); + LOG(WARNING) << "Extension does not provide a valid file handler."; LaunchWithNoLaunchData(); return; } @@ -258,39 +330,44 @@ class PlatformAppPathLauncher // available, or it might be in the process of being unloaded, in which case // the lazy background task queue is used to load the extension and then // call back to us. - extensions::LazyBackgroundTaskQueue* queue = + extensions::LazyBackgroundTaskQueue* const queue = ExtensionSystem::Get(profile_)->lazy_background_task_queue(); if (queue->ShouldEnqueueTask(profile_, extension_)) { - queue->AddPendingTask(profile_, extension_->id(), base::Bind( - &PlatformAppPathLauncher::GrantAccessToFileAndLaunch, - this, mime_type)); + queue->AddPendingTask( + profile_, + extension_->id(), + base::Bind(&PlatformAppPathLauncher::GrantAccessToFilesAndLaunch, + this)); return; } - extensions::ProcessManager* process_manager = + extensions::ProcessManager* const process_manager = ExtensionSystem::Get(profile_)->process_manager(); - ExtensionHost* host = + ExtensionHost* const host = process_manager->GetBackgroundHostForExtension(extension_->id()); DCHECK(host); - GrantAccessToFileAndLaunch(mime_type, host); + GrantAccessToFilesAndLaunch(host); } - void GrantAccessToFileAndLaunch(const std::string& mime_type, - ExtensionHost* host) { + void GrantAccessToFilesAndLaunch(ExtensionHost* host) { // If there was an error loading the app page, |host| will be NULL. if (!host) { LOG(ERROR) << "Could not load app page for " << extension_->id(); return; } - GrantedFileEntry file_entry = - CreateFileEntry(profile_, - extension_, - host->render_process_host()->GetID(), - file_path_, - false); - AppEventRouter::DispatchOnLaunchedEventWithFileEntry( - profile_, extension_, handler_id_, mime_type, file_entry); + std::vector<GrantedFileEntry> file_entries; + for (size_t i = 0; i < file_paths_.size(); ++i) { + file_entries.push_back( + CreateFileEntry(profile_, + extension_, + host->render_process_host()->GetID(), + file_paths_[i], + false)); + } + + AppEventRouter::DispatchOnLaunchedEventWithFileEntries( + profile_, extension_, handler_id_, mime_types_, file_entries); } // The profile the app should be run in. @@ -301,7 +378,8 @@ class PlatformAppPathLauncher // See http://crbug.com/372270 for details. const Extension* extension_; // The path to be passed through to the app. - base::FilePath file_path_; + std::vector<base::FilePath> file_paths_; + std::vector<std::string> mime_types_; // The ID of the file handler used to launch the app. std::string handler_id_; @@ -369,12 +447,13 @@ void LaunchPlatformApp(Profile* profile, const Extension* extension) { base::FilePath()); } -void LaunchPlatformAppWithFileHandler(Profile* profile, - const Extension* extension, - const std::string& handler_id, - const base::FilePath& file_path) { +void LaunchPlatformAppWithFileHandler( + Profile* profile, + const Extension* extension, + const std::string& handler_id, + const std::vector<base::FilePath>& file_paths) { scoped_refptr<PlatformAppPathLauncher> launcher = - new PlatformAppPathLauncher(profile, extension, file_path); + new PlatformAppPathLauncher(profile, extension, file_paths); launcher->LaunchWithHandler(handler_id); } |