shortcut_manager.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/apps/shortcut_manager.h" 6 7#include "base/bind.h" 8#include "base/compiler_specific.h" 9#include "base/prefs/pref_service.h" 10#include "base/strings/string16.h" 11#include "base/strings/utf_string_conversions.h" 12#include "chrome/browser/browser_process.h" 13#include "chrome/browser/extensions/extension_service.h" 14#include "chrome/browser/extensions/extension_ui_util.h" 15#include "chrome/browser/profiles/profile.h" 16#include "chrome/browser/profiles/profile_info_cache.h" 17#include "chrome/browser/profiles/profile_manager.h" 18#include "chrome/browser/shell_integration.h" 19#include "chrome/browser/web_applications/web_app.h" 20#include "chrome/common/pref_names.h" 21#include "components/pref_registry/pref_registry_syncable.h" 22#include "content/public/browser/browser_thread.h" 23#include "extensions/browser/extension_registry.h" 24#include "extensions/browser/extension_system.h" 25#include "extensions/browser/extension_util.h" 26#include "extensions/common/extension_set.h" 27#include "extensions/common/one_shot_event.h" 28 29using extensions::Extension; 30 31namespace { 32 33// This version number is stored in local prefs to check whether app shortcuts 34// need to be recreated. This might happen when we change various aspects of app 35// shortcuts like command-line flags or associated icons, binaries, etc. 36const int kCurrentAppShortcutsVersion = 0; 37 38// Delay in seconds before running UpdateShortcutsForAllApps. 39const int kUpdateShortcutsForAllAppsDelay = 10; 40 41void CreateShortcutsForApp(Profile* profile, const Extension* app) { 42 web_app::ShortcutLocations creation_locations; 43 44 if (extensions::util::IsEphemeralApp(app->id(), profile)) { 45 // Ephemeral apps should not have visible shortcuts, but may still require 46 // platform-specific handling. 47 creation_locations.applications_menu_location = 48 web_app::APP_MENU_LOCATION_HIDDEN; 49 } else { 50 // Creates a shortcut for an app in the Chrome Apps subdir of the 51 // applications menu, if there is not already one present. 52 creation_locations.applications_menu_location = 53 web_app::APP_MENU_LOCATION_SUBDIR_CHROMEAPPS; 54 } 55 56 web_app::CreateShortcuts( 57 web_app::SHORTCUT_CREATION_AUTOMATED, creation_locations, profile, app); 58} 59 60void SetCurrentAppShortcutsVersion(PrefService* prefs) { 61 prefs->SetInteger(prefs::kAppShortcutsVersion, kCurrentAppShortcutsVersion); 62} 63 64} // namespace 65 66// static 67void AppShortcutManager::RegisterProfilePrefs( 68 user_prefs::PrefRegistrySyncable* registry) { 69 // Indicates whether app shortcuts have been created. 70 registry->RegisterIntegerPref( 71 prefs::kAppShortcutsVersion, 0, 72 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 73} 74 75AppShortcutManager::AppShortcutManager(Profile* profile) 76 : profile_(profile), 77 is_profile_info_cache_observer_(false), 78 prefs_(profile->GetPrefs()), 79 extension_registry_observer_(this), 80 weak_ptr_factory_(this) { 81 // Use of g_browser_process requires that we are either on the UI thread, or 82 // there are no threads initialized (such as in unit tests). 83 DCHECK(!content::BrowserThread::IsThreadInitialized( 84 content::BrowserThread::UI) || 85 content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 86 87 extension_registry_observer_.Add( 88 extensions::ExtensionRegistry::Get(profile_)); 89 // Wait for extensions to be ready before running 90 // UpdateShortcutsForAllAppsIfNeeded. 91 extensions::ExtensionSystem::Get(profile)->ready().Post( 92 FROM_HERE, 93 base::Bind(&AppShortcutManager::UpdateShortcutsForAllAppsIfNeeded, 94 weak_ptr_factory_.GetWeakPtr())); 95 96 ProfileManager* profile_manager = g_browser_process->profile_manager(); 97 // profile_manager might be NULL in testing environments. 98 if (profile_manager) { 99 profile_manager->GetProfileInfoCache().AddObserver(this); 100 is_profile_info_cache_observer_ = true; 101 } 102} 103 104AppShortcutManager::~AppShortcutManager() { 105 if (g_browser_process && is_profile_info_cache_observer_) { 106 ProfileManager* profile_manager = g_browser_process->profile_manager(); 107 // profile_manager might be NULL in testing environments or during shutdown. 108 if (profile_manager) 109 profile_manager->GetProfileInfoCache().RemoveObserver(this); 110 } 111} 112 113void AppShortcutManager::OnExtensionWillBeInstalled( 114 content::BrowserContext* browser_context, 115 const Extension* extension, 116 bool is_update, 117 bool from_ephemeral, 118 const std::string& old_name) { 119 if (!extension->is_app()) 120 return; 121 122 // If the app is being updated, update any existing shortcuts but do not 123 // create new ones. If it is being installed, automatically create a 124 // shortcut in the applications menu (e.g., Start Menu). 125 if (is_update && !from_ephemeral) { 126 web_app::UpdateAllShortcuts( 127 base::UTF8ToUTF16(old_name), profile_, extension); 128 } else { 129 CreateShortcutsForApp(profile_, extension); 130 } 131} 132 133void AppShortcutManager::OnExtensionUninstalled( 134 content::BrowserContext* browser_context, 135 const Extension* extension) { 136 web_app::DeleteAllShortcuts(profile_, extension); 137} 138 139void AppShortcutManager::OnProfileWillBeRemoved( 140 const base::FilePath& profile_path) { 141 if (profile_path != profile_->GetPath()) 142 return; 143 content::BrowserThread::PostTask( 144 content::BrowserThread::FILE, FROM_HERE, 145 base::Bind(&web_app::internals::DeleteAllShortcutsForProfile, 146 profile_path)); 147} 148 149void AppShortcutManager::UpdateShortcutsForAllAppsIfNeeded() { 150 int last_version = prefs_->GetInteger(prefs::kAppShortcutsVersion); 151 if (last_version >= kCurrentAppShortcutsVersion) 152 return; 153 154 content::BrowserThread::PostDelayedTask( 155 content::BrowserThread::UI, 156 FROM_HERE, 157 base::Bind(&web_app::UpdateShortcutsForAllApps, 158 profile_, 159 base::Bind(&SetCurrentAppShortcutsVersion, prefs_)), 160 base::TimeDelta::FromSeconds(kUpdateShortcutsForAllAppsDelay)); 161} 162