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