Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(134)

Side by Side Diff: chrome/browser/web_applications/web_app_mac.mm

Issue 15724019: Recreate shortcuts on app update. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Sync and rebase Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 #import "chrome/browser/web_applications/web_app_mac.h" 5 #import "chrome/browser/web_applications/web_app_mac.h"
6 6
7 #import <Carbon/Carbon.h> 7 #import <Carbon/Carbon.h>
8 #import <Cocoa/Cocoa.h> 8 #import <Cocoa/Cocoa.h>
9 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
159 } 159 }
160 } 160 }
161 161
162 return false; 162 return false;
163 } 163 }
164 164
165 void LaunchShimOnFileThread( 165 void LaunchShimOnFileThread(
166 const ShellIntegration::ShortcutInfo& shortcut_info) { 166 const ShellIntegration::ShortcutInfo& shortcut_info) {
167 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); 167 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
168 base::FilePath shim_path = web_app::GetAppInstallPath(shortcut_info); 168 base::FilePath shim_path = web_app::GetAppInstallPath(shortcut_info);
169 if (shim_path.empty()) 169
170 if (shim_path.empty() || !file_util::PathExists(shim_path)) {
171 // The user may have deleted the copy in the Applications folder, use the
172 // one in the web app's app_data_path.
173 base::FilePath app_data_path = web_app::GetWebAppDataDirectory(
174 shortcut_info.profile_path, shortcut_info.extension_id, GURL());
175 shim_path = app_data_path.Append(shim_path.BaseName());
176 }
177
178 if (!file_util::PathExists(shim_path))
170 return; 179 return;
171 180
172 CommandLine command_line(CommandLine::NO_PROGRAM); 181 CommandLine command_line(CommandLine::NO_PROGRAM);
173 command_line.AppendSwitch(app_mode::kNoLaunchApp); 182 command_line.AppendSwitch(app_mode::kNoLaunchApp);
174 base::mac::OpenApplicationWithPath(shim_path, command_line, NULL); 183 base::mac::OpenApplicationWithPath(shim_path, command_line, NULL);
175 } 184 }
176 185
177 base::FilePath GetLocalizableAppShortcutsSubdirName() { 186 base::FilePath GetLocalizableAppShortcutsSubdirName() {
178 #if defined(GOOGLE_CHROME_BUILD) 187 #if defined(GOOGLE_CHROME_BUILD)
179 static const char kChromeAppDirName[] = "Chrome Apps.localized"; 188 static const char kChromeAppDirName[] = "Chrome Apps.localized";
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 221
213 std::string locale = l10n_util::NormalizeLocale( 222 std::string locale = l10n_util::NormalizeLocale(
214 l10n_util::GetApplicationLocale(std::string())); 223 l10n_util::GetApplicationLocale(std::string()));
215 224
216 NSString* strings_path = base::mac::FilePathToNSString( 225 NSString* strings_path = base::mac::FilePathToNSString(
217 localized.Append(locale + ".strings")); 226 localized.Append(locale + ".strings"));
218 [strings_dict writeToFile:strings_path 227 [strings_dict writeToFile:strings_path
219 atomically:YES]; 228 atomically:YES];
220 } 229 }
221 230
231 void DeletePathAndParentIfEmpty(const base::FilePath& app_path) {
232 DCHECK(!app_path.empty());
233 file_util::Delete(app_path, true);
234 base::FilePath apps_folder = app_path.DirName();
235 if (file_util::IsDirectoryEmpty(apps_folder))
236 file_util::Delete(apps_folder, false);
237 }
238
222 } // namespace 239 } // namespace
223 240
224 namespace web_app { 241 namespace web_app {
225 242
226 243
227 WebAppShortcutCreator::WebAppShortcutCreator( 244 WebAppShortcutCreator::WebAppShortcutCreator(
228 const base::FilePath& app_data_path, 245 const base::FilePath& app_data_path,
229 const ShellIntegration::ShortcutInfo& shortcut_info, 246 const ShellIntegration::ShortcutInfo& shortcut_info,
230 const string16& chrome_bundle_id) 247 const std::string& chrome_bundle_id)
231 : app_data_path_(app_data_path), 248 : app_data_path_(app_data_path),
232 info_(shortcut_info), 249 info_(shortcut_info),
233 chrome_bundle_id_(chrome_bundle_id) { 250 chrome_bundle_id_(chrome_bundle_id) {
234 } 251 }
235 252
236 WebAppShortcutCreator::~WebAppShortcutCreator() { 253 WebAppShortcutCreator::~WebAppShortcutCreator() {
237 } 254 }
238 255
239 base::FilePath WebAppShortcutCreator::GetShortcutPath() const { 256 base::FilePath WebAppShortcutCreator::GetShortcutName() const {
240 base::FilePath dst_path = GetDestinationPath();
241 if (dst_path.empty())
242 return dst_path;
243
244 std::string app_name; 257 std::string app_name;
245 // Check if there should be a separate shortcut made for different profiles. 258 // Check if there should be a separate shortcut made for different profiles.
246 // Such shortcuts will have a |profile_name| set on the ShortcutInfo, 259 // Such shortcuts will have a |profile_name| set on the ShortcutInfo,
247 // otherwise it will be empty. 260 // otherwise it will be empty.
248 if (!info_.profile_name.empty()) { 261 if (!info_.profile_name.empty()) {
249 app_name += info_.profile_path.BaseName().value(); 262 app_name += info_.profile_path.BaseName().value();
250 app_name += ' '; 263 app_name += ' ';
251 } 264 }
252 app_name += info_.extension_id; 265 app_name += info_.extension_id;
253 return dst_path.Append(app_name).ReplaceExtension("app"); 266 return base::FilePath(app_name).ReplaceExtension("app");
254 } 267 }
255 268
256 bool WebAppShortcutCreator::CreateShortcut() { 269 bool WebAppShortcutCreator::BuildShortcut(
257 base::FilePath app_path = GetShortcutPath(); 270 const base::FilePath& staging_path) const {
258 base::FilePath app_name = app_path.BaseName();
259 base::FilePath dst_path = app_path.DirName();
260 if (app_path.empty() || !file_util::DirectoryExists(dst_path.DirName())) {
261 LOG(ERROR) << "Couldn't find an Applications directory to copy app to.";
262 return false;
263 }
264 if (!file_util::CreateDirectory(app_data_path_)) {
265 LOG(ERROR) << "Creating app_data_path " << app_data_path_.value()
266 << " failed.";
267 return false;
268 }
269 if (!file_util::CreateDirectory(dst_path)) {
270 LOG(ERROR) << "Creating directory " << dst_path.value() << " failed.";
271 return false;
272 }
273 UpdateAppShortcutsSubdirLocalizedName(dst_path);
274
275 base::ScopedTempDir scoped_temp_dir;
276 if (!scoped_temp_dir.CreateUniqueTempDir())
277 return false;
278 base::FilePath staging_path = scoped_temp_dir.path().Append(app_name);
279
280 // Update the app's plist and icon in a temp directory. This works around 271 // Update the app's plist and icon in a temp directory. This works around
281 // a Finder bug where the app's icon doesn't properly update. 272 // a Finder bug where the app's icon doesn't properly update.
282 if (!file_util::CopyDirectory(GetAppLoaderPath(), staging_path, true)) { 273 if (!file_util::CopyDirectory(GetAppLoaderPath(), staging_path, true)) {
283 LOG(ERROR) << "Copying app to staging path: " << staging_path.value() 274 LOG(ERROR) << "Copying app to staging path: " << staging_path.value()
284 << " failed."; 275 << " failed.";
285 return false; 276 return false;
286 } 277 }
287 278
288 if (!UpdatePlist(staging_path)) 279 if (!UpdatePlist(staging_path))
289 return false; 280 return false;
290 281
291 if (!UpdateDisplayName(staging_path)) 282 if (!UpdateDisplayName(staging_path))
292 return false; 283 return false;
293 284
294 if (!UpdateIcon(staging_path)) 285 if (!UpdateIcon(staging_path))
295 return false; 286 return false;
296 287
297 // Put one copy in the app's app_data_path so we can still run it if the user
298 // deletes the one in the applications folder.
299 if (!file_util::CopyDirectory(staging_path, app_data_path_, true)) {
300 NOTREACHED();
301 return false;
302 }
303 base::mac::RemoveQuarantineAttribute(app_data_path_.Append(app_name));
304
305 if (!file_util::CopyDirectory(staging_path, dst_path, true))
306 return false;
307
308 base::mac::RemoveQuarantineAttribute(app_path);
309 RevealGeneratedBundleInFinder(app_path);
310
311 return true; 288 return true;
312 } 289 }
313 290
291 size_t WebAppShortcutCreator::CreateShortcutsIn(
292 const std::vector<base::FilePath>& folders) const {
293 size_t succeeded = 0;
294
295 base::ScopedTempDir scoped_temp_dir;
296 if (!scoped_temp_dir.CreateUniqueTempDir())
297 return 0;
298
299 base::FilePath app_name = GetShortcutName();
300 base::FilePath staging_path =
301 scoped_temp_dir.path().Append(app_name);
302 if (!BuildShortcut(staging_path))
303 return 0;
304
305 for (std::vector<base::FilePath>::const_iterator it = folders.begin();
306 it != folders.end(); ++it) {
307 const base::FilePath& dst_path = *it;
308 if (!file_util::CopyDirectory(staging_path, dst_path, true)) {
309 LOG(ERROR) << "Copying app to dst path: " << dst_path.value()
310 << " failed";
311 return succeeded;
312 }
313
314 base::mac::RemoveQuarantineAttribute(dst_path.Append(app_name));
315 ++succeeded;
316 }
317
318 return succeeded;
319 }
320
321 bool WebAppShortcutCreator::CreateShortcuts() {
322 base::FilePath dst_path = GetDestinationPath();
323 if (dst_path.empty() || !file_util::DirectoryExists(dst_path.DirName())) {
324 LOG(ERROR) << "Couldn't find an Applications directory to copy app to.";
325 return false;
326 }
327
328 if (!file_util::CreateDirectory(app_data_path_)) {
329 LOG(ERROR) << "Creating app_data_path " << app_data_path_.value()
330 << " failed.";
331 return false;
332 }
333
334 if (!file_util::CreateDirectory(dst_path)) {
335 LOG(ERROR) << "Creating directory " << dst_path.value() << " failed.";
336 return false;
337 }
338
339 UpdateAppShortcutsSubdirLocalizedName(dst_path);
340
341 std::vector<base::FilePath> paths;
342 paths.push_back(app_data_path_);
343 paths.push_back(dst_path);
344 size_t success_count = CreateShortcutsIn(paths);
345 if (success_count == 0)
346 return false;
347
348 UpdateInternalBundleIdentifier();
349
350 if (success_count != paths.size())
351 return false;
352
353 RevealAppShimInFinder();
354 return true;
355 }
356
357 void WebAppShortcutCreator::DeleteShortcuts() {
358 base::FilePath dst_path = GetDestinationPath();
359 if (!dst_path.empty())
360 DeletePathAndParentIfEmpty(dst_path.Append(GetShortcutName()));
361
362 // In case the user has moved/renamed/copied the app bundle.
363 base::FilePath bundle_path = GetAppBundleById(GetBundleIdentifier());
364 if (!bundle_path.empty())
365 file_util::Delete(bundle_path, true);
366
367 // Delete the internal one.
368 DeletePathAndParentIfEmpty(app_data_path_.Append(GetShortcutName()));
369 }
370
371 bool WebAppShortcutCreator::UpdateShortcuts() {
372 std::vector<base::FilePath> paths;
373 file_util::Delete(app_data_path_.Append(GetShortcutName()), true);
374 paths.push_back(app_data_path_);
375
376 base::FilePath dst_path = GetDestinationPath();
377 base::FilePath app_path = dst_path.Append(GetShortcutName());
378
379 // If the path does not exist, check if a matching bundle can be found
380 // elsewhere.
381 if (dst_path.empty() || !file_util::PathExists(app_path))
382 app_path = GetAppBundleById(GetBundleIdentifier());
383
384 if (!app_path.empty()) {
385 file_util::Delete(app_path, true);
386 paths.push_back(app_path.DirName());
387 }
388
389 size_t success_count = CreateShortcutsIn(paths);
390 if (success_count == 0)
391 return false;
392
393 UpdateInternalBundleIdentifier();
394 return success_count == paths.size() && !app_path.empty();
395 }
396
314 base::FilePath WebAppShortcutCreator::GetAppLoaderPath() const { 397 base::FilePath WebAppShortcutCreator::GetAppLoaderPath() const {
315 return base::mac::PathForFrameworkBundleResource( 398 return base::mac::PathForFrameworkBundleResource(
316 base::mac::NSToCFCast(@"app_mode_loader.app")); 399 base::mac::NSToCFCast(@"app_mode_loader.app"));
317 } 400 }
318 401
319 base::FilePath WebAppShortcutCreator::GetDestinationPath() const { 402 base::FilePath WebAppShortcutCreator::GetDestinationPath() const {
320 base::FilePath path = GetWritableApplicationsDirectory(); 403 base::FilePath path = GetWritableApplicationsDirectory();
321 if (path.empty()) 404 if (path.empty())
322 return path; 405 return path;
323 return path.Append(GetLocalizableAppShortcutsSubdirName()); 406 return path.Append(GetLocalizableAppShortcutsSubdirName());
324 } 407 }
325 408
326 bool WebAppShortcutCreator::UpdatePlist(const base::FilePath& app_path) const { 409 bool WebAppShortcutCreator::UpdatePlist(const base::FilePath& app_path) const {
327 NSString* extension_id = base::SysUTF8ToNSString(info_.extension_id); 410 NSString* extension_id = base::SysUTF8ToNSString(info_.extension_id);
328 NSString* extension_title = base::SysUTF16ToNSString(info_.title); 411 NSString* extension_title = base::SysUTF16ToNSString(info_.title);
329 NSString* extension_url = base::SysUTF8ToNSString(info_.url.spec()); 412 NSString* extension_url = base::SysUTF8ToNSString(info_.url.spec());
330 NSString* chrome_bundle_id = base::SysUTF16ToNSString(chrome_bundle_id_); 413 NSString* chrome_bundle_id = base::SysUTF8ToNSString(chrome_bundle_id_);
331 NSDictionary* replacement_dict = 414 NSDictionary* replacement_dict =
332 [NSDictionary dictionaryWithObjectsAndKeys: 415 [NSDictionary dictionaryWithObjectsAndKeys:
333 extension_id, app_mode::kShortcutIdPlaceholder, 416 extension_id, app_mode::kShortcutIdPlaceholder,
334 extension_title, app_mode::kShortcutNamePlaceholder, 417 extension_title, app_mode::kShortcutNamePlaceholder,
335 extension_url, app_mode::kShortcutURLPlaceholder, 418 extension_url, app_mode::kShortcutURLPlaceholder,
336 chrome_bundle_id, app_mode::kShortcutBrowserBundleIDPlaceholder, 419 chrome_bundle_id, app_mode::kShortcutBrowserBundleIDPlaceholder,
337 nil]; 420 nil];
338 421
339 NSString* plist_path = base::mac::FilePathToNSString( 422 NSString* plist_path = base::mac::FilePathToNSString(
340 app_path.Append("Contents").Append("Info.plist")); 423 app_path.Append("Contents").Append("Info.plist"));
(...skipping 10 matching lines...) Expand all
351 // Remove leading and trailing '@'s. 434 // Remove leading and trailing '@'s.
352 NSString* variable = 435 NSString* variable =
353 [value substringWithRange:NSMakeRange(1, [value length] - 2)]; 436 [value substringWithRange:NSMakeRange(1, [value length] - 2)];
354 437
355 NSString* substitution = [replacement_dict valueForKey:variable]; 438 NSString* substitution = [replacement_dict valueForKey:variable];
356 if (substitution) 439 if (substitution)
357 [plist setObject:substitution forKey:key]; 440 [plist setObject:substitution forKey:key];
358 } 441 }
359 442
360 // 2. Fill in other values. 443 // 2. Fill in other values.
361 [plist setObject:GetBundleIdentifier(plist) 444 [plist setObject:base::SysUTF8ToNSString(GetBundleIdentifier())
362 forKey:base::mac::CFToNSCast(kCFBundleIdentifierKey)]; 445 forKey:base::mac::CFToNSCast(kCFBundleIdentifierKey)];
363 [plist setObject:base::mac::FilePathToNSString(app_data_path_) 446 [plist setObject:base::mac::FilePathToNSString(app_data_path_)
364 forKey:app_mode::kCrAppModeUserDataDirKey]; 447 forKey:app_mode::kCrAppModeUserDataDirKey];
365 [plist setObject:base::mac::FilePathToNSString(info_.profile_path.BaseName()) 448 [plist setObject:base::mac::FilePathToNSString(info_.profile_path.BaseName())
366 forKey:app_mode::kCrAppModeProfileDirKey]; 449 forKey:app_mode::kCrAppModeProfileDirKey];
367 [plist setObject:base::SysUTF8ToNSString(info_.profile_name) 450 [plist setObject:base::SysUTF8ToNSString(info_.profile_name)
368 forKey:app_mode::kCrAppModeProfileNameKey]; 451 forKey:app_mode::kCrAppModeProfileNameKey];
369 [plist setObject:[NSNumber numberWithBool:YES] 452 [plist setObject:[NSNumber numberWithBool:YES]
370 forKey:app_mode::kLSHasLocalizedDisplayNameKey]; 453 forKey:app_mode::kLSHasLocalizedDisplayNameKey];
371 454
372 base::FilePath app_name = app_path.BaseName().RemoveExtension(); 455 base::FilePath app_name = app_path.BaseName().RemoveExtension();
373 [plist setObject:base::mac::FilePathToNSString(app_name) 456 [plist setObject:base::mac::FilePathToNSString(app_name)
374 forKey:base::mac::CFToNSCast(kCFBundleNameKey)]; 457 forKey:base::mac::CFToNSCast(kCFBundleNameKey)];
375 458
376 return [plist writeToFile:plist_path atomically:YES]; 459 return [plist writeToFile:plist_path
460 atomically:YES];
377 } 461 }
378 462
379 bool WebAppShortcutCreator::UpdateDisplayName( 463 bool WebAppShortcutCreator::UpdateDisplayName(
380 const base::FilePath& app_path) const { 464 const base::FilePath& app_path) const {
381 // OSX searches for the best language in the order of preferred languages. 465 // OSX searches for the best language in the order of preferred languages.
382 // Since we only have one localization directory, it will choose this one. 466 // Since we only have one localization directory, it will choose this one.
383 base::FilePath localized_dir = GetResourcesPath(app_path).Append("en.lproj"); 467 base::FilePath localized_dir = GetResourcesPath(app_path).Append("en.lproj");
384 if (!file_util::CreateDirectory(localized_dir)) 468 if (!file_util::CreateDirectory(localized_dir))
385 return false; 469 return false;
386 470
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 if (!image_added) 511 if (!image_added)
428 return false; 512 return false;
429 513
430 base::FilePath resources_path = GetResourcesPath(app_path); 514 base::FilePath resources_path = GetResourcesPath(app_path);
431 if (!file_util::CreateDirectory(resources_path)) 515 if (!file_util::CreateDirectory(resources_path))
432 return false; 516 return false;
433 517
434 return icon_family.WriteDataToFile(resources_path.Append("app.icns")); 518 return icon_family.WriteDataToFile(resources_path.Append("app.icns"));
435 } 519 }
436 520
437 NSString* WebAppShortcutCreator::GetBundleIdentifier(NSDictionary* plist) const 521 bool WebAppShortcutCreator::UpdateInternalBundleIdentifier() const {
438 { 522 NSString* plist_path = base::mac::FilePathToNSString(
439 NSString* bundle_id_template = 523 app_data_path_.Append(GetShortcutName())
440 base::mac::ObjCCast<NSString>( 524 .Append("Contents").Append("Info.plist"));
441 [plist objectForKey:base::mac::CFToNSCast(kCFBundleIdentifierKey)]); 525 NSMutableDictionary* plist =
442 NSString* extension_id = base::SysUTF8ToNSString(info_.extension_id); 526 [NSMutableDictionary dictionaryWithContentsOfFile:plist_path];
443 NSString* placeholder = 527
444 [NSString stringWithFormat:@"@%@@", app_mode::kShortcutIdPlaceholder]; 528 [plist setObject:base::SysUTF8ToNSString(GetInternalBundleIdentifier())
445 NSString* bundle_id = 529 forKey:base::mac::CFToNSCast(kCFBundleIdentifierKey)];
446 [bundle_id_template 530 return [plist writeToFile:plist_path
447 stringByReplacingOccurrencesOfString:placeholder 531 atomically:YES];
448 withString:extension_id]; 532 }
533
534 base::FilePath WebAppShortcutCreator::GetAppBundleById(
535 const std::string& bundle_id) const {
536 base::mac::ScopedCFTypeRef<CFStringRef> bundle_id_cf(
537 base::SysUTF8ToCFStringRef(bundle_id));
538 CFURLRef url_ref = NULL;
539 OSStatus status = LSFindApplicationForInfo(
540 kLSUnknownCreator, bundle_id_cf.get(), NULL, NULL, &url_ref);
541 if (status != noErr)
542 return base::FilePath();
543
544 base::mac::ScopedCFTypeRef<CFURLRef> url(url_ref);
545 NSString* path_string = [base::mac::CFToNSCast(url.get()) path];
546 return base::FilePath([path_string fileSystemRepresentation]);
547 }
548
549 std::string WebAppShortcutCreator::GetBundleIdentifier() const {
550 // Replace spaces in the profile path with hyphen.
551 std::string normalized_profile_path;
552 ReplaceChars(info_.profile_path.BaseName().value(),
553 " ", "-", &normalized_profile_path);
554
555 // This matches APP_MODE_APP_BUNDLE_ID in chrome/chrome.gyp.
556 std::string bundle_id =
557 chrome_bundle_id_ + std::string(".app.") +
558 normalized_profile_path + "-" + info_.extension_id;
559
449 return bundle_id; 560 return bundle_id;
450 } 561 }
451 562
452 void WebAppShortcutCreator::RevealGeneratedBundleInFinder( 563 std::string WebAppShortcutCreator::GetInternalBundleIdentifier() const {
453 const base::FilePath& generated_bundle) const { 564 return GetBundleIdentifier() + "-internal";
565 }
566
567 void WebAppShortcutCreator::RevealAppShimInFinder() const {
568 base::FilePath dst_path = GetDestinationPath();
569 if (dst_path.empty())
570 return;
571
572 base::FilePath app_path = dst_path.Append(GetShortcutName());
454 [[NSWorkspace sharedWorkspace] 573 [[NSWorkspace sharedWorkspace]
455 selectFile:base::mac::FilePathToNSString(generated_bundle) 574 selectFile:base::mac::FilePathToNSString(app_path)
456 inFileViewerRootedAtPath:nil]; 575 inFileViewerRootedAtPath:nil];
457 } 576 }
458 577
459 base::FilePath GetAppInstallPath( 578 base::FilePath GetAppInstallPath(
460 const ShellIntegration::ShortcutInfo& shortcut_info) { 579 const ShellIntegration::ShortcutInfo& shortcut_info) {
461 WebAppShortcutCreator shortcut_creator(base::FilePath(), 580 WebAppShortcutCreator shortcut_creator(base::FilePath(),
462 shortcut_info, 581 shortcut_info,
463 string16()); 582 std::string());
464 return shortcut_creator.GetShortcutPath(); 583 base::FilePath dst_path = shortcut_creator.GetDestinationPath();
584 return dst_path.empty() ?
585 base::FilePath() : dst_path.Append(shortcut_creator.GetShortcutName());
465 } 586 }
466 587
467 void MaybeLaunchShortcut(const ShellIntegration::ShortcutInfo& shortcut_info) { 588 void MaybeLaunchShortcut(const ShellIntegration::ShortcutInfo& shortcut_info) {
468 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAppShims)) 589 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAppShims))
469 return; 590 return;
470 591
471 content::BrowserThread::PostTask( 592 content::BrowserThread::PostTask(
472 content::BrowserThread::FILE, FROM_HERE, 593 content::BrowserThread::FILE, FROM_HERE,
473 base::Bind(&LaunchShimOnFileThread, shortcut_info)); 594 base::Bind(&LaunchShimOnFileThread, shortcut_info));
474 } 595 }
475 596
476 namespace internals { 597 namespace internals {
477 598
478 base::FilePath GetAppBundleByExtensionId(std::string extension_id) {
479 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
480 // This matches APP_MODE_APP_BUNDLE_ID in chrome/chrome.gyp.
481 std::string bundle_id =
482 base::mac::BaseBundleID() + std::string(".app.") + extension_id;
483 base::mac::ScopedCFTypeRef<CFStringRef> bundle_id_cf(
484 base::SysUTF8ToCFStringRef(bundle_id));
485 CFURLRef url_ref = NULL;
486 OSStatus status = LSFindApplicationForInfo(
487 kLSUnknownCreator, bundle_id_cf.get(), NULL, NULL, &url_ref);
488 base::mac::ScopedCFTypeRef<CFURLRef> url(url_ref);
489
490 if (status != noErr)
491 return base::FilePath();
492
493 NSString* path_string = [base::mac::CFToNSCast(url.get()) path];
494 return base::FilePath([path_string fileSystemRepresentation]);
495 }
496
497 bool CreatePlatformShortcuts( 599 bool CreatePlatformShortcuts(
498 const base::FilePath& app_data_path, 600 const base::FilePath& app_data_path,
499 const ShellIntegration::ShortcutInfo& shortcut_info, 601 const ShellIntegration::ShortcutInfo& shortcut_info,
500 const ShellIntegration::ShortcutLocations& creation_locations) { 602 const ShellIntegration::ShortcutLocations& creation_locations) {
501 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); 603 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
502 string16 bundle_id = UTF8ToUTF16(base::mac::BaseBundleID()); 604 WebAppShortcutCreator shortcut_creator(
503 WebAppShortcutCreator shortcut_creator(app_data_path, shortcut_info, 605 app_data_path, shortcut_info, base::mac::BaseBundleID());
504 bundle_id); 606 return shortcut_creator.CreateShortcuts();
505 return shortcut_creator.CreateShortcut();
506 } 607 }
507 608
508 void DeletePlatformShortcuts( 609 void DeletePlatformShortcuts(
509 const base::FilePath& app_data_path, 610 const base::FilePath& app_data_path,
510 const ShellIntegration::ShortcutInfo& info) { 611 const ShellIntegration::ShortcutInfo& shortcut_info) {
511 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); 612 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
512 613 WebAppShortcutCreator shortcut_creator(
513 base::FilePath bundle_path = GetAppBundleByExtensionId(info.extension_id); 614 app_data_path, shortcut_info, base::mac::BaseBundleID());
514 file_util::Delete(bundle_path, true); 615 shortcut_creator.DeleteShortcuts();
515 } 616 }
516 617
517 void UpdatePlatformShortcuts( 618 void UpdatePlatformShortcuts(
518 const base::FilePath& app_data_path, 619 const base::FilePath& app_data_path,
519 const string16& old_app_title, 620 const string16& old_app_title,
520 const ShellIntegration::ShortcutInfo& shortcut_info) { 621 const ShellIntegration::ShortcutInfo& shortcut_info) {
521 // TODO(benwells): Implement this when shortcuts / weblings are enabled on 622 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
522 // mac. 623 WebAppShortcutCreator shortcut_creator(
624 app_data_path, shortcut_info, base::mac::BaseBundleID());
625 shortcut_creator.UpdateShortcuts();
523 } 626 }
524 627
525 } // namespace internals 628 } // namespace internals
526 629
527 } // namespace web_app 630 } // namespace web_app
OLDNEW
« no previous file with comments | « chrome/browser/web_applications/web_app_mac.h ('k') | chrome/browser/web_applications/web_app_mac_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698