Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/platform_app_launcher.h" | 5 #include "chrome/browser/extensions/platform_app_launcher.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/file_path.h" | 8 #include "base/file_path.h" |
| 9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
| 12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 13 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
| 14 #include "chrome/browser/extensions/api/app_runtime/app_runtime_api.h" | 14 #include "chrome/browser/extensions/api/app_runtime/app_runtime_api.h" |
| 15 #include "chrome/browser/extensions/extension_host.h" | 15 #include "chrome/browser/extensions/extension_host.h" |
| 16 #include "chrome/browser/extensions/extension_process_manager.h" | 16 #include "chrome/browser/extensions/extension_process_manager.h" |
| 17 #include "chrome/browser/extensions/extension_system.h" | 17 #include "chrome/browser/extensions/extension_system.h" |
| 18 #include "chrome/browser/extensions/lazy_background_task_queue.h" | 18 #include "chrome/browser/extensions/lazy_background_task_queue.h" |
| 19 #include "chrome/browser/intents/web_intents_util.h" | |
| 19 #include "chrome/browser/profiles/profile.h" | 20 #include "chrome/browser/profiles/profile.h" |
| 20 #include "chrome/common/extensions/extension.h" | 21 #include "chrome/common/extensions/extension.h" |
| 21 #include "chrome/common/extensions/extension_messages.h" | 22 #include "chrome/common/extensions/extension_messages.h" |
| 22 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
| 23 #include "content/public/browser/child_process_security_policy.h" | 24 #include "content/public/browser/child_process_security_policy.h" |
| 24 #include "content/public/browser/render_process_host.h" | 25 #include "content/public/browser/render_process_host.h" |
| 25 #include "net/base/mime_util.h" | 26 #include "net/base/mime_util.h" |
| 26 #include "net/base/net_util.h" | 27 #include "net/base/net_util.h" |
| 27 #include "webkit/fileapi/file_system_types.h" | 28 #include "webkit/fileapi/file_system_types.h" |
| 28 #include "webkit/fileapi/isolated_context.h" | 29 #include "webkit/fileapi/isolated_context.h" |
| 29 #include "webkit/glue/web_intent_data.h" | 30 #include "webkit/glue/web_intent_data.h" |
| 30 #include "webkit/glue/web_intent_service_data.h" | 31 #include "webkit/glue/web_intent_service_data.h" |
| 31 | 32 |
| 32 using content::BrowserThread; | 33 using content::BrowserThread; |
| 33 | 34 |
| 34 namespace extensions { | 35 namespace extensions { |
| 35 | 36 |
| 36 namespace { | 37 namespace { |
| 37 | 38 |
| 38 const char kViewIntent[] = "http://webintents.org/view"; | |
| 39 | |
| 40 bool MakePathAbsolute(const FilePath& current_directory, | 39 bool MakePathAbsolute(const FilePath& current_directory, |
| 41 FilePath* file_path) { | 40 FilePath* file_path) { |
| 42 DCHECK(file_path); | 41 DCHECK(file_path); |
| 43 if (file_path->IsAbsolute()) | 42 if (file_path->IsAbsolute()) |
| 44 return true; | 43 return true; |
| 45 | 44 |
| 46 if (current_directory.empty()) | 45 if (current_directory.empty()) |
| 47 return file_util::AbsolutePath(file_path); | 46 return file_util::AbsolutePath(file_path); |
| 48 | 47 |
| 49 if (!current_directory.IsAbsolute()) | 48 if (!current_directory.IsAbsolute()) |
| 50 return false; | 49 return false; |
| 51 | 50 |
| 52 *file_path = current_directory.Append(*file_path); | 51 *file_path = current_directory.Append(*file_path); |
| 53 return true; | 52 return true; |
| 54 } | 53 } |
| 55 | 54 |
| 56 // Class to handle launching of platform apps with command line information. | 55 bool GetAbsolutePathFromCommandLine(const CommandLine* command_line, |
| 56 const FilePath& current_directory, | |
| 57 FilePath* path) { | |
| 58 if (!command_line || !command_line->GetArgs().size()) | |
| 59 return false; | |
| 60 | |
| 61 FilePath relative_path(command_line->GetArgs()[0]); | |
| 62 FilePath absolute_path(relative_path); | |
| 63 if (!MakePathAbsolute(current_directory, &absolute_path)) { | |
| 64 LOG(WARNING) << "Cannot make absolute path from " << relative_path.value(); | |
| 65 return false; | |
| 66 } | |
| 67 *path = absolute_path; | |
| 68 return true; | |
| 69 } | |
| 70 | |
| 71 // Helper method to launches the platform app |extension| with no data. This | |
| 72 // should be called in the fallback case for the launchers above. | |
| 73 void LaunchPlatformAppWithNoData(Profile* profile, const Extension* extension) { | |
| 74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 75 extensions::AppEventRouter::DispatchOnLaunchedEvent(profile, extension); | |
| 76 } | |
| 77 | |
| 78 // Class to handle launching of platform apps to open a specific path. | |
| 57 // An instance of this class is created for each launch. The lifetime of these | 79 // An instance of this class is created for each launch. The lifetime of these |
| 58 // instances is managed by reference counted pointers. As long as an instance | 80 // instances is managed by reference counted pointers. As long as an instance |
| 59 // has outstanding tasks on a message queue it will be retained; once all | 81 // has outstanding tasks on a message queue it will be retained; once all |
| 60 // outstanding tasks are completed it will be deleted. | 82 // outstanding tasks are completed it will be deleted. |
| 61 class PlatformAppCommandLineLauncher | 83 class PlatformAppPathLauncher |
| 62 : public base::RefCountedThreadSafe<PlatformAppCommandLineLauncher> { | 84 : public base::RefCountedThreadSafe<PlatformAppPathLauncher> { |
| 63 public: | 85 public: |
| 64 PlatformAppCommandLineLauncher(Profile* profile, | 86 PlatformAppPathLauncher(Profile* profile, |
| 65 const Extension* extension, | 87 const Extension* extension, |
| 66 const CommandLine* command_line, | 88 const FilePath& file_path) |
| 67 const FilePath& current_directory) | |
| 68 : profile_(profile), | 89 : profile_(profile), |
| 69 extension_(extension), | 90 extension_(extension), |
| 70 command_line_(command_line), | 91 file_path_(file_path) {} |
| 71 current_directory_(current_directory) {} | |
| 72 | 92 |
| 73 void Launch() { | 93 void Launch() { |
| 74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 75 if (!command_line_ || !command_line_->GetArgs().size()) { | 95 if (file_path_.empty()) { |
| 76 LaunchWithNoLaunchData(); | 96 LaunchPlatformAppWithNoData(profile_, extension_); |
| 77 return; | 97 return; |
| 78 } | 98 } |
| 79 | 99 |
| 80 FilePath file_path(command_line_->GetArgs()[0]); | 100 DCHECK(file_path_.IsAbsolute()); |
| 81 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind( | 101 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind( |
| 82 &PlatformAppCommandLineLauncher::GetMimeTypeAndLaunch, | 102 &PlatformAppPathLauncher::GetMimeTypeAndLaunch, this)); |
| 83 this, file_path)); | |
| 84 } | 103 } |
| 85 | 104 |
| 86 private: | 105 private: |
| 87 friend class base::RefCountedThreadSafe<PlatformAppCommandLineLauncher>; | 106 friend class base::RefCountedThreadSafe<PlatformAppPathLauncher>; |
| 88 | 107 |
| 89 virtual ~PlatformAppCommandLineLauncher() {} | 108 virtual ~PlatformAppPathLauncher() {} |
| 90 | 109 |
| 91 void LaunchWithNoLaunchData() { | 110 void GetMimeTypeAndLaunch() { |
| 92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 93 extensions::AppEventRouter::DispatchOnLaunchedEvent(profile_, extension_); | |
| 94 } | |
| 95 | |
| 96 void GetMimeTypeAndLaunch(const FilePath& file_path) { | |
| 97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 98 | 112 |
| 99 // If we cannot construct an absolute path, launch with no launch data. | 113 // If the file doesn't exist, or is a directory, launch with no launch data. |
| 100 FilePath absolute_path(file_path); | 114 if (!file_util::PathExists(file_path_) || |
| 101 if (!MakePathAbsolute(current_directory_, &absolute_path)) { | 115 file_util::DirectoryExists(file_path_)) { |
| 102 LOG(WARNING) << "Cannot make absolute path from " << file_path.value(); | 116 LOG(WARNING) << "No file exists with path " << file_path_.value(); |
| 103 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | 117 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( |
| 104 &PlatformAppCommandLineLauncher::LaunchWithNoLaunchData, this)); | 118 &PlatformAppPathLauncher::LaunchWithNoLaunchData, this)); |
| 105 return; | |
| 106 } | |
| 107 | |
| 108 // If the file doesn't exist, or is a directory, launch with no launch data. | |
| 109 if (!file_util::PathExists(absolute_path) || | |
| 110 file_util::DirectoryExists(absolute_path)) { | |
| 111 LOG(WARNING) << "No file exists with path " << absolute_path.value(); | |
| 112 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | |
| 113 &PlatformAppCommandLineLauncher::LaunchWithNoLaunchData, this)); | |
| 114 return; | 119 return; |
| 115 } | 120 } |
| 116 | 121 |
| 117 std::string mime_type; | 122 std::string mime_type; |
| 118 // If we cannot obtain the MIME type, launch with no launch data. | 123 // If we cannot obtain the MIME type, launch with no launch data. |
| 119 if (!net::GetMimeTypeFromFile(absolute_path, &mime_type)) { | 124 if (!net::GetMimeTypeFromFile(file_path_, &mime_type)) { |
| 120 LOG(WARNING) << "Could not obtain MIME type for " | 125 LOG(WARNING) << "Could not obtain MIME type for " |
| 121 << absolute_path.value(); | 126 << file_path_.value(); |
| 122 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | 127 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( |
| 123 &PlatformAppCommandLineLauncher::LaunchWithNoLaunchData, this)); | 128 &PlatformAppPathLauncher::LaunchWithNoLaunchData, this)); |
| 124 return; | 129 return; |
| 125 } | 130 } |
| 126 | 131 |
| 127 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | 132 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( |
| 128 &PlatformAppCommandLineLauncher::LaunchWithMimeTypeAndPath, | 133 &PlatformAppPathLauncher::LaunchWithMimeType, this, mime_type)); |
| 129 this, absolute_path, mime_type)); | |
| 130 } | 134 } |
| 131 | 135 |
| 132 void LaunchWithMimeTypeAndPath(const FilePath& file_path, | 136 void LaunchWithNoLaunchData() { |
| 133 const std::string& mime_type) { | 137 // This method is required as an entry point on the UI thread. |
| 138 LaunchPlatformAppWithNoData(profile_, extension_); | |
| 139 } | |
| 140 | |
| 141 void LaunchWithMimeType(const std::string& mime_type) { | |
| 134 // Find the intent service from the platform app for the file being opened. | 142 // Find the intent service from the platform app for the file being opened. |
| 135 webkit_glue::WebIntentServiceData service; | 143 webkit_glue::WebIntentServiceData service; |
| 136 bool found_service = false; | 144 bool found_service = false; |
| 137 | 145 |
| 138 std::vector<webkit_glue::WebIntentServiceData> services = | 146 std::vector<webkit_glue::WebIntentServiceData> services = |
| 139 extension_->intents_services(); | 147 extension_->intents_services(); |
| 140 for (size_t i = 0; i < services.size(); i++) { | 148 for (size_t i = 0; i < services.size(); i++) { |
| 141 std::string service_type_ascii = UTF16ToASCII(services[i].type); | 149 std::string service_type_ascii = UTF16ToASCII(services[i].type); |
| 142 if (services[i].action == ASCIIToUTF16(kViewIntent) && | 150 if (services[i].action == ASCIIToUTF16(web_intents::action::kView) && |
| 143 net::MatchesMimeType(service_type_ascii, mime_type)) { | 151 net::MatchesMimeType(service_type_ascii, mime_type)) { |
| 144 service = services[i]; | 152 service = services[i]; |
| 145 found_service = true; | 153 found_service = true; |
| 146 break; | 154 break; |
| 147 } | 155 } |
| 148 } | 156 } |
| 149 | 157 |
| 150 // If this app doesn't have an intent that supports the file, launch with | 158 // If this app doesn't have an intent that supports the file, launch with |
| 151 // no launch data. | 159 // no launch data. |
| 152 if (!found_service) { | 160 if (!found_service) { |
| 153 LOG(WARNING) << "Extension does not provide a valid intent for " | 161 LOG(WARNING) << "Extension does not provide a valid intent for " |
| 154 << file_path.value(); | 162 << file_path_.value(); |
| 155 LaunchWithNoLaunchData(); | 163 LaunchWithNoLaunchData(); |
| 156 return; | 164 return; |
| 157 } | 165 } |
| 158 | 166 |
| 159 // Access needs to be granted to the file for the process associated with | 167 // Access needs to be granted to the file for the process associated with |
| 160 // the extension. To do this the ExtensionHost is needed. This might not be | 168 // the extension. To do this the ExtensionHost is needed. This might not be |
| 161 // available, or it might be in the process of being unloaded, in which case | 169 // available, or it might be in the process of being unloaded, in which case |
| 162 // the lazy background task queue is used to load the extension and then | 170 // the lazy background task queue is used to load the extension and then |
| 163 // call back to us. | 171 // call back to us. |
| 164 extensions::LazyBackgroundTaskQueue* queue = | 172 extensions::LazyBackgroundTaskQueue* queue = |
| 165 ExtensionSystem::Get(profile_)->lazy_background_task_queue(); | 173 ExtensionSystem::Get(profile_)->lazy_background_task_queue(); |
| 166 if (queue->ShouldEnqueueTask(profile_, extension_)) { | 174 if (queue->ShouldEnqueueTask(profile_, extension_)) { |
| 167 queue->AddPendingTask(profile_, extension_->id(), base::Bind( | 175 queue->AddPendingTask(profile_, extension_->id(), base::Bind( |
| 168 &PlatformAppCommandLineLauncher::GrantAccessToFileAndLaunch, | 176 &PlatformAppPathLauncher::GrantAccessToFileAndLaunch, |
| 169 this, file_path, mime_type)); | 177 this, mime_type)); |
| 170 return; | 178 return; |
| 171 } | 179 } |
| 172 | 180 |
| 173 ExtensionProcessManager* process_manager = | 181 ExtensionProcessManager* process_manager = |
| 174 ExtensionSystem::Get(profile_)->process_manager(); | 182 ExtensionSystem::Get(profile_)->process_manager(); |
| 175 extensions::ExtensionHost* host = | 183 extensions::ExtensionHost* host = |
| 176 process_manager->GetBackgroundHostForExtension(extension_->id()); | 184 process_manager->GetBackgroundHostForExtension(extension_->id()); |
| 177 DCHECK(host); | 185 DCHECK(host); |
| 178 GrantAccessToFileAndLaunch(file_path, mime_type, host); | 186 GrantAccessToFileAndLaunch(mime_type, host); |
| 179 } | 187 } |
| 180 | 188 |
| 181 void GrantAccessToFileAndLaunch(const FilePath& file_path, | 189 void GrantAccessToFileAndLaunch(const std::string& mime_type, |
| 182 const std::string& mime_type, | |
| 183 extensions::ExtensionHost* host) { | 190 extensions::ExtensionHost* host) { |
| 184 // If there was an error loading the app page, |host| will be NULL. | 191 // If there was an error loading the app page, |host| will be NULL. |
| 185 if (!host) { | 192 if (!host) { |
| 186 LOG(ERROR) << "Could not load app page for " << extension_->id(); | 193 LOG(ERROR) << "Could not load app page for " << extension_->id(); |
| 187 return; | 194 return; |
| 188 } | 195 } |
| 189 | 196 |
| 190 content::ChildProcessSecurityPolicy* policy = | 197 content::ChildProcessSecurityPolicy* policy = |
| 191 content::ChildProcessSecurityPolicy::GetInstance(); | 198 content::ChildProcessSecurityPolicy::GetInstance(); |
| 192 int renderer_id = host->render_process_host()->GetID(); | 199 int renderer_id = host->render_process_host()->GetID(); |
| 193 | 200 |
| 194 // Granting read file permission to allow reading file content. | 201 // Granting read file permission to allow reading file content. |
| 195 // If the renderer already has permission to read these paths, it is not | 202 // If the renderer already has permission to read these paths, it is not |
| 196 // regranted, as this would overwrite any other permissions which the | 203 // regranted, as this would overwrite any other permissions which the |
| 197 // renderer may already have. | 204 // renderer may already have. |
| 198 if (!policy->CanReadFile(renderer_id, file_path)) | 205 if (!policy->CanReadFile(renderer_id, file_path_)) |
| 199 policy->GrantReadFile(renderer_id, file_path); | 206 policy->GrantReadFile(renderer_id, file_path_); |
| 200 | 207 |
| 201 std::string registered_name; | 208 std::string registered_name; |
| 202 fileapi::IsolatedContext* isolated_context = | 209 fileapi::IsolatedContext* isolated_context = |
| 203 fileapi::IsolatedContext::GetInstance(); | 210 fileapi::IsolatedContext::GetInstance(); |
| 204 DCHECK(isolated_context); | 211 DCHECK(isolated_context); |
| 205 std::string filesystem_id = isolated_context->RegisterFileSystemForPath( | 212 std::string filesystem_id = isolated_context->RegisterFileSystemForPath( |
| 206 fileapi::kFileSystemTypeNativeLocal, file_path, ®istered_name); | 213 fileapi::kFileSystemTypeNativeLocal, file_path_, ®istered_name); |
| 207 // Granting read file system permission as well to allow file-system | 214 // Granting read file system permission as well to allow file-system |
| 208 // read operations. | 215 // read operations. |
| 209 policy->GrantReadFileSystem(renderer_id, filesystem_id); | 216 policy->GrantReadFileSystem(renderer_id, filesystem_id); |
| 210 | 217 |
| 211 extensions::AppEventRouter::DispatchOnLaunchedEventWithFileEntry( | 218 extensions::AppEventRouter::DispatchOnLaunchedEventWithFileEntry( |
| 212 profile_, extension_, ASCIIToUTF16(kViewIntent), filesystem_id, | 219 profile_, extension_, ASCIIToUTF16(web_intents::action::kView), |
| 213 registered_name); | 220 filesystem_id, registered_name); |
| 214 } | 221 } |
| 215 | 222 |
| 216 // The profile the app should be run in. | 223 // The profile the app should be run in. |
| 217 Profile* profile_; | 224 Profile* profile_; |
| 218 // The extension providing the app. | 225 // The extension providing the app. |
| 219 const Extension* extension_; | 226 const Extension* extension_; |
| 220 // The command line to be passed through to the app, or NULL. | 227 // The path to be passed through to the app. This may be the empty path. |
| 221 const CommandLine* command_line_; | 228 const FilePath file_path_; |
| 222 // If non-empty, this is used to expand relative paths. | |
| 223 const FilePath current_directory_; | |
| 224 | 229 |
| 225 DISALLOW_COPY_AND_ASSIGN(PlatformAppCommandLineLauncher); | 230 DISALLOW_COPY_AND_ASSIGN(PlatformAppPathLauncher); |
| 226 }; | 231 }; |
| 227 | 232 |
| 228 // Class to handle launching of platform apps with WebIntent data. | 233 // Class to handle launching of platform apps with WebIntent data. |
| 229 // An instance of this class is created for each launch. The lifetime of these | 234 // An instance of this class is created for each launch. The lifetime of these |
| 230 // instances is managed by reference counted pointers. As long as an instance | 235 // instances is managed by reference counted pointers. As long as an instance |
| 231 // has outstanding tasks on a message queue it will be retained; once all | 236 // has outstanding tasks on a message queue it will be retained; once all |
| 232 // outstanding tasks are completed it will be deleted. | 237 // outstanding tasks are completed it will be deleted. |
| 233 class PlatformAppWebIntentLauncher | 238 class PlatformAppWebIntentLauncher |
| 234 : public base::RefCountedThreadSafe<PlatformAppWebIntentLauncher> { | 239 : public base::RefCountedThreadSafe<PlatformAppWebIntentLauncher> { |
| 235 public: | 240 public: |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 323 | 328 |
| 324 DISALLOW_COPY_AND_ASSIGN(PlatformAppWebIntentLauncher); | 329 DISALLOW_COPY_AND_ASSIGN(PlatformAppWebIntentLauncher); |
| 325 }; | 330 }; |
| 326 | 331 |
| 327 } // namespace | 332 } // namespace |
| 328 | 333 |
| 329 void LaunchPlatformApp(Profile* profile, | 334 void LaunchPlatformApp(Profile* profile, |
| 330 const Extension* extension, | 335 const Extension* extension, |
| 331 const CommandLine* command_line, | 336 const CommandLine* command_line, |
| 332 const FilePath& current_directory) { | 337 const FilePath& current_directory) { |
| 338 FilePath path; | |
| 339 if (GetAbsolutePathFromCommandLine(command_line, current_directory, &path)) | |
| 340 LaunchPlatformAppWithPath(profile, extension, path); | |
| 341 else | |
| 342 LaunchPlatformAppWithNoData(profile, extension); | |
|
benwells
2012/08/31 05:40:15
Nit: Use an early return here:
if (...) {
Launc
thorogood
2012/09/01 03:02:11
Done.
| |
| 343 } | |
| 344 | |
| 345 void LaunchPlatformAppWithPath(Profile* profile, | |
| 346 const Extension* extension, | |
| 347 const FilePath& file_path) { | |
| 333 // launcher will be freed when nothing has a reference to it. The message | 348 // launcher will be freed when nothing has a reference to it. The message |
| 334 // queue will retain a reference for any outstanding task, so when the | 349 // queue will retain a reference for any outstanding task, so when the |
| 335 // launcher has finished it will be freed. | 350 // launcher has finished it will be freed. |
| 336 scoped_refptr<PlatformAppCommandLineLauncher> launcher = | 351 scoped_refptr<PlatformAppPathLauncher> launcher = |
| 337 new PlatformAppCommandLineLauncher(profile, extension, command_line, | 352 new PlatformAppPathLauncher(profile, extension, file_path); |
| 338 current_directory); | |
| 339 launcher->Launch(); | 353 launcher->Launch(); |
| 340 } | 354 } |
| 341 | 355 |
| 342 void LaunchPlatformAppWithWebIntent( | 356 void LaunchPlatformAppWithWebIntent( |
| 343 Profile* profile, | 357 Profile* profile, |
| 344 const Extension* extension, | 358 const Extension* extension, |
| 345 const webkit_glue::WebIntentData& web_intent_data) { | 359 const webkit_glue::WebIntentData& web_intent_data) { |
| 346 scoped_refptr<PlatformAppWebIntentLauncher> launcher = | 360 scoped_refptr<PlatformAppWebIntentLauncher> launcher = |
| 347 new PlatformAppWebIntentLauncher(profile, extension, web_intent_data); | 361 new PlatformAppWebIntentLauncher(profile, extension, web_intent_data); |
| 348 launcher->Launch(); | 362 launcher->Launch(); |
| 349 } | 363 } |
| 350 | 364 |
| 351 } // namespace extensions | 365 } // namespace extensions |
| OLD | NEW |