Home | History | Annotate | Download | only in extensions
      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
     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 
     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 
     54 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
     55   registry->RegisterIntegerPref(
     56       prefs::kDefaultAppsInstallState,
     57       kUnknown,
     58       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
     59 }
     60 
     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 
    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 
    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 
    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