| 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 #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 Loading... |
| 159 return false; | 159 return false; |
| 160 } | 160 } |
| 161 | 161 |
| 162 } // namespace | 162 } // namespace |
| 163 | 163 |
| 164 namespace web_app { | 164 namespace web_app { |
| 165 | 165 |
| 166 const char kChromeAppDirName[] = "Chrome Apps.localized"; | 166 const char kChromeAppDirName[] = "Chrome Apps.localized"; |
| 167 | 167 |
| 168 WebAppShortcutCreator::WebAppShortcutCreator( | 168 WebAppShortcutCreator::WebAppShortcutCreator( |
| 169 const base::FilePath& user_data_dir, | 169 const base::FilePath& app_data_path, |
| 170 const ShellIntegration::ShortcutInfo& shortcut_info, | 170 const ShellIntegration::ShortcutInfo& shortcut_info, |
| 171 const string16& chrome_bundle_id) | 171 const string16& chrome_bundle_id) |
| 172 : user_data_dir_(user_data_dir), | 172 : app_data_path_(app_data_path), |
| 173 info_(shortcut_info), | 173 info_(shortcut_info), |
| 174 chrome_bundle_id_(chrome_bundle_id) { | 174 chrome_bundle_id_(chrome_bundle_id) { |
| 175 } | 175 } |
| 176 | 176 |
| 177 WebAppShortcutCreator::~WebAppShortcutCreator() { | 177 WebAppShortcutCreator::~WebAppShortcutCreator() { |
| 178 } | 178 } |
| 179 | 179 |
| 180 base::FilePath WebAppShortcutCreator::GetShortcutPath() const { | 180 base::FilePath WebAppShortcutCreator::GetShortcutPath() const { |
| 181 base::FilePath dst_path = GetDestinationPath(); | 181 base::FilePath dst_path = GetDestinationPath(); |
| 182 if (dst_path.empty()) | 182 if (dst_path.empty()) |
| 183 return dst_path; | 183 return dst_path; |
| 184 | 184 |
| 185 base::FilePath app_name = internals::GetSanitizedFileName(UTF8ToUTF16( | 185 base::FilePath app_name = internals::GetSanitizedFileName(UTF8ToUTF16( |
| 186 info_.profile_path.BaseName().value() + " " + info_.extension_id)); | 186 info_.profile_path.BaseName().value() + " " + info_.extension_id)); |
| 187 return dst_path.Append(app_name.ReplaceExtension("app")); | 187 return dst_path.Append(app_name.ReplaceExtension("app")); |
| 188 } | 188 } |
| 189 | 189 |
| 190 bool WebAppShortcutCreator::CreateShortcut() { | 190 bool WebAppShortcutCreator::CreateShortcut() { |
| 191 base::FilePath app_path = GetShortcutPath(); | 191 base::FilePath app_path = GetShortcutPath(); |
| 192 base::FilePath app_name = app_path.BaseName(); | 192 base::FilePath app_name = app_path.BaseName(); |
| 193 base::FilePath dst_path = app_path.DirName(); | 193 base::FilePath dst_path = app_path.DirName(); |
| 194 if (app_path.empty() || !file_util::DirectoryExists(dst_path.DirName())) { | 194 if (app_path.empty() || !file_util::DirectoryExists(dst_path.DirName())) { |
| 195 LOG(ERROR) << "Couldn't find an Applications directory to copy app to."; | 195 LOG(ERROR) << "Couldn't find an Applications directory to copy app to."; |
| 196 return false; | 196 return false; |
| 197 } | 197 } |
| 198 if (!file_util::CreateDirectory(app_data_path_)) { |
| 199 LOG(ERROR) << "Creating app_data_path " << app_data_path_.value() |
| 200 << " failed."; |
| 201 return false; |
| 202 } |
| 198 if (!file_util::CreateDirectory(dst_path)) { | 203 if (!file_util::CreateDirectory(dst_path)) { |
| 199 LOG(ERROR) << "Creating directory " << dst_path.value() << " failed."; | 204 LOG(ERROR) << "Creating directory " << dst_path.value() << " failed."; |
| 200 return false; | 205 return false; |
| 201 } | 206 } |
| 202 | 207 |
| 203 base::ScopedTempDir scoped_temp_dir; | 208 base::ScopedTempDir scoped_temp_dir; |
| 204 if (!scoped_temp_dir.CreateUniqueTempDir()) | 209 if (!scoped_temp_dir.CreateUniqueTempDir()) |
| 205 return false; | 210 return false; |
| 206 base::FilePath staging_path = scoped_temp_dir.path().Append(app_name); | 211 base::FilePath staging_path = scoped_temp_dir.path().Append(app_name); |
| 207 | 212 |
| 208 // Update the app's plist and icon in a temp directory. This works around | 213 // Update the app's plist and icon in a temp directory. This works around |
| 209 // a Finder bug where the app's icon doesn't properly update. | 214 // a Finder bug where the app's icon doesn't properly update. |
| 210 if (!file_util::CopyDirectory(GetAppLoaderPath(), staging_path, true)) { | 215 if (!file_util::CopyDirectory(GetAppLoaderPath(), staging_path, true)) { |
| 211 LOG(ERROR) << "Copying app to staging path: " << staging_path.value() | 216 LOG(ERROR) << "Copying app to staging path: " << staging_path.value() |
| 212 << " failed"; | 217 << " failed."; |
| 213 return false; | 218 return false; |
| 214 } | 219 } |
| 215 | 220 |
| 216 if (!UpdatePlist(staging_path)) | 221 if (!UpdatePlist(staging_path)) |
| 217 return false; | 222 return false; |
| 218 | 223 |
| 219 if (!UpdateDisplayName(staging_path)) | 224 if (!UpdateDisplayName(staging_path)) |
| 220 return false; | 225 return false; |
| 221 | 226 |
| 222 if (!UpdateIcon(staging_path)) | 227 if (!UpdateIcon(staging_path)) |
| 223 return false; | 228 return false; |
| 224 | 229 |
| 225 if (!file_util::CopyDirectory(staging_path, dst_path, true)) { | 230 // Put one copy in the app's app_data_path so we can still run it if the user |
| 226 LOG(ERROR) << "Copying app to dst path: " << dst_path.value() << " failed"; | 231 // deletes the one in the applications folder. |
| 232 if (!file_util::CopyDirectory(staging_path, app_data_path_, true)) { |
| 233 NOTREACHED(); |
| 227 return false; | 234 return false; |
| 228 } | 235 } |
| 236 base::mac::RemoveQuarantineAttribute(app_data_path_.Append(app_name)); |
| 237 |
| 238 if (!file_util::CopyDirectory(staging_path, dst_path, true)) |
| 239 return false; |
| 229 | 240 |
| 230 base::mac::RemoveQuarantineAttribute(app_path); | 241 base::mac::RemoveQuarantineAttribute(app_path); |
| 231 RevealGeneratedBundleInFinder(app_path); | 242 RevealGeneratedBundleInFinder(app_path); |
| 232 | 243 |
| 233 return true; | 244 return true; |
| 234 } | 245 } |
| 235 | 246 |
| 236 base::FilePath WebAppShortcutCreator::GetAppLoaderPath() const { | 247 base::FilePath WebAppShortcutCreator::GetAppLoaderPath() const { |
| 237 return base::mac::PathForFrameworkBundleResource( | 248 return base::mac::PathForFrameworkBundleResource( |
| 238 base::mac::NSToCFCast(@"app_mode_loader.app")); | 249 base::mac::NSToCFCast(@"app_mode_loader.app")); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 [value substringWithRange:NSMakeRange(1, [value length] - 2)]; | 286 [value substringWithRange:NSMakeRange(1, [value length] - 2)]; |
| 276 | 287 |
| 277 NSString* substitution = [replacement_dict valueForKey:variable]; | 288 NSString* substitution = [replacement_dict valueForKey:variable]; |
| 278 if (substitution) | 289 if (substitution) |
| 279 [plist setObject:substitution forKey:key]; | 290 [plist setObject:substitution forKey:key]; |
| 280 } | 291 } |
| 281 | 292 |
| 282 // 2. Fill in other values. | 293 // 2. Fill in other values. |
| 283 [plist setObject:GetBundleIdentifier(plist) | 294 [plist setObject:GetBundleIdentifier(plist) |
| 284 forKey:base::mac::CFToNSCast(kCFBundleIdentifierKey)]; | 295 forKey:base::mac::CFToNSCast(kCFBundleIdentifierKey)]; |
| 285 [plist setObject:base::mac::FilePathToNSString(user_data_dir_) | 296 [plist setObject:base::mac::FilePathToNSString(app_data_path_) |
| 286 forKey:app_mode::kCrAppModeUserDataDirKey]; | 297 forKey:app_mode::kCrAppModeUserDataDirKey]; |
| 287 [plist setObject:base::mac::FilePathToNSString(info_.profile_path.BaseName()) | 298 [plist setObject:base::mac::FilePathToNSString(info_.profile_path.BaseName()) |
| 288 forKey:app_mode::kCrAppModeProfileDirKey]; | 299 forKey:app_mode::kCrAppModeProfileDirKey]; |
| 289 [plist setObject:base::SysUTF8ToNSString(info_.profile_name) | 300 [plist setObject:base::SysUTF8ToNSString(info_.profile_name) |
| 290 forKey:app_mode::kCrAppModeProfileNameKey]; | 301 forKey:app_mode::kCrAppModeProfileNameKey]; |
| 291 [plist setObject:[NSNumber numberWithBool:YES] | 302 [plist setObject:[NSNumber numberWithBool:YES] |
| 292 forKey:app_mode::kLSHasLocalizedDisplayNameKey]; | 303 forKey:app_mode::kLSHasLocalizedDisplayNameKey]; |
| 293 | 304 |
| 294 base::FilePath app_name = app_path.BaseName().RemoveExtension(); | 305 base::FilePath app_name = app_path.BaseName().RemoveExtension(); |
| 295 [plist setObject:base::mac::FilePathToNSString(app_name) | 306 [plist setObject:base::mac::FilePathToNSString(app_name) |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 const base::FilePath& generated_bundle) const { | 386 const base::FilePath& generated_bundle) const { |
| 376 [[NSWorkspace sharedWorkspace] | 387 [[NSWorkspace sharedWorkspace] |
| 377 selectFile:base::mac::FilePathToNSString(generated_bundle) | 388 selectFile:base::mac::FilePathToNSString(generated_bundle) |
| 378 inFileViewerRootedAtPath:nil]; | 389 inFileViewerRootedAtPath:nil]; |
| 379 } | 390 } |
| 380 | 391 |
| 381 void LaunchShimOnFileThread( | 392 void LaunchShimOnFileThread( |
| 382 const ShellIntegration::ShortcutInfo& shortcut_info) { | 393 const ShellIntegration::ShortcutInfo& shortcut_info) { |
| 383 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 394 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
| 384 base::FilePath shim_path = web_app::GetAppInstallPath(shortcut_info); | 395 base::FilePath shim_path = web_app::GetAppInstallPath(shortcut_info); |
| 385 if (shim_path.empty()) | 396 |
| 386 return; | 397 if (shim_path.empty() || !file_util::PathExists(shim_path)) { |
| 398 // The user may have deleted the copy in the Applications folder, use the |
| 399 // one in the web app's app_data_path. |
| 400 base::FilePath app_data_path = GetWebAppDataDirectory( |
| 401 shortcut_info.profile_path, shortcut_info.extension_id, GURL()); |
| 402 shim_path = app_data_path.Append(shim_path.BaseName()); |
| 403 } |
| 387 | 404 |
| 388 CommandLine command_line(CommandLine::NO_PROGRAM); | 405 CommandLine command_line(CommandLine::NO_PROGRAM); |
| 389 command_line.AppendSwitch(app_mode::kNoLaunchApp); | 406 command_line.AppendSwitch(app_mode::kNoLaunchApp); |
| 390 base::mac::OpenApplicationWithPath(shim_path, command_line, NULL); | 407 base::mac::OpenApplicationWithPath(shim_path, command_line, NULL); |
| 391 } | 408 } |
| 392 | 409 |
| 393 } // namespace | 410 } // namespace |
| 394 | 411 |
| 395 namespace web_app { | 412 namespace web_app { |
| 396 | 413 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 426 base::mac::ScopedCFTypeRef<CFURLRef> url(url_ref); | 443 base::mac::ScopedCFTypeRef<CFURLRef> url(url_ref); |
| 427 | 444 |
| 428 if (status != noErr) | 445 if (status != noErr) |
| 429 return base::FilePath(); | 446 return base::FilePath(); |
| 430 | 447 |
| 431 NSString* path_string = [base::mac::CFToNSCast(url.get()) path]; | 448 NSString* path_string = [base::mac::CFToNSCast(url.get()) path]; |
| 432 return base::FilePath([path_string fileSystemRepresentation]); | 449 return base::FilePath([path_string fileSystemRepresentation]); |
| 433 } | 450 } |
| 434 | 451 |
| 435 bool CreatePlatformShortcuts( | 452 bool CreatePlatformShortcuts( |
| 436 const base::FilePath& web_app_path, | 453 const base::FilePath& app_data_path, |
| 437 const ShellIntegration::ShortcutInfo& shortcut_info, | 454 const ShellIntegration::ShortcutInfo& shortcut_info, |
| 438 const ShellIntegration::ShortcutLocations& /*creation_locations*/) { | 455 const ShellIntegration::ShortcutLocations& creation_locations) { |
| 439 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 456 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
| 440 string16 bundle_id = UTF8ToUTF16(base::mac::BaseBundleID()); | 457 string16 bundle_id = UTF8ToUTF16(base::mac::BaseBundleID()); |
| 441 WebAppShortcutCreator shortcut_creator(web_app_path, shortcut_info, | 458 WebAppShortcutCreator shortcut_creator(app_data_path, shortcut_info, |
| 442 bundle_id); | 459 bundle_id); |
| 443 return shortcut_creator.CreateShortcut(); | 460 return shortcut_creator.CreateShortcut(); |
| 444 } | 461 } |
| 445 | 462 |
| 446 void DeletePlatformShortcuts( | 463 void DeletePlatformShortcuts( |
| 447 const base::FilePath& web_app_path, | 464 const base::FilePath& app_data_path, |
| 448 const ShellIntegration::ShortcutInfo& info) { | 465 const ShellIntegration::ShortcutInfo& info) { |
| 449 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 466 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
| 450 | 467 |
| 451 base::FilePath bundle_path = GetAppBundleByExtensionId(info.extension_id); | 468 base::FilePath bundle_path = GetAppBundleByExtensionId(info.extension_id); |
| 452 file_util::Delete(bundle_path, true); | 469 file_util::Delete(bundle_path, true); |
| 453 } | 470 } |
| 454 | 471 |
| 455 void UpdatePlatformShortcuts( | 472 void UpdatePlatformShortcuts( |
| 456 const base::FilePath& web_app_path, | 473 const base::FilePath& app_data_path, |
| 457 const string16& old_app_title, | 474 const string16& old_app_title, |
| 458 const ShellIntegration::ShortcutInfo& shortcut_info) { | 475 const ShellIntegration::ShortcutInfo& shortcut_info) { |
| 459 // TODO(benwells): Implement this when shortcuts / weblings are enabled on | 476 // TODO(benwells): Implement this when shortcuts / weblings are enabled on |
| 460 // mac. | 477 // mac. |
| 461 } | 478 } |
| 462 | 479 |
| 463 } // namespace internals | 480 } // namespace internals |
| 464 | 481 |
| 465 } // namespace web_app | 482 } // namespace web_app |
| OLD | NEW |