shortcut_manager.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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/command_line.h"
9#include "base/compiler_specific.h"
10#include "base/prefs/pref_service.h"
11#include "base/strings/string16.h"
12#include "base/strings/utf_string_conversions.h"
13#include "chrome/browser/browser_process.h"
14#include "chrome/browser/extensions/extension_service.h"
15#include "chrome/browser/extensions/extension_ui_util.h"
16#include "chrome/browser/profiles/profile.h"
17#include "chrome/browser/profiles/profile_info_cache.h"
18#include "chrome/browser/profiles/profile_manager.h"
19#include "chrome/browser/shell_integration.h"
20#include "chrome/browser/web_applications/web_app.h"
21#include "chrome/common/chrome_switches.h"
22#include "chrome/common/pref_names.h"
23#include "components/pref_registry/pref_registry_syncable.h"
24#include "content/public/browser/browser_thread.h"
25#include "extensions/browser/extension_registry.h"
26#include "extensions/browser/extension_system.h"
27#include "extensions/common/extension_set.h"
28#include "extensions/common/one_shot_event.h"
29
30using extensions::Extension;
31
32namespace {
33
34// Creates a shortcut for an application in the applications menu, if there is
35// not already one present.
36void CreateShortcutsInApplicationsMenu(Profile* profile,
37                                       const Extension* app) {
38  web_app::ShortcutLocations creation_locations;
39  // Create the shortcut in the Chrome Apps subdir.
40  creation_locations.applications_menu_location =
41      web_app::APP_MENU_LOCATION_SUBDIR_CHROMEAPPS;
42  web_app::CreateShortcuts(
43      web_app::SHORTCUT_CREATION_AUTOMATED, creation_locations, profile, app);
44}
45
46bool ShouldCreateShortcutFor(Profile* profile, const Extension* extension) {
47  return extension->is_platform_app() &&
48      extension->location() != extensions::Manifest::COMPONENT &&
49      extensions::ui_util::ShouldDisplayInAppLauncher(extension, profile);
50}
51
52}  // namespace
53
54// static
55void AppShortcutManager::RegisterProfilePrefs(
56    user_prefs::PrefRegistrySyncable* registry) {
57  // Indicates whether app shortcuts have been created.
58  registry->RegisterBooleanPref(
59      prefs::kAppShortcutsHaveBeenCreated, false,
60      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
61}
62
63AppShortcutManager::AppShortcutManager(Profile* profile)
64    : profile_(profile),
65      is_profile_info_cache_observer_(false),
66      prefs_(profile->GetPrefs()),
67      extension_registry_observer_(this),
68      weak_ptr_factory_(this) {
69  // Use of g_browser_process requires that we are either on the UI thread, or
70  // there are no threads initialized (such as in unit tests).
71  DCHECK(!content::BrowserThread::IsThreadInitialized(
72             content::BrowserThread::UI) ||
73         content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
74
75  extension_registry_observer_.Add(
76      extensions::ExtensionRegistry::Get(profile_));
77  // Wait for extensions to be ready before running OnceOffCreateShortcuts.
78  extensions::ExtensionSystem::Get(profile)->ready().Post(
79      FROM_HERE,
80      base::Bind(&AppShortcutManager::OnceOffCreateShortcuts,
81                 weak_ptr_factory_.GetWeakPtr()));
82
83  ProfileManager* profile_manager = g_browser_process->profile_manager();
84  // profile_manager might be NULL in testing environments.
85  if (profile_manager) {
86    profile_manager->GetProfileInfoCache().AddObserver(this);
87    is_profile_info_cache_observer_ = true;
88  }
89}
90
91AppShortcutManager::~AppShortcutManager() {
92  if (g_browser_process && is_profile_info_cache_observer_) {
93    ProfileManager* profile_manager = g_browser_process->profile_manager();
94    // profile_manager might be NULL in testing environments or during shutdown.
95    if (profile_manager)
96      profile_manager->GetProfileInfoCache().RemoveObserver(this);
97  }
98}
99
100void AppShortcutManager::OnExtensionWillBeInstalled(
101    content::BrowserContext* browser_context,
102    const Extension* extension,
103    bool is_update,
104    bool from_ephemeral,
105    const std::string& old_name) {
106  if (!extension->is_app())
107    return;
108
109  // If the app is being updated, update any existing shortcuts but do not
110  // create new ones. If it is being installed, automatically create a
111  // shortcut in the applications menu (e.g., Start Menu).
112  if (is_update && !from_ephemeral) {
113    web_app::UpdateAllShortcuts(
114        base::UTF8ToUTF16(old_name), profile_, extension);
115  } else if (ShouldCreateShortcutFor(profile_, extension)) {
116    CreateShortcutsInApplicationsMenu(profile_, extension);
117  }
118}
119
120void AppShortcutManager::OnExtensionUninstalled(
121    content::BrowserContext* browser_context,
122    const Extension* extension) {
123  web_app::DeleteAllShortcuts(profile_, extension);
124}
125
126void AppShortcutManager::OnProfileWillBeRemoved(
127    const base::FilePath& profile_path) {
128  if (profile_path != profile_->GetPath())
129    return;
130  content::BrowserThread::PostTask(
131      content::BrowserThread::FILE, FROM_HERE,
132      base::Bind(&web_app::internals::DeleteAllShortcutsForProfile,
133                 profile_path));
134}
135
136void AppShortcutManager::OnceOffCreateShortcuts() {
137  if (prefs_->GetBoolean(prefs::kAppShortcutsHaveBeenCreated))
138    return;
139
140  prefs_->SetBoolean(prefs::kAppShortcutsHaveBeenCreated, true);
141
142  // Check if extension system/service are available. They might not be in
143  // tests.
144  extensions::ExtensionSystem* extension_system;
145  ExtensionServiceInterface* extension_service;
146  if (!(extension_system = extensions::ExtensionSystem::Get(profile_)) ||
147      !(extension_service = extension_system->extension_service()))
148    return;
149
150  // Create an applications menu shortcut for each app in this profile.
151  const extensions::ExtensionSet* apps = extension_service->extensions();
152  for (extensions::ExtensionSet::const_iterator it = apps->begin();
153       it != apps->end(); ++it) {
154    if (ShouldCreateShortcutFor(profile_, it->get()))
155      CreateShortcutsInApplicationsMenu(profile_, it->get());
156  }
157}
158