diff options
author | jstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-15 16:03:38 +0000 |
---|---|---|
committer | jstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-15 16:03:38 +0000 |
commit | 18cc5a578b6bc5eca8854cf6da68ff9878975d8b (patch) | |
tree | faba06827e3621ca1f915c7442452ff6b4b94c92 /chrome/browser/extensions | |
parent | b5d20c2e5f1ccf983bc49259b553f3acd9d1c18a (diff) | |
download | chromium_src-18cc5a578b6bc5eca8854cf6da68ff9878975d8b.zip chromium_src-18cc5a578b6bc5eca8854cf6da68ff9878975d8b.tar.gz chromium_src-18cc5a578b6bc5eca8854cf6da68ff9878975d8b.tar.bz2 |
Update the web store promo to be clearer and configurable at run-time.
The promo now behaves like this:
a) Promo is fetched 5 seconds after first launch.
b) Promo is shown whenever no apps are installed, or if only default apps are installed (from old Chrome versions).
c) Clicking "hide this" puts the apps section into menu mode.
d) Switching locales will fetch a new promo in that locale.
e) We no longer install default apps, but they'll expire and be uninstalled the same as before.
BUG=78358
TEST=PromoResourceServiceTest, ExtensionAppsPromo
Review URL: http://codereview.chromium.org/6825052
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81750 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r-- | chrome/browser/extensions/apps_promo.cc | 221 | ||||
-rw-r--r-- | chrome/browser/extensions/apps_promo.h | 113 | ||||
-rw-r--r-- | chrome/browser/extensions/apps_promo_unittest.cc | 183 | ||||
-rw-r--r-- | chrome/browser/extensions/default_apps.cc | 181 | ||||
-rw-r--r-- | chrome/browser/extensions/default_apps.h | 88 | ||||
-rw-r--r-- | chrome/browser/extensions/default_apps_unittest.cc | 236 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_service.cc | 11 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_service.h | 9 |
8 files changed, 523 insertions, 519 deletions
diff --git a/chrome/browser/extensions/apps_promo.cc b/chrome/browser/extensions/apps_promo.cc new file mode 100644 index 0000000..ec0d9dd --- /dev/null +++ b/chrome/browser/extensions/apps_promo.cc @@ -0,0 +1,221 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/apps_promo.h" + +#include "base/command_line.h" +#include "base/metrics/histogram.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/ui/webui/shown_sections_handler.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/pref_names.h" + +const int AppsPromo::kDefaultAppsCounterMax = 10; + +// static +void AppsPromo::RegisterPrefs(PrefService* local_state) { + std::string empty; + local_state->RegisterStringPref(prefs::kNTPWebStorePromoId, empty); + local_state->RegisterStringPref(prefs::kNTPWebStorePromoHeader, empty); + local_state->RegisterStringPref(prefs::kNTPWebStorePromoButton, empty); + local_state->RegisterStringPref(prefs::kNTPWebStorePromoLink, empty); + local_state->RegisterStringPref(prefs::kNTPWebStorePromoExpire, empty); +} + +// static +void AppsPromo::RegisterUserPrefs(PrefService* prefs) { + // Set the default value for the counter to max+1 since we don't install + // default apps for new users. + prefs->RegisterIntegerPref( + prefs::kAppsPromoCounter, kDefaultAppsCounterMax + 1); + prefs->RegisterBooleanPref(prefs::kDefaultAppsInstalled, false); + prefs->RegisterStringPref(prefs::kNTPWebStorePromoLastId, std::string()); +} + +// static +void AppsPromo::ClearPromo() { + PrefService* local_state = g_browser_process->local_state(); + local_state->ClearPref(prefs::kNTPWebStorePromoId); + local_state->ClearPref(prefs::kNTPWebStorePromoHeader); + local_state->ClearPref(prefs::kNTPWebStorePromoButton); + local_state->ClearPref(prefs::kNTPWebStorePromoLink); + local_state->ClearPref(prefs::kNTPWebStorePromoExpire); +} + +// static +std::string AppsPromo::GetPromoButtonText() { + PrefService* local_state = g_browser_process->local_state(); + return local_state->GetString(prefs::kNTPWebStorePromoButton); +} + +// static +std::string AppsPromo::GetPromoId() { + PrefService* local_state = g_browser_process->local_state(); + return local_state->GetString(prefs::kNTPWebStorePromoId); +} + +// static +std::string AppsPromo::GetPromoHeaderText() { + PrefService* local_state = g_browser_process->local_state(); + return local_state->GetString(prefs::kNTPWebStorePromoHeader); +} + +// static +GURL AppsPromo::GetPromoLink() { + PrefService* local_state = g_browser_process->local_state(); + return GURL(local_state->GetString(prefs::kNTPWebStorePromoLink)); +} + +// static +std::string AppsPromo::GetPromoExpireText() { + PrefService* local_state = g_browser_process->local_state(); + return local_state->GetString(prefs::kNTPWebStorePromoExpire); +} + +// static +void AppsPromo::SetPromo(const std::string& id, + const std::string& header_text, + const std::string& button_text, + const GURL& link, + const std::string& expire_text) { + PrefService* local_state = g_browser_process->local_state(); + local_state->SetString(prefs::kNTPWebStorePromoId, id); + local_state->SetString(prefs::kNTPWebStorePromoButton, button_text); + local_state->SetString(prefs::kNTPWebStorePromoHeader, header_text); + local_state->SetString(prefs::kNTPWebStorePromoLink, link.spec()); + local_state->SetString(prefs::kNTPWebStorePromoExpire, expire_text); +} + +// static +bool AppsPromo::IsPromoSupportedForLocale() { + PrefService* local_state = g_browser_process->local_state(); + // PromoResourceService will clear the promo data if the current locale is + // not supported. + return local_state->HasPrefPath(prefs::kNTPWebStorePromoId) && + local_state->HasPrefPath(prefs::kNTPWebStorePromoHeader) && + local_state->HasPrefPath(prefs::kNTPWebStorePromoButton) && + local_state->HasPrefPath(prefs::kNTPWebStorePromoLink) && + local_state->HasPrefPath(prefs::kNTPWebStorePromoExpire); +} + +AppsPromo::AppsPromo(PrefService* prefs) + : prefs_(prefs) { + // Poppit, Entanglement + old_default_app_ids_.insert("mcbkbpnkkkipelfledbfocopglifcfmi"); + old_default_app_ids_.insert("aciahcmjmecflokailenpkdchphgkefd"); +} + +AppsPromo::~AppsPromo() {} + +bool AppsPromo::ShouldShowPromo(const ExtensionIdSet& installed_ids, + bool* just_expired) { + *just_expired = false; + + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kForceAppsPromoVisible)) { + return true; + } + + // Don't show the promo if one wasn't served to this locale. + if (!IsPromoSupportedForLocale()) + return false; + + int promo_counter = GetPromoCounter(); + if (GetDefaultAppsInstalled() && promo_counter <= kDefaultAppsCounterMax) { + // If the default apps were installed from a previous Chrome version, we + // should still show the promo. If we don't have the exact set of default + // apps, this means that the user manually installed or uninstalled one. + // We no longer keep track of the default apps once others have been + // installed, so expire them immediately. + if (old_default_app_ids_ != installed_ids) { + ExpireDefaultApps(); + return false; + } + + if (promo_counter == kDefaultAppsCounterMax) { + *just_expired = true; + + // The default apps have expired due to inaction, so ping PROMO_EXPIRE. + UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, + extension_misc::PROMO_EXPIRE, + extension_misc::PROMO_BUCKET_BOUNDARY); + + ExpireDefaultApps(); + return true; + } else { + SetPromoCounter(++promo_counter); + return true; + } + } else if (installed_ids.empty()) { + return true; + } + + return false; +} + +bool AppsPromo::ShouldShowAppLauncher(const ExtensionIdSet& installed_ids) { + // On Chrome OS the default apps are installed via a separate mechanism that + // is always enabled. Therefore we always show the launcher. +#if defined(OS_CHROME) + return true; +#else + + // Always show the app launcher if an app is installed. + if (!installed_ids.empty()) + return true; + + // Otherwise, only show the app launcher if there's a promo for this locale. + return IsPromoSupportedForLocale(); +#endif +} + +void AppsPromo::ExpireDefaultApps() { + SetPromoCounter(kDefaultAppsCounterMax + 1); +} + +void AppsPromo::MaximizeAppsIfFirstView() { + std::string promo_id = GetPromoId(); + + // Maximize the apps section of the NTP if this is the first time viewing the + // specific promo. + if (GetLastPromoId() != promo_id) { + prefs_->SetString(prefs::kNTPWebStorePromoLastId, promo_id); + ShownSectionsHandler::SetShownSection(prefs_, APPS); + } +} + +void AppsPromo::HidePromo() { + UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, + extension_misc::PROMO_CLOSE, + extension_misc::PROMO_BUCKET_BOUNDARY); + + // Put the apps section into menu mode, and maximize the recent section. + ShownSectionsHandler::SetShownSection(prefs_, MENU_APPS); + ShownSectionsHandler::SetShownSection(prefs_, THUMB); + + ExpireDefaultApps(); +} + +std::string AppsPromo::GetLastPromoId() { + return prefs_->GetString(prefs::kNTPWebStorePromoLastId); +} + +void AppsPromo::SetLastPromoId(const std::string& id) { + prefs_->SetString(prefs::kNTPWebStorePromoLastId, id); +} + +int AppsPromo::GetPromoCounter() const { + return prefs_->GetInteger(prefs::kAppsPromoCounter); +} + +void AppsPromo::SetPromoCounter(int val) { + prefs_->SetInteger(prefs::kAppsPromoCounter, val); + prefs_->ScheduleSavePersistentPrefs(); +} + +bool AppsPromo::GetDefaultAppsInstalled() const { + return prefs_->GetBoolean(prefs::kDefaultAppsInstalled); +} diff --git a/chrome/browser/extensions/apps_promo.h b/chrome/browser/extensions/apps_promo.h new file mode 100644 index 0000000..772df00 --- /dev/null +++ b/chrome/browser/extensions/apps_promo.h @@ -0,0 +1,113 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_APPS_PROMO_H_ +#define CHROME_BROWSER_EXTENSIONS_APPS_PROMO_H_ +#pragma once + +#include <set> +#include <string> + +#include "base/gtest_prod_util.h" +#include "chrome/common/extensions/extension.h" + +class PrefService; + +// This encapsulates business logic for: +// - Whether to show the apps promo in the launcher +// - Whether to expire existing default apps +class AppsPromo { + public: + // Register our preferences. Parts of the promo content are stored in Local + // State since they're independent of the user profile. + static void RegisterPrefs(PrefService* local_state); + static void RegisterUserPrefs(PrefService* prefs); + + // Removes the current promo data. + static void ClearPromo(); + + // Gets the ID of the current promo. + static std::string GetPromoId(); + + // Gets the text for the promo button. + static std::string GetPromoButtonText(); + + // Gets the text for the promo header. + static std::string GetPromoHeaderText(); + + // Gets the promo link. + static GURL GetPromoLink(); + + // Gets the text for the promo "hide this" link. + static std::string GetPromoExpireText(); + + // Called to set the current promo data. + static void SetPromo(const std::string& id, + const std::string& header_text, + const std::string& button_text, + const GURL& link, + const std::string& expire_text); + + explicit AppsPromo(PrefService* prefs); + ~AppsPromo(); + + // Gets the set of old default apps that may have been installed by previous + // versions of Chrome. + const ExtensionIdSet& old_default_apps() const { + return old_default_app_ids_; + } + + // Halts the special treatment of the default apps. The default apps may be + // removed by the caller after calling this method. If the apps remain + // installed, AppsPromo will no longer consider the apps "default". + void ExpireDefaultApps(); + + // Called to hide the promo from the apps section. + void HidePromo(); + + // Maximizes the apps section the first time this is called for a given promo. + void MaximizeAppsIfFirstView(); + + // Returns true if the app launcher should be displayed on the NTP. + bool ShouldShowAppLauncher(const ExtensionIdSet& installed_ids); + + // Returns true if the apps promo should be displayed in the launcher. + bool ShouldShowPromo(const ExtensionIdSet& installed_ids, + bool* just_expired); + + private: + FRIEND_TEST_ALL_PREFIXES(ExtensionAppsPromo, HappyPath); + FRIEND_TEST_ALL_PREFIXES(ExtensionAppsPromo, PromoPrefs); + FRIEND_TEST_ALL_PREFIXES(ExtensionAppsPromo, UpdatePromoFocus); + + // The maximum number of times to show the apps promo. The promo counter + // actually goes up to this number + 1 because we need to differentiate + // between the first time we overflow and subsequent times. + static const int kDefaultAppsCounterMax; + + // Returns true if a promo is available for the current locale. + static bool IsPromoSupportedForLocale(); + + bool GetDefaultAppsInstalled() const; + + // Gets/sets the ID of the last promo shown. + std::string GetLastPromoId(); + void SetLastPromoId(const std::string& id); + + // Gets/sets the number of times the promo has been viewed. Promo views are + // only counted when the default apps are installed. + int GetPromoCounter() const; + void SetPromoCounter(int val); + + // Our permanent state is stored in this PrefService instance. + PrefService* prefs_; + + // The set of default extensions. Initialized to a static list in the + // constructor. + ExtensionIdSet old_default_app_ids_; + + DISALLOW_COPY_AND_ASSIGN(AppsPromo); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_APPS_PROMO_H_ diff --git a/chrome/browser/extensions/apps_promo_unittest.cc b/chrome/browser/extensions/apps_promo_unittest.cc new file mode 100644 index 0000000..3816b78 --- /dev/null +++ b/chrome/browser/extensions/apps_promo_unittest.cc @@ -0,0 +1,183 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/logging.h" +#include "chrome/browser/extensions/apps_promo.h" +#include "chrome/browser/prefs/browser_prefs.h" +#include "chrome/browser/ui/webui/shown_sections_handler.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/testing_browser_process.h" +#include "chrome/test/testing_pref_service.h" +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +const char kPromoId[] = "23123123"; +const char kPromoHeader[] = "Get great apps!"; +const char kPromoButton[] = "Click for apps!"; +const char kPromoLink[] = "http://apps.com"; +const char kPromoExpire[] = "No thanks."; + +} // namespace + +class ExtensionAppsPromo : public testing::Test { + public: + TestingPrefService* local_state() { return &local_state_; } + TestingPrefService* prefs() { return &prefs_; } + AppsPromo* apps_promo() { return apps_promo_; } + + protected: + explicit ExtensionAppsPromo(); + virtual ~ExtensionAppsPromo(); + + // testing::Test + virtual void SetUp(); + virtual void TearDown(); + + private: + TestingPrefService local_state_; + TestingPrefService prefs_; + AppsPromo* apps_promo_; +}; + +ExtensionAppsPromo::ExtensionAppsPromo() : + apps_promo_(new AppsPromo(&prefs_)) { +} + +ExtensionAppsPromo::~ExtensionAppsPromo() { + delete apps_promo_; +} + +void ExtensionAppsPromo::SetUp() { + browser::RegisterLocalState(&local_state_); + browser::RegisterUserPrefs(&prefs_); + + TestingBrowserProcess* testing_browser_process = + static_cast<TestingBrowserProcess*>(g_browser_process); + testing_browser_process->SetPrefService(&local_state_); +} + +void ExtensionAppsPromo::TearDown() { + TestingBrowserProcess* testing_browser_process = + static_cast<TestingBrowserProcess*>(g_browser_process); + testing_browser_process->SetPrefService(NULL); +} + +// TODO(dpolukhin): On Chrome OS all apps are installed via external extensions, +// and the web store promo is never shown. +#if !defined(OS_CHROMEOS) +TEST_F(ExtensionAppsPromo, HappyPath) { + const ExtensionIdSet& default_app_ids = apps_promo()->old_default_apps(); + + EXPECT_GT(default_app_ids.size(), 0u); + + // The promo counter should default to the max, since we only use the counter + // if they were installed from older versions of Chrome. + EXPECT_EQ(AppsPromo::kDefaultAppsCounterMax + 1, + apps_promo()->GetPromoCounter()); + + // The app launcher and promo should not be shown if there are no extensions + // installed and no promo is set. + ExtensionIdSet installed_ids; + bool promo_just_expired = false; + EXPECT_FALSE(AppsPromo::IsPromoSupportedForLocale()); + EXPECT_FALSE(apps_promo()->ShouldShowAppLauncher(installed_ids)); + EXPECT_FALSE(apps_promo()->ShouldShowPromo(installed_ids, + &promo_just_expired)); + EXPECT_FALSE(promo_just_expired); + + // Once the promo is set, we show both the promo and app launcher. + AppsPromo::SetPromo( + kPromoId, kPromoHeader, kPromoButton, GURL(kPromoLink), kPromoExpire); + + EXPECT_TRUE(AppsPromo::IsPromoSupportedForLocale()); + EXPECT_TRUE(apps_promo()->ShouldShowAppLauncher(installed_ids)); + EXPECT_TRUE(apps_promo()->ShouldShowPromo(installed_ids, + &promo_just_expired)); + EXPECT_FALSE(promo_just_expired); + + + // Now install an app and the promo should not be shown. + installed_ids.insert(*(default_app_ids.begin())); + EXPECT_TRUE(AppsPromo::IsPromoSupportedForLocale()); + EXPECT_TRUE(apps_promo()->ShouldShowAppLauncher(installed_ids)); + EXPECT_FALSE(apps_promo()->ShouldShowPromo(installed_ids, + &promo_just_expired)); + EXPECT_FALSE(promo_just_expired); + + // Even if the user installs the exact set of default apps, we still don't + // show the promo. + installed_ids = default_app_ids; + EXPECT_TRUE(AppsPromo::IsPromoSupportedForLocale()); + EXPECT_TRUE(apps_promo()->ShouldShowAppLauncher(installed_ids)); + EXPECT_FALSE(apps_promo()->ShouldShowPromo(installed_ids, + &promo_just_expired)); + EXPECT_FALSE(promo_just_expired); + + // If the user then uninstalls the apps, the app launcher should remain + // and the promo should return. + installed_ids.clear(); + EXPECT_TRUE(AppsPromo::IsPromoSupportedForLocale()); + EXPECT_TRUE(apps_promo()->ShouldShowAppLauncher(installed_ids)); + EXPECT_TRUE(apps_promo()->ShouldShowPromo(installed_ids, + &promo_just_expired)); + EXPECT_FALSE(promo_just_expired); +} + +// Tests get and set of promo content. +TEST_F(ExtensionAppsPromo, PromoPrefs) { + // Store a promo.... + AppsPromo::SetPromo( + kPromoId, kPromoHeader, kPromoButton, GURL(kPromoLink), kPromoExpire); + + // ... then make sure AppsPromo can access it. + EXPECT_EQ(kPromoId, AppsPromo::GetPromoId()); + EXPECT_EQ(kPromoHeader, AppsPromo::GetPromoHeaderText()); + EXPECT_EQ(kPromoButton, AppsPromo::GetPromoButtonText()); + EXPECT_EQ(GURL(kPromoLink), AppsPromo::GetPromoLink()); + EXPECT_EQ(kPromoExpire, AppsPromo::GetPromoExpireText()); + EXPECT_TRUE(AppsPromo::IsPromoSupportedForLocale()); + + AppsPromo::ClearPromo(); + EXPECT_EQ("", AppsPromo::GetPromoId()); + EXPECT_EQ("", AppsPromo::GetPromoHeaderText()); + EXPECT_EQ("", AppsPromo::GetPromoButtonText()); + EXPECT_EQ(GURL(""), AppsPromo::GetPromoLink()); + EXPECT_EQ("", AppsPromo::GetPromoExpireText()); + EXPECT_FALSE(AppsPromo::IsPromoSupportedForLocale()); +} + +// Tests that the apps section is maxmized when showing a promo for the first +// time. +TEST_F(ExtensionAppsPromo, UpdatePromoFocus) { + ExtensionIdSet installed_ids; + + bool promo_just_expired = false; + EXPECT_FALSE(apps_promo()->ShouldShowPromo(installed_ids, + &promo_just_expired)); + EXPECT_FALSE(promo_just_expired); + + // Set the promo content. + AppsPromo::SetPromo( + kPromoId, kPromoHeader, kPromoButton, GURL(kPromoLink), kPromoExpire); + + // After asking if we should show the promo, the + EXPECT_TRUE(AppsPromo::IsPromoSupportedForLocale()); + EXPECT_TRUE(apps_promo()->ShouldShowPromo(installed_ids, + &promo_just_expired)); + apps_promo()->MaximizeAppsIfFirstView(); + + EXPECT_TRUE( + (ShownSectionsHandler::GetShownSections(prefs()) & APPS) != 0); + EXPECT_FALSE( + (ShownSectionsHandler::GetShownSections(prefs()) & THUMB) != 0); + + apps_promo()->HidePromo(); + + EXPECT_TRUE((ShownSectionsHandler::GetShownSections(prefs()) & + (MENU_APPS | THUMB)) != 0); +} +#endif // OS_CHROMEOS diff --git a/chrome/browser/extensions/default_apps.cc b/chrome/browser/extensions/default_apps.cc deleted file mode 100644 index bf8aa9a..0000000 --- a/chrome/browser/extensions/default_apps.cc +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <algorithm> - -#include "chrome/browser/extensions/default_apps.h" - -#include "base/command_line.h" -#include "base/metrics/histogram.h" -#include "chrome/browser/prefs/pref_service.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/pref_names.h" - -const int DefaultApps::kAppsPromoCounterMax = 10; - -// static -void DefaultApps::RegisterUserPrefs(PrefService* prefs) { - prefs->RegisterBooleanPref(prefs::kDefaultAppsInstalled, false); - prefs->RegisterIntegerPref(prefs::kAppsPromoCounter, 0); -} - -DefaultApps::DefaultApps(PrefService* prefs, - const std::string& application_locale) - : prefs_(prefs), application_locale_(application_locale) { - // Poppit, Entanglement - ids_.insert("mcbkbpnkkkipelfledbfocopglifcfmi"); - ids_.insert("aciahcmjmecflokailenpkdchphgkefd"); -} - -DefaultApps::~DefaultApps() {} - -const ExtensionIdSet& DefaultApps::default_apps() const { - return ids_; -} - -bool DefaultApps::DefaultAppSupported() { - // On Chrome OS the default apps are installed via a different mechanism. -#if defined(OS_CHROMEOS) - return false; -#else - return DefaultAppsSupportedForLanguage(); -#endif -} - -bool DefaultApps::DefaultAppsSupportedForLanguage() { - return application_locale_ == "en-US"; -} - -bool DefaultApps::ShouldInstallDefaultApps( - const ExtensionIdSet& installed_ids) { - if (!DefaultAppSupported()) - return false; - - if (GetDefaultAppsInstalled()) - return false; - - // If there are any non-default apps installed, we should never try to install - // the default apps again, even if the non-default apps are later removed. - if (NonDefaultAppIsInstalled(installed_ids)) { - SetDefaultAppsInstalled(true); - return false; - } - - return true; -} - -bool DefaultApps::ShouldShowAppLauncher(const ExtensionIdSet& installed_ids) { - // On Chrome OS the default apps are installed via a separate mechanism that - // is always enabled. Therefore we always show the launcher. -#if defined(OS_CHROME) - return true; -#else - // The app store only supports en-us at the moment, so we don't show the apps - // section by default for users in other locales. But we do show it if a user - // from a non-supported locale somehow installs an app (eg by navigating - // directly to the store). - if (!DefaultAppsSupportedForLanguage()) - return !installed_ids.empty(); - - // For supported locales, we need to wait for all the default apps to be - // installed before showing the apps section. We also show it if any - // non-default app is installed (eg because the user installed the app in a - // previous version of Chrome). - if (GetDefaultAppsInstalled() || NonDefaultAppIsInstalled(installed_ids)) - return true; - else - return false; -#endif -} - -bool DefaultApps::ShouldShowPromo(const ExtensionIdSet& installed_ids, - bool* just_expired) { - *just_expired = false; - - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kForceAppsPromoVisible)) { - return true; - } - - if (!DefaultAppSupported()) - return false; - - if (!GetDefaultAppsInstalled()) - return false; - - int promo_counter = GetPromoCounter(); - if (promo_counter <= kAppsPromoCounterMax) { - // If we have the exact set of default apps, show the promo. If we don't - // have the exact set of default apps, this means that the user manually - // installed or uninstalled one. The promo doesn't make sense if it shows - // apps the user manually installed, so expire it immediately in that - // situation. - if (ids_ != installed_ids) { - SetPromoHidden(); - return false; - } - - if (promo_counter == kAppsPromoCounterMax) { - *just_expired = true; - UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, - extension_misc::PROMO_EXPIRE, - extension_misc::PROMO_BUCKET_BOUNDARY); - SetPromoCounter(++promo_counter); - return false; - } else { - UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, - extension_misc::PROMO_SEEN, - extension_misc::PROMO_BUCKET_BOUNDARY); - SetPromoCounter(++promo_counter); - return true; - } - } - - return false; -} - -void DefaultApps::DidInstallApp(const ExtensionIdSet& installed_ids) { - // If all the default apps have been installed, stop trying to install them. - // Note that we use std::includes here instead of == because apps might have - // been manually installed while the the default apps were installing and we - // wouldn't want to keep trying to install them in that case. - if (!GetDefaultAppsInstalled() && - std::includes(installed_ids.begin(), installed_ids.end(), - ids_.begin(), ids_.end())) { - SetDefaultAppsInstalled(true); - } -} - -bool DefaultApps::NonDefaultAppIsInstalled( - const ExtensionIdSet& installed_ids) const { - for (ExtensionIdSet::const_iterator iter = installed_ids.begin(); - iter != installed_ids.end(); ++iter) { - if (ids_.find(*iter) == ids_.end()) - return true; - } - - return false; -} - -void DefaultApps::SetPromoHidden() { - SetPromoCounter(kAppsPromoCounterMax + 1); -} - -int DefaultApps::GetPromoCounter() const { - return prefs_->GetInteger(prefs::kAppsPromoCounter); -} - -void DefaultApps::SetPromoCounter(int val) { - prefs_->SetInteger(prefs::kAppsPromoCounter, val); - prefs_->ScheduleSavePersistentPrefs(); -} - -bool DefaultApps::GetDefaultAppsInstalled() const { - return prefs_->GetBoolean(prefs::kDefaultAppsInstalled); -} - -void DefaultApps::SetDefaultAppsInstalled(bool val) { - prefs_->SetBoolean(prefs::kDefaultAppsInstalled, val); - prefs_->ScheduleSavePersistentPrefs(); -} diff --git a/chrome/browser/extensions/default_apps.h b/chrome/browser/extensions/default_apps.h deleted file mode 100644 index 2ff8801..0000000 --- a/chrome/browser/extensions/default_apps.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_EXTENSIONS_DEFAULT_APPS_H_ -#define CHROME_BROWSER_EXTENSIONS_DEFAULT_APPS_H_ -#pragma once - -#include <set> -#include <string> -#include "chrome/common/extensions/extension.h" -#include "base/gtest_prod_util.h" - -class PrefService; - -// Encapsulates business logic for: -// - Whether to install default apps on Chrome startup -// - Whether to show the app launcher -// - Whether to show the apps promo in the launcher -class DefaultApps { - public: - // The maximum number of times to show the apps promo. The promo counter - // actually goes up to this number + 1 because we need to differentiate - // between the first time we overflow and subsequent times. - static const int kAppsPromoCounterMax; - - // Register our preferences. - static void RegisterUserPrefs(PrefService* prefs); - - explicit DefaultApps(PrefService* prefs, - const std::string& application_locale); - ~DefaultApps(); - - // Gets the set of default apps. - const ExtensionIdSet& default_apps() const; - - // Returns true if the default apps should be installed. - bool ShouldInstallDefaultApps(const ExtensionIdSet& installed_ids); - - // Returns true if the app launcher in the NTP should be shown. - bool ShouldShowAppLauncher(const ExtensionIdSet& installed_ids); - - // Returns true if the apps promo should be displayed in the launcher. - // - // NOTE: If the default apps have been installed, but |installed_ids| is - // different than GetDefaultApps(), this will permanently expire the promo. - bool ShouldShowPromo(const ExtensionIdSet& installed_ids, bool* just_expired); - - // Should be called after each app is installed. Once installed_ids contains - // all the default apps, GetAppsToInstall() will start returning NULL. - void DidInstallApp(const ExtensionIdSet& installed_ids); - - // Force the promo to be hidden. - void SetPromoHidden(); - - private: - FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, HappyPath); - FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, UnsupportedLocale); - FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, HidePromo); - FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, InstallingAnAppHidesPromo); - FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, - ManualAppInstalledWhileInstallingDefaultApps); - - bool DefaultAppSupported(); - bool DefaultAppsSupportedForLanguage(); - - bool NonDefaultAppIsInstalled(const ExtensionIdSet& installed_ids) const; - - bool GetDefaultAppsInstalled() const; - void SetDefaultAppsInstalled(bool val); - - int GetPromoCounter() const; - void SetPromoCounter(int val); - - // Our permanent state is stored in this PrefService instance. - PrefService* prefs_; - - // The locale the browser is currently in. - std::string application_locale_; - - // The set of default extensions. Initialized to a static list in the - // constructor. - ExtensionIdSet ids_; - - DISALLOW_COPY_AND_ASSIGN(DefaultApps); -}; - -#endif // CHROME_BROWSER_EXTENSIONS_DEFAULT_APPS_H_ diff --git a/chrome/browser/extensions/default_apps_unittest.cc b/chrome/browser/extensions/default_apps_unittest.cc deleted file mode 100644 index 316568d..0000000 --- a/chrome/browser/extensions/default_apps_unittest.cc +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/logging.h" -#include "chrome/browser/extensions/default_apps.h" -#include "chrome/common/extensions/extension.h" -#include "chrome/test/testing_pref_service.h" -#include "testing/gtest/include/gtest/gtest.h" - -// TODO(dpolukhin): On Chrome OS all apps are installed via external extensions, -// and the web store promo is never shown. -#if !defined(OS_CHROMEOS) -TEST(ExtensionDefaultApps, HappyPath) { - TestingPrefService pref_service; - DefaultApps::RegisterUserPrefs(&pref_service); - DefaultApps default_apps(&pref_service, "en-US"); - - const ExtensionIdSet& default_app_ids = default_apps.default_apps(); - ASSERT_GT(default_app_ids.size(), 0u); - EXPECT_FALSE(default_apps.GetDefaultAppsInstalled()); - EXPECT_EQ(0, default_apps.GetPromoCounter()); - - // If no apps are installed, the default apps should be installed. - ExtensionIdSet installed_app_ids; - EXPECT_TRUE(default_apps.ShouldInstallDefaultApps(installed_app_ids)); - - // The launcher should not be shown until the default apps have been - // installed. - EXPECT_FALSE(default_apps.ShouldShowAppLauncher(installed_app_ids)); - - // The promo should not be shown until the default apps have been installed. - bool promo_just_expired = false; - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - - // Simulate installing the apps one by one and notifying default_apps after - // each intallation. Nothing should change until we have installed all the - // default apps. - for (size_t i = 0; i < default_app_ids.size() - 1; ++i) { - ExtensionIdSet::const_iterator iter = default_app_ids.begin(); - for (size_t j = 0; j <= i; ++j) - ++iter; - installed_app_ids.insert(*iter); - default_apps.DidInstallApp(installed_app_ids); - EXPECT_FALSE(default_apps.GetDefaultAppsInstalled()); - EXPECT_TRUE(default_apps.ShouldInstallDefaultApps(installed_app_ids)); - EXPECT_FALSE(default_apps.ShouldShowAppLauncher(installed_app_ids)); - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - } - - // Simulate all the default apps being installed. Now we should stop getting - // default apps to install. - installed_app_ids = default_app_ids; - default_apps.DidInstallApp(installed_app_ids); - EXPECT_TRUE(default_apps.GetDefaultAppsInstalled()); - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_app_ids)); - - // And the promo and launcher should become available. - EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_app_ids)); - EXPECT_TRUE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - - // The promo should be available up to the max allowed times, then stop. - // We start counting at 1 because of the call to ShouldShowPromo() above. - for (int i = 1; i < DefaultApps::kAppsPromoCounterMax; ++i) { - EXPECT_TRUE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - EXPECT_EQ(i + 1, default_apps.GetPromoCounter()); - } - - // The first time, should_show_promo should flip to true, then back to false. - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_TRUE(promo_just_expired); - EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1, - default_apps.GetPromoCounter()); - - // Even if all the apps are subsequently removed, the apps section should - // remain. - installed_app_ids.clear(); - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_app_ids)); - EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_app_ids)); - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1, - default_apps.GetPromoCounter()); -} - -TEST(ExtensionDefaultApps, UnsupportedLocale) { - TestingPrefService pref_service; - DefaultApps::RegisterUserPrefs(&pref_service); - DefaultApps default_apps(&pref_service, "fr"); - - const ExtensionIdSet& default_app_ids = default_apps.default_apps(); - EXPECT_GT(default_app_ids.size(), 0u); - - // Since the store only supports en-US at the moment, we don't install default - // apps or promote the store. - ExtensionIdSet installed_ids; - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids)); - EXPECT_FALSE(default_apps.ShouldShowAppLauncher(installed_ids)); - - bool promo_just_expired = false; - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - - // If the user installs an app manually, then we show the apps section, but - // no promotion or default apps. - installed_ids.insert(*(default_app_ids.begin())); - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids)); - EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_ids)); - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - - // Even if the user installs the exact set of default apps, we don't show the - // promo. - installed_ids = default_app_ids; - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids)); - EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_ids)); - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - - // If the user uninstalls the apps again, we go back to not showing the - // apps section. - installed_ids.clear(); - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids)); - EXPECT_FALSE(default_apps.ShouldShowAppLauncher(installed_ids)); - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); -} - -TEST(ExtensionDefaultApps, HidePromo) { - TestingPrefService pref_service; - DefaultApps::RegisterUserPrefs(&pref_service); - DefaultApps default_apps(&pref_service, "en-US"); - - const ExtensionIdSet& default_app_ids = default_apps.default_apps(); - default_apps.DidInstallApp(default_app_ids); - - bool promo_just_expired = false; - EXPECT_TRUE(default_apps.ShouldShowPromo(default_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - EXPECT_EQ(1, default_apps.GetPromoCounter()); - - default_apps.SetPromoHidden(); - EXPECT_FALSE(default_apps.ShouldShowPromo(default_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1, - default_apps.GetPromoCounter()); -} - -TEST(ExtensionDefaultApps, InstallingAnAppHidesPromo) { - TestingPrefService pref_service; - DefaultApps::RegisterUserPrefs(&pref_service); - DefaultApps default_apps(&pref_service, "en-US"); - - const ExtensionIdSet& default_app_ids = default_apps.default_apps(); - ExtensionIdSet installed_app_ids = default_app_ids; - default_apps.DidInstallApp(installed_app_ids); - - bool promo_just_expired = false; - EXPECT_TRUE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - EXPECT_EQ(1, default_apps.GetPromoCounter()); - - // Now simulate a new extension being installed. This should cause the promo - // to be hidden. - installed_app_ids.insert("foo"); - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1, - default_apps.GetPromoCounter()); -} - -TEST(ExtensionDefaultApps, ManualAppInstalledWhileInstallingDefaultApps) { - // It is possible to have apps manually installed while the default apps are - // being installed. The network or server might be down, causing the default - // app installation to fail. The updater might take awhile to get around to - // updating, giving the user a chance to manually intall. - // - // In these cases, we should keep trying to install default apps until we have - // them all, and then stop, even if at that point, we have more apps than just - // the default ones. - TestingPrefService pref_service; - DefaultApps::RegisterUserPrefs(&pref_service); - DefaultApps default_apps(&pref_service, "en-US"); - - // Simulate an app getting installed before the complete set of default apps. - // This should stop the default apps from trying to be installed. The launcher - // should also immediately show up. - ExtensionIdSet installed_ids; - installed_ids.insert("foo"); - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids)); - EXPECT_TRUE(default_apps.GetDefaultAppsInstalled()); - EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_ids)); - - // The promo shouldn't turn on though, because it would look weird with the - // user's extra, manually installed extensions. - bool promo_just_expired = false; - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1, - default_apps.GetPromoCounter()); - - // Going back to a subset of the default apps shouldn't allow the default app - // install to continue. - installed_ids.clear(); - EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids)); - EXPECT_TRUE(default_apps.GetDefaultAppsInstalled()); - EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_ids)); - EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids, - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); - - // Going to the exact set of default apps shouldn't show the promo. - EXPECT_FALSE(default_apps.ShouldShowPromo(default_apps.default_apps(), - &promo_just_expired)); - EXPECT_FALSE(promo_just_expired); -} -#endif // OS_CHROMEOS diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 78c3ff0..8bf7764 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc @@ -24,7 +24,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/debugger/devtools_manager.h" #include "chrome/browser/extensions/crx_installer.h" -#include "chrome/browser/extensions/default_apps.h" +#include "chrome/browser/extensions/apps_promo.h" #include "chrome/browser/extensions/extension_accessibility_api.h" #include "chrome/browser/extensions/extension_bookmarks_module.h" #include "chrome/browser/extensions/extension_browser_event_router.h" @@ -410,8 +410,7 @@ ExtensionService::ExtensionService(Profile* profile, show_extensions_prompts_(true), ready_(false), ALLOW_THIS_IN_INITIALIZER_LIST(toolbar_model_(this)), - default_apps_(profile->GetPrefs(), - g_browser_process->GetApplicationLocale()), + apps_promo_(profile->GetPrefs()), event_routers_initialized_(false) { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -1671,12 +1670,6 @@ void ExtensionService::OnExtensionInstalled(const Extension* extension) { Details<const Extension>(extension)); } - if (extension->is_app()) { - ExtensionIdSet installed_ids = GetAppIds(); - installed_ids.insert(id); - default_apps_.DidInstallApp(installed_ids); - } - // Transfer ownership of |extension| to AddExtension. AddExtension(scoped_extension); } diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h index ee486f7..6c6ad49 100644 --- a/chrome/browser/extensions/extension_service.h +++ b/chrome/browser/extensions/extension_service.h @@ -19,7 +19,7 @@ #include "base/task.h" #include "base/time.h" #include "base/tuple.h" -#include "chrome/browser/extensions/default_apps.h" +#include "chrome/browser/extensions/apps_promo.h" #include "chrome/browser/extensions/extension_icon_manager.h" #include "chrome/browser/extensions/extension_menu_manager.h" #include "chrome/browser/extensions/extension_prefs.h" @@ -163,7 +163,7 @@ class ExtensionService const FilePath& install_directory() const { return install_directory_; } - DefaultApps* default_apps() { return &default_apps_; } + AppsPromo* apps_promo() { return &apps_promo_; } // Whether this extension can run in an incognito window. virtual bool IsIncognitoEnabled(const std::string& extension_id) const; @@ -555,9 +555,8 @@ class ExtensionService typedef std::vector<ComponentExtensionInfo> RegisteredComponentExtensions; RegisteredComponentExtensions component_extension_manifests_; - // Manages the installation of default apps and the promotion of them in the - // app launcher. - DefaultApps default_apps_; + // Manages the promotion of the web store. + AppsPromo apps_promo_; // Flag to make sure event routers are only initialized once. bool event_routers_initialized_; |