shortcut_manager.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
1558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "chrome/browser/apps/shortcut_manager.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/command_line.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/compiler_specific.h" 10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/prefs/pref_service.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string16.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/browser_process.h" 147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h" 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/extensions/extension_service.h" 16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/profiles/profile.h" 17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/profiles/profile_info_cache.h" 18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/profiles/profile_manager.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/shell_integration.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/web_applications/web_app.h" 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/chrome_switches.h" 224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/common/pref_names.h" 234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "components/user_prefs/pref_registry_syncable.h" 24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/public/browser/browser_thread.h" 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_details.h" 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_source.h" 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h" 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/extension_set.h" 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 30a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#if defined(OS_MACOSX) 31a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "apps/app_shim/app_shim_mac.h" 32a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#endif 33a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using extensions::Extension; 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace { 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Creates a shortcut for an application in the applications menu, if there is 39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// not already one present. 40c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid CreateShortcutsInApplicationsMenu(Profile* profile, 41c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const Extension* app) { 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ShellIntegration::ShortcutLocations creation_locations; 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Create the shortcut in the Chrome Apps subdir. 44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) creation_locations.applications_menu_location = 45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ShellIntegration::APP_MENU_LOCATION_SUBDIR_CHROMEAPPS; 46c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch web_app::CreateShortcuts( 47c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch web_app::SHORTCUT_CREATION_AUTOMATED, creation_locations, profile, app); 48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 50c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool ShouldCreateShortcutFor(const Extension* extension) { 51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return extension->is_platform_app() && 52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch extension->location() != extensions::Manifest::COMPONENT && 53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch extension->ShouldDisplayInAppLauncher(); 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static 594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void AppShortcutManager::RegisterProfilePrefs( 604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) user_prefs::PrefRegistrySyncable* registry) { 614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Indicates whether app shortcuts have been created. 624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) registry->RegisterBooleanPref( 634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) prefs::kAppShortcutsHaveBeenCreated, false, 644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 67558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochAppShortcutManager::AppShortcutManager(Profile* profile) 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : profile_(profile), 69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch is_profile_info_cache_observer_(false), 7023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) prefs_(profile->GetPrefs()) { 712385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch // Use of g_browser_process requires that we are either on the UI thread, or 722385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch // there are no threads initialized (such as in unit tests). 73ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch DCHECK(!content::BrowserThread::IsThreadInitialized( 74ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch content::BrowserThread::UI) || 75ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 762385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::Source<Profile>(profile_)); 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::Source<Profile>(profile_)); 81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Wait for extensions to be ready before running OnceOffCreateShortcuts. 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, 83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch content::Source<Profile>(profile_)); 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ProfileManager* profile_manager = g_browser_process->profile_manager(); 86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // profile_manager might be NULL in testing environments. 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (profile_manager) { 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch profile_manager->GetProfileInfoCache().AddObserver(this); 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch is_profile_info_cache_observer_ = true; 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 93558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochAppShortcutManager::~AppShortcutManager() { 94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (g_browser_process && is_profile_info_cache_observer_) { 95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ProfileManager* profile_manager = g_browser_process->profile_manager(); 96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // profile_manager might be NULL in testing environments or during shutdown. 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (profile_manager) 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch profile_manager->GetProfileInfoCache().RemoveObserver(this); 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 102558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid AppShortcutManager::Observe(int type, 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const content::NotificationSource& source, 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const content::NotificationDetails& details) { 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (type) { 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch case chrome::NOTIFICATION_EXTENSIONS_READY: { 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch OnceOffCreateShortcuts(); 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch break; 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case chrome::NOTIFICATION_EXTENSION_INSTALLED: { 111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#if defined(OS_MACOSX) 112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!apps::IsAppShimsEnabled()) 113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) break; 114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif // defined(OS_MACOSX) 115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const extensions::InstalledExtensionInfo* installed_info = 117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::Details<const extensions::InstalledExtensionInfo>(details) 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) .ptr(); 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const Extension* extension = installed_info->extension; 12023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // If the app is being updated, update any existing shortcuts but do not 12123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // create new ones. If it is being installed, automatically create a 12223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // shortcut in the applications menu (e.g., Start Menu). 12323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (installed_info->is_update) { 124c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch web_app::UpdateAllShortcuts( 125c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::UTF8ToUTF16(installed_info->old_name), profile_, extension); 12623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } else if (ShouldCreateShortcutFor(extension)) { 127c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch CreateShortcutsInApplicationsMenu(profile_, extension); 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: { 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const Extension* extension = content::Details<const Extension>( 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) details).ptr(); 134c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch web_app::DeleteAllShortcuts(profile_, extension); 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 142558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid AppShortcutManager::OnProfileWillBeRemoved( 143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const base::FilePath& profile_path) { 144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (profile_path != profile_->GetPath()) 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch content::BrowserThread::PostTask( 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch content::BrowserThread::FILE, FROM_HERE, 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Bind(&web_app::internals::DeleteAllShortcutsForProfile, 149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch profile_path)); 150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 152558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid AppShortcutManager::OnceOffCreateShortcuts() { 1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool was_enabled = prefs_->GetBoolean(prefs::kAppShortcutsHaveBeenCreated); 154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Creation of shortcuts on Mac currently can be disabled with 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // --disable-app-shims, so check the flag, and set the pref accordingly. 157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_MACOSX) 158a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) bool is_now_enabled = apps::IsAppShimsEnabled(); 159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#else 160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool is_now_enabled = true; 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif // defined(OS_MACOSX) 162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (was_enabled != is_now_enabled) 1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) prefs_->SetBoolean(prefs::kAppShortcutsHaveBeenCreated, is_now_enabled); 165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (was_enabled || !is_now_enabled) 167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Check if extension system/service are available. They might not be in 170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // tests. 171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch extensions::ExtensionSystem* extension_system; 172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ExtensionServiceInterface* extension_service; 173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!(extension_system = extensions::ExtensionSystem::Get(profile_)) || 174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch !(extension_service = extension_system->extension_service())) 175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Create an applications menu shortcut for each app in this profile. 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const extensions::ExtensionSet* apps = extension_service->extensions(); 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (extensions::ExtensionSet::const_iterator it = apps->begin(); 180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch it != apps->end(); ++it) { 181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (ShouldCreateShortcutFor(it->get())) 182c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch CreateShortcutsInApplicationsMenu(profile_, it->get()); 183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 185