Chromium Code Reviews| Index: apps/launcher.cc |
| diff --git a/apps/launcher.cc b/apps/launcher.cc |
| index acaec4156a77cf2b3005a097fab7065cf4ec475b..8946e02990c909085250cd0f336761214a123ea7 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_); |
| CheckWritableFiles( |
| - 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,146 @@ 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; |
| - } |
| + GetNextNonNativeMimeType(); |
| +#else |
| + GetMimeTypesAndLaunch(); |
|
kinaba
2014/06/04 02:29:59
PostTask(FILE) is needed, I guess.
benwells
2014/06/04 02:55:38
Yes, good catch. Looking back at the last patch to
hirono
2014/06/04 04:02:23
Fixed. Thank you!
|
| #endif |
| - |
| - BrowserThread::PostTask( |
| - BrowserThread::FILE, |
| - FROM_HERE, |
| - base::Bind(&PlatformAppPathLauncher::GetMimeTypeAndLaunch, this)); |
| } |
| 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 +327,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 +375,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 +444,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); |
| } |