• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/extensions/default_apps.h"
6 
7 #include <set>
8 #include <string>
9 
10 #include "base/command_line.h"
11 #include "base/prefs/pref_service.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/chrome_version_info.h"
16 #include "chrome/common/extensions/extension_constants.h"
17 #include "chrome/common/pref_names.h"
18 #include "components/pref_registry/pref_registry_syncable.h"
19 #include "extensions/common/extension.h"
20 #include "ui/base/l10n/l10n_util.h"
21 
22 #if !defined(OS_ANDROID)
23 #include "chrome/browser/first_run/first_run.h"
24 #endif
25 
26 namespace {
27 
28 // Returns true if the app was a default app in Chrome 22
IsOldDefaultApp(const std::string & extension_id)29 bool IsOldDefaultApp(const std::string& extension_id) {
30   return extension_id == extension_misc::kGmailAppId ||
31          extension_id == extension_misc::kGoogleSearchAppId ||
32          extension_id == extension_misc::kYoutubeAppId;
33 }
34 
IsLocaleSupported()35 bool IsLocaleSupported() {
36   // Don't bother installing default apps in locales where it is known that
37   // they don't work.
38   // TODO(rogerta): Do this check dynamically once the webstore can expose
39   // an API. See http://crbug.com/101357
40   const std::string& locale = g_browser_process->GetApplicationLocale();
41   static const char* unsupported_locales[] = {"CN", "TR", "IR"};
42   for (size_t i = 0; i < arraysize(unsupported_locales); ++i) {
43     if (EndsWith(locale, unsupported_locales[i], false)) {
44       return false;
45     }
46   }
47   return true;
48 }
49 
50 }  // namespace
51 
52 namespace default_apps {
53 
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)54 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
55   registry->RegisterIntegerPref(
56       prefs::kDefaultAppsInstallState,
57       kUnknown,
58       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
59 }
60 
ShouldInstallInProfile()61 bool Provider::ShouldInstallInProfile() {
62   // We decide to install or not install default apps based on the following
63   // criteria, from highest priority to lowest priority:
64   //
65   // - The command line option.  Tests use this option to disable installation
66   //   of default apps in some cases.
67   // - If the locale is not compatible with the defaults, don't install them.
68   // - The kDefaultApps preferences value in the profile.  This value is
69   //   usually set in the master_preferences file.
70   bool install_apps =
71       profile_->GetPrefs()->GetString(prefs::kDefaultApps) == "install";
72 
73   InstallState state =
74       static_cast<InstallState>(profile_->GetPrefs()->GetInteger(
75           prefs::kDefaultAppsInstallState));
76 
77   is_migration_ = (state == kProvideLegacyDefaultApps);
78 
79   switch (state) {
80     case kUnknown: {
81       // Only new installations and profiles get default apps. In theory the
82       // new profile checks should catch new installations, but that is not
83       // always the case (http:/crbug.com/145351).
84       chrome::VersionInfo version_info;
85       bool is_new_profile =
86           profile_->WasCreatedByVersionOrLater(version_info.Version().c_str());
87       // Android excludes most of the first run code, so it can't determine
88       // if this is a first run. That's OK though, because Android doesn't
89       // use default apps in general.
90 #if defined(OS_ANDROID)
91       bool is_first_run = false;
92 #else
93       bool is_first_run = first_run::IsChromeFirstRun();
94 #endif
95       if (!is_first_run && !is_new_profile)
96         install_apps = false;
97       break;
98     }
99 
100     // The old default apps were provided as external extensions and were
101     // installed everytime Chrome was run. Thus, changing the list of default
102     // apps affected all users. Migrate old default apps to new mechanism where
103     // they are installed only once as INTERNAL.
104     // TODO(grv) : remove after Q1-2013.
105     case kProvideLegacyDefaultApps:
106       profile_->GetPrefs()->SetInteger(
107           prefs::kDefaultAppsInstallState,
108           kAlreadyInstalledDefaultApps);
109       break;
110 
111     case kAlreadyInstalledDefaultApps:
112     case kNeverInstallDefaultApps:
113       install_apps = false;
114       break;
115     default:
116       NOTREACHED();
117   }
118 
119   if (install_apps && !IsLocaleSupported())
120     install_apps = false;
121 
122   // Default apps are only installed on profile creation or a new chrome
123   // download.
124   if (state == kUnknown) {
125     if (install_apps) {
126       profile_->GetPrefs()->SetInteger(prefs::kDefaultAppsInstallState,
127                                        kAlreadyInstalledDefaultApps);
128     } else {
129       profile_->GetPrefs()->SetInteger(prefs::kDefaultAppsInstallState,
130                                        kNeverInstallDefaultApps);
131     }
132   }
133 
134   return install_apps;
135 }
136 
Provider(Profile * profile,VisitorInterface * service,extensions::ExternalLoader * loader,extensions::Manifest::Location crx_location,extensions::Manifest::Location download_location,int creation_flags)137 Provider::Provider(Profile* profile,
138                    VisitorInterface* service,
139                    extensions::ExternalLoader* loader,
140                    extensions::Manifest::Location crx_location,
141                    extensions::Manifest::Location download_location,
142                    int creation_flags)
143     : extensions::ExternalProviderImpl(service, loader, profile, crx_location,
144                                        download_location, creation_flags),
145       profile_(profile),
146       is_migration_(false) {
147   DCHECK(profile);
148   set_auto_acknowledge(true);
149 }
150 
VisitRegisteredExtension()151 void Provider::VisitRegisteredExtension() {
152   if (!profile_ || !ShouldInstallInProfile()) {
153     base::DictionaryValue* prefs = new base::DictionaryValue;
154     SetPrefs(prefs);
155     return;
156   }
157 
158   extensions::ExternalProviderImpl::VisitRegisteredExtension();
159 }
160 
SetPrefs(base::DictionaryValue * prefs)161 void Provider::SetPrefs(base::DictionaryValue* prefs) {
162   if (is_migration_) {
163     std::set<std::string> new_default_apps;
164     for (base::DictionaryValue::Iterator i(*prefs); !i.IsAtEnd(); i.Advance()) {
165       if (!IsOldDefaultApp(i.key()))
166         new_default_apps.insert(i.key());
167     }
168     // Filter out the new default apps for migrating users.
169     for (std::set<std::string>::iterator it = new_default_apps.begin();
170          it != new_default_apps.end(); ++it) {
171       prefs->Remove(*it, NULL);
172     }
173   }
174 
175   ExternalProviderImpl::SetPrefs(prefs);
176 }
177 
178 }  // namespace default_apps
179