shortcut_manager.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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" 86d86b77056ed63eb6871182f42a9fd5f07550f90Torne (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" 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/extensions/extension_service.h" 15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/extensions/extension_ui_util.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" 216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "chrome/common/chrome_switches.h" 224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/common/pref_names.h" 23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/pref_registry/pref_registry_syncable.h" 24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/public/browser/browser_thread.h" 25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/browser/extension_registry.h" 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h" 27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "extensions/browser/extension_util.h" 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/extension_set.h" 29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/one_shot_event.h" 30a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using extensions::Extension; 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace { 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// This version number is stored in local prefs to check whether app shortcuts 3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// need to be recreated. This might happen when we change various aspects of app 3746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// shortcuts like command-line flags or associated icons, binaries, etc. 386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#if defined(OS_MACOSX) 396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const int kCurrentAppShortcutsVersion = 1; 406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#else 4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const int kCurrentAppShortcutsVersion = 0; 426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#endif 4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Delay in seconds before running UpdateShortcutsForAllApps. 4546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const int kUpdateShortcutsForAllAppsDelay = 10; 4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void CreateShortcutsForApp(Profile* profile, const Extension* app) { 48a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch web_app::ShortcutLocations creation_locations; 49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (extensions::util::IsEphemeralApp(app->id(), profile)) { 51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Ephemeral apps should not have visible shortcuts, but may still require 52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // platform-specific handling. 53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) creation_locations.applications_menu_location = 54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) web_app::APP_MENU_LOCATION_HIDDEN; 55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Creates a shortcut for an app in the Chrome Apps subdir of the 57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // applications menu, if there is not already one present. 58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) creation_locations.applications_menu_location = 59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) web_app::APP_MENU_LOCATION_SUBDIR_CHROMEAPPS; 60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 62c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch web_app::CreateShortcuts( 63c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch web_app::SHORTCUT_CREATION_AUTOMATED, creation_locations, profile, app); 64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void SetCurrentAppShortcutsVersion(PrefService* prefs) { 6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) prefs->SetInteger(prefs::kAppShortcutsVersion, kCurrentAppShortcutsVersion); 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static 734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void AppShortcutManager::RegisterProfilePrefs( 744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) user_prefs::PrefRegistrySyncable* registry) { 754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Indicates whether app shortcuts have been created. 7646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) registry->RegisterIntegerPref( 7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) prefs::kAppShortcutsVersion, 0, 784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 81558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochAppShortcutManager::AppShortcutManager(Profile* profile) 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : profile_(profile), 83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch is_profile_info_cache_observer_(false), 84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) prefs_(profile->GetPrefs()), 85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) extension_registry_observer_(this), 86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) weak_ptr_factory_(this) { 872385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch // Use of g_browser_process requires that we are either on the UI thread, or 882385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch // there are no threads initialized (such as in unit tests). 89ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch DCHECK(!content::BrowserThread::IsThreadInitialized( 90ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch content::BrowserThread::UI) || 91ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 922385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch 93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) extension_registry_observer_.Add( 94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) extensions::ExtensionRegistry::Get(profile_)); 9546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // Wait for extensions to be ready before running 9646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // UpdateShortcutsForAllAppsIfNeeded. 97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) extensions::ExtensionSystem::Get(profile)->ready().Post( 98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FROM_HERE, 9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::Bind(&AppShortcutManager::UpdateShortcutsForAllAppsIfNeeded, 100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr())); 101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ProfileManager* profile_manager = g_browser_process->profile_manager(); 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // profile_manager might be NULL in testing environments. 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (profile_manager) { 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch profile_manager->GetProfileInfoCache().AddObserver(this); 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch is_profile_info_cache_observer_ = true; 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 110558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochAppShortcutManager::~AppShortcutManager() { 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (g_browser_process && is_profile_info_cache_observer_) { 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ProfileManager* profile_manager = g_browser_process->profile_manager(); 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // profile_manager might be NULL in testing environments or during shutdown. 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (profile_manager) 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch profile_manager->GetProfileInfoCache().RemoveObserver(this); 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void AppShortcutManager::OnExtensionWillBeInstalled( 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) content::BrowserContext* browser_context, 121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const Extension* extension, 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool is_update, 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool from_ephemeral, 124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& old_name) { 125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!extension->is_app()) 126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // If the app is being updated, update any existing shortcuts but do not 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // create new ones. If it is being installed, automatically create a 130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // shortcut in the applications menu (e.g., Start Menu). 131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (is_update && !from_ephemeral) { 132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) web_app::UpdateAllShortcuts( 133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::UTF8ToUTF16(old_name), profile_, extension); 13446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } else { 135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CreateShortcutsForApp(profile_, extension); 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void AppShortcutManager::OnExtensionUninstalled( 140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) content::BrowserContext* browser_context, 141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const Extension* extension) { 142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) web_app::DeleteAllShortcuts(profile_, extension); 143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 145558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid AppShortcutManager::OnProfileWillBeRemoved( 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const base::FilePath& profile_path) { 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (profile_path != profile_->GetPath()) 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch content::BrowserThread::PostTask( 150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch content::BrowserThread::FILE, FROM_HERE, 151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Bind(&web_app::internals::DeleteAllShortcutsForProfile, 152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch profile_path)); 153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 15546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void AppShortcutManager::UpdateShortcutsForAllAppsIfNeeded() { 1566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) 1576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return; 1586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 15946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) int last_version = prefs_->GetInteger(prefs::kAppShortcutsVersion); 16046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (last_version >= kCurrentAppShortcutsVersion) 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return; 162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 16346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) content::BrowserThread::PostDelayedTask( 16446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) content::BrowserThread::UI, 16546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) FROM_HERE, 16646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::Bind(&web_app::UpdateShortcutsForAllApps, 16746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) profile_, 16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::Bind(&SetCurrentAppShortcutsVersion, prefs_)), 16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::TimeDelta::FromSeconds(kUpdateShortcutsForAllAppsDelay)); 170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 171