diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-09 16:35:18 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-09 16:35:18 +0000 |
commit | ec5b50d6d76fc975f0e7b5e037f28974e13cabb5 (patch) | |
tree | 9643090a68cd8ff404aae0c79330822a855d5270 | |
parent | e161c191f63808fb0503af5ab05ae5ac176ecfe9 (diff) | |
download | chromium_src-ec5b50d6d76fc975f0e7b5e037f28974e13cabb5.zip chromium_src-ec5b50d6d76fc975f0e7b5e037f28974e13cabb5.tar.gz chromium_src-ec5b50d6d76fc975f0e7b5e037f28974e13cabb5.tar.bz2 |
Implement new strategy for default apps. Instead of using
the component extension system, simply install them as
normal apps the first time Chrome runs. Remove the old
style default apps.
This also removes support for --disable-apps, which doesn't
seem necessary since we already have --disable-extensions.
BUG=53972
TEST=Uninstall any installed apps. Remove the
"default_apps_installed" and "app_promo_counter" keys from
Preferences if they are present.
Start Chrome with the --enable-default-apps flag, navigate
to chrome://extensions/, and click "update now" in the
developer tools. This is to make the updater grab the
apps from the store quicker, so that you don't have to wait
while testing. Normally Chrome would do this by itself
after 5-40 mins.
Go to NTP. You should see gmail, calendar, and docs default
apps show up along with the promo (the text that says "New!
A world of ...").
Refresh the NTP 10 times. The promo should go away on the
10th time.
There are other details. To test each of these, remove all
installed apps and remove the keys from the preferences to
reset the state.
* If you close Chrome before getting the default apps. They
should still show up the next time Chrome is started (after
clicking 'Update now')
* Clicking "hide this message" should hide the promo and it
shouldn't come back on refresh.
* Installing or uninstalling any app should hide the promo,
and it shouldn't come back.
* If the keys from the preferences are removed, but apps
are left installed, the default apps should not be
installed when clicking 'update now'.
* The default apps should only be installed in locale
en-US.
Review URL: http://codereview.chromium.org/3522015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62084 0039d316-1c4b-4281-b951-d872f2087c98
48 files changed, 524 insertions, 275 deletions
diff --git a/chrome/browser/browser_init.cc b/chrome/browser/browser_init.cc index 115eb41..621bb4e 100644 --- a/chrome/browser/browser_init.cc +++ b/chrome/browser/browser_init.cc @@ -587,8 +587,7 @@ bool BrowserInit::LaunchWithProfile::IsAppLaunch(std::string* app_url, *app_url = command_line_.GetSwitchValueASCII(switches::kApp); return true; } - if (!command_line_.HasSwitch(switches::kDisableApps) && - command_line_.HasSwitch(switches::kAppId)) { + if (command_line_.HasSwitch(switches::kAppId)) { if (app_id) *app_id = command_line_.GetSwitchValueASCII(switches::kAppId); return true; diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index ed89389..f981d4f 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd @@ -24,9 +24,7 @@ without changes to the corresponding grd file. eter --> <include name="IDR_ABOUT_SYNC_HTML" file="sync\resources\about_sync.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_ABOUT_VERSION_HTML" file="resources\about_version.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_BOOKMARKS_MANIFEST" file="resources\bookmark_manager\manifest.json" type="BINDATA" /> - <include name="IDR_CALENDAR_APP_MANIFEST" file="resources\calendar_app\manifest.json" type="BINDATA" /> <include name="IDR_CREDITS_HTML" file="resources\about_credits.html" flattenhtml="true" type="BINDATA" /> - <include name="IDR_DOCS_APP_MANIFEST" file="resources\docs_app\manifest.json" type="BINDATA" /> <include name="IDR_DOWNLOADS_HTML" file="resources\downloads.html" flattenhtml="true" type="BINDATA" /> <if expr="os == 'darwin'"> <include name="IDR_EXTENSIONS_INFOBAR_CSS" file="resources\extensions_infobar_mac.css" flattenhtml="true" type="BINDATA" /> @@ -36,7 +34,6 @@ without changes to the corresponding grd file. eter --> </if> <include name="IDR_EXTENSIONS_UI_HTML" file="resources\extensions_ui.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_GAIA_LOGIN_HTML" file="sync\resources\gaia_login.html" flattenhtml="true" type="BINDATA" /> - <include name="IDR_GMAIL_APP_MANIFEST" file="resources\gmail_app\manifest.json" type="BINDATA" /> <include name="IDR_HISTORY_HTML" file="resources\history.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_HISTORY2_HTML" file="resources\history2.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_INCOGNITO_TAB_HTML" file="resources\incognito_tab.html" flattenhtml="true" type="BINDATA" /> diff --git a/chrome/browser/dom_ui/app_launcher_handler.cc b/chrome/browser/dom_ui/app_launcher_handler.cc index 9c867d1..e834754 100644 --- a/chrome/browser/dom_ui/app_launcher_handler.cc +++ b/chrome/browser/dom_ui/app_launcher_handler.cc @@ -12,9 +12,11 @@ #include "chrome/browser/app_launched_animation.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" +#include "chrome/browser/extensions/default_apps.h" #include "chrome/browser/extensions/extension_prefs.h" #include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/platform_util.h" +#include "chrome/browser/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" @@ -73,6 +75,8 @@ void AppLauncherHandler::RegisterMessages() { NewCallback(this, &AppLauncherHandler::HandleSetLaunchType)); dom_ui_->RegisterMessageCallback("uninstallApp", NewCallback(this, &AppLauncherHandler::HandleUninstallApp)); + dom_ui_->RegisterMessageCallback("hideAppsPromo", + NewCallback(this, &AppLauncherHandler::HandleHideAppsPromo)); } void AppLauncherHandler::Observe(NotificationType type, @@ -133,6 +137,14 @@ void AppLauncherHandler::FillAppDictionary(DictionaryValue* dictionary) { } } dictionary->Set("apps", list); + + DefaultApps* default_apps = extensions_service_->default_apps(); + if (default_apps->ShouldShowPromo(extensions_service_->GetAppIds())) { + dictionary->SetBoolean("showPromo", true); + default_apps->DidShowPromo(); + } else { + dictionary->SetBoolean("showPromo", false); + } } void AppLauncherHandler::HandleGetApps(const ListValue* args) { @@ -245,6 +257,10 @@ void AppLauncherHandler::HandleUninstallApp(const ListValue* args) { GetExtensionInstallUI()->ConfirmUninstall(this, extension); } +void AppLauncherHandler::HandleHideAppsPromo(const ListValue* args) { + extensions_service_->default_apps()->SetPromoHidden(); +} + ExtensionInstallUI* AppLauncherHandler::GetExtensionInstallUI() { if (!install_ui_.get()) install_ui_.reset(new ExtensionInstallUI(dom_ui_->GetProfile())); diff --git a/chrome/browser/dom_ui/app_launcher_handler.h b/chrome/browser/dom_ui/app_launcher_handler.h index 23c1753..c3ca622 100644 --- a/chrome/browser/dom_ui/app_launcher_handler.h +++ b/chrome/browser/dom_ui/app_launcher_handler.h @@ -61,6 +61,9 @@ class AppLauncherHandler // Callback for the "uninstallApp" message. void HandleUninstallApp(const ListValue* args); + // Callback for the "hideAppPromo" message. + void HandleHideAppsPromo(const ListValue* args); + private: // ExtensionInstallUI::Delegate implementation, used for receiving // notification about uninstall confirmation dialog selections. diff --git a/chrome/browser/dom_ui/new_tab_ui.cc b/chrome/browser/dom_ui/new_tab_ui.cc index 047efdc..6d9ac9d 100644 --- a/chrome/browser/dom_ui/new_tab_ui.cc +++ b/chrome/browser/dom_ui/new_tab_ui.cc @@ -441,13 +441,11 @@ NewTabUI::NewTabUI(TabContents* contents) AddMessageHandler((new MetricsHandler())->Attach(this)); if (GetProfile()->IsSyncAccessible()) AddMessageHandler((new NewTabPageSyncHandler())->Attach(this)); - if (Extension::AppsAreEnabled()) { - ExtensionsService* service = GetProfile()->GetExtensionsService(); - // We might not have an ExtensionsService (on ChromeOS when not logged in - // for example). - if (service) - AddMessageHandler((new AppLauncherHandler(service))->Attach(this)); - } + ExtensionsService* service = GetProfile()->GetExtensionsService(); + // We might not have an ExtensionsService (on ChromeOS when not logged in + // for example). + if (service) + AddMessageHandler((new AppLauncherHandler(service))->Attach(this)); AddMessageHandler((new NewTabPageSetHomePageHandler())->Attach(this)); } diff --git a/chrome/browser/dom_ui/ntp_resource_cache.cc b/chrome/browser/dom_ui/ntp_resource_cache.cc index 9e05662..571a71c 100644 --- a/chrome/browser/dom_ui/ntp_resource_cache.cc +++ b/chrome/browser/dom_ui/ntp_resource_cache.cc @@ -11,7 +11,6 @@ #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "app/theme_provider.h" -#include "base/command_line.h" #include "base/file_util.h" #include "base/ref_counted_memory.h" #include "base/string16.h" @@ -304,10 +303,6 @@ void NTPResourceCache::CreateNewTabHTML() { localized_strings.SetString("appspromotext2", l10n_util::GetStringUTF16(IDS_APPS_PROMO_TEXT_2)); - localized_strings.SetString("appspromovisible", - CommandLine::ForCurrentProcess()->HasSwitch( - switches::kForceAppsPromoVisible) ? "true" : "false"); - // Don't initiate the sync related message passing with the page if the sync // code is not present. if (profile_->GetProfileSyncService()) diff --git a/chrome/browser/extensions/default_apps.cc b/chrome/browser/extensions/default_apps.cc new file mode 100644 index 0000000..5614dfb --- /dev/null +++ b/chrome/browser/extensions/default_apps.cc @@ -0,0 +1,105 @@ +// 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 "chrome/browser/extensions/default_apps.h" + +#include "base/command_line.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) + : prefs_(prefs) { + // gmail, calendar, docs + ids_.insert("pjkljhegncpnkpknbcohdijeoejaedia"); + ids_.insert("ejjicmeblgpmajnghnpcppodonldlgfn"); + ids_.insert("apdfllckaahabafndbhieahigkjlhalf"); +} + +const ExtensionIdSet* DefaultApps::GetAppsToInstall() const { + if (GetDefaultAppsInstalled()) + return NULL; + else + return &ids_; +} + +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::ShouldShowPromo(const ExtensionIdSet& installed_ids) { + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kForceAppsPromoVisible)) { + return true; + } + + if (GetDefaultAppsInstalled() && GetPromoCounter() < 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 one. The promo doesn't make sense if it shows apps the user + // manually installed, so expire it immediately in that situation. + if (installed_ids == ids_) + return true; + else + SetPromoHidden(); + } + + return false; +} + +void DefaultApps::DidShowPromo() { + if (!GetDefaultAppsInstalled()) { + NOTREACHED() << "Should not show promo until default apps are installed."; + return; + } + + int promo_counter = GetPromoCounter(); + if (promo_counter == kAppsPromoCounterMax) { + NOTREACHED() << "Promo has already been shown the maximum number of times."; + return; + } + + if (promo_counter < kAppsPromoCounterMax) + SetPromoCounter(++promo_counter); + else + SetPromoHidden(); +} + +void DefaultApps::SetPromoHidden() { + SetPromoCounter(kAppsPromoCounterMax); +} + +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 new file mode 100644 index 0000000..f61539f --- /dev/null +++ b/chrome/browser/extensions/default_apps.h @@ -0,0 +1,83 @@ +// 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; + +// Manages the installation of the set of default apps into Chrome, and the +// promotion of those apps in the launcher. +// +// It implements the following rules: +// +// - Only install default apps once per-profile. +// - Don't install default apps if any apps are already installed. +// - Do not start showing the promo until all default apps have been installed. +// - Do not show the promo if it has been hidden by the user. +// - Do not show promo after one app has been manually installed or uninstalled. +// - Do not show promo if the set of installed apps is different than the set of +// default apps. +// - Only show promo a certain amount of times. +// +// The promo can also be forced on with --force-apps-promo-visible. +class DefaultApps { + public: + // The maximum number of times to show the apps promo. + static const int kAppsPromoCounterMax; + + // Register our preferences. + static void RegisterUserPrefs(PrefService* prefs); + + explicit DefaultApps(PrefService* prefs); + + // Gets the list of default apps that should be installed. Can return NULL if + // no apps need to be installed. + const ExtensionIdSet* GetAppsToInstall() const; + + // 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); + + // Returns true if the apps promo should be displayed in the launcher. This + // starts returning true once the default apps have all been installed and + // stops after the promo expires. + bool ShouldShowPromo(const ExtensionIdSet& installed_ids); + + // Should be called after each time the promo is installed. + void DidShowPromo(); + + // Force the promo to be hidden. + void SetPromoHidden(); + + private: + FRIEND_TEST_ALL_PREFIXES(DefaultApps, Basics); + FRIEND_TEST_ALL_PREFIXES(DefaultApps, HidePromo); + FRIEND_TEST_ALL_PREFIXES(DefaultApps, InstallingAnAppHidesPromo); + FRIEND_TEST_ALL_PREFIXES(DefaultApps, + ManualAppInstalledWhileInstallingDefaultApps); + + 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 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 new file mode 100644 index 0000000..9e7b0d5 --- /dev/null +++ b/chrome/browser/extensions/default_apps_unittest.cc @@ -0,0 +1,132 @@ +// 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 "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" + +TEST(DefaultApps, Basics) { + TestingPrefService pref_service; + DefaultApps::RegisterUserPrefs(&pref_service); + DefaultApps default_apps(&pref_service); + + ExtensionIdSet default_app_ids = *default_apps.GetAppsToInstall(); + ASSERT_GT(default_app_ids.size(), 0u); + EXPECT_FALSE(default_apps.GetDefaultAppsInstalled()); + EXPECT_EQ(0, default_apps.GetPromoCounter()); + + // The promo should not be shown until the default apps have been installed. + ExtensionIdSet installed_app_ids; + EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids)); + + // 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. + ExtensionIdSet extension_id_sets[] = { + default_app_ids, + default_app_ids, + default_app_ids + }; + extension_id_sets[0].clear(); + extension_id_sets[1].erase(extension_id_sets[1].begin()); + extension_id_sets[2].erase(extension_id_sets[2].begin(), + ++extension_id_sets[2].begin()); + for (size_t i = 0; i < arraysize(extension_id_sets); ++i) { + default_apps.DidInstallApp(extension_id_sets[i]); + EXPECT_TRUE(default_app_ids == *default_apps.GetAppsToInstall()); + EXPECT_FALSE(default_apps.GetDefaultAppsInstalled()); + EXPECT_FALSE(default_apps.ShouldShowPromo(extension_id_sets[i])); + } + + // Simulate all the default apps being installed. Now we should stop getting + // default apps to install. + default_apps.DidInstallApp(default_app_ids); + EXPECT_EQ(NULL, default_apps.GetAppsToInstall()); + EXPECT_TRUE(default_apps.GetDefaultAppsInstalled()); + + // And the promo should become available. + EXPECT_TRUE(default_apps.ShouldShowPromo(default_app_ids)); + + // The promo should be available up to the max allowed times, then stop. + for (int i = 0; i < DefaultApps::kAppsPromoCounterMax; ++i) { + EXPECT_TRUE(default_apps.ShouldShowPromo(default_app_ids)); + default_apps.DidShowPromo(); + EXPECT_EQ(i + 1, default_apps.GetPromoCounter()); + } + EXPECT_FALSE(default_apps.ShouldShowPromo(default_app_ids)); + EXPECT_EQ(DefaultApps::kAppsPromoCounterMax, default_apps.GetPromoCounter()); +} + +TEST(DefaultApps, HidePromo) { + TestingPrefService pref_service; + DefaultApps::RegisterUserPrefs(&pref_service); + DefaultApps default_apps(&pref_service); + + ExtensionIdSet default_app_ids = *default_apps.GetAppsToInstall(); + default_apps.DidInstallApp(default_app_ids); + + EXPECT_TRUE(default_apps.ShouldShowPromo(default_app_ids)); + default_apps.DidShowPromo(); + EXPECT_EQ(1, default_apps.GetPromoCounter()); + + default_apps.SetPromoHidden(); + EXPECT_FALSE(default_apps.ShouldShowPromo(default_app_ids)); + EXPECT_EQ(DefaultApps::kAppsPromoCounterMax, default_apps.GetPromoCounter()); +} + +TEST(DefaultApps, InstallingAnAppHidesPromo) { + TestingPrefService pref_service; + DefaultApps::RegisterUserPrefs(&pref_service); + DefaultApps default_apps(&pref_service); + + ExtensionIdSet default_app_ids = *default_apps.GetAppsToInstall(); + ExtensionIdSet installed_app_ids = default_app_ids; + default_apps.DidInstallApp(installed_app_ids); + + EXPECT_TRUE(default_apps.ShouldShowPromo(installed_app_ids)); + default_apps.DidShowPromo(); + 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)); + EXPECT_EQ(DefaultApps::kAppsPromoCounterMax, default_apps.GetPromoCounter()); +} + +TEST(DefaultApps, 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); + + // Simulate an app getting installed before the complete set of default apps. + // This shouldn't affect us installing default apps. We should keep trying. + ExtensionIdSet installed_ids; + installed_ids.insert("foo"); + default_apps.DidInstallApp(installed_ids); + EXPECT_FALSE(default_apps.GetDefaultAppsInstalled()); + EXPECT_TRUE(default_apps.GetAppsToInstall()); + + // Now add all the default apps in addition to the extra app. We should stop + // trying to install default apps. + installed_ids = *default_apps.GetAppsToInstall(); + installed_ids.insert("foo"); + default_apps.DidInstallApp(installed_ids); + EXPECT_TRUE(default_apps.GetDefaultAppsInstalled()); + EXPECT_FALSE(default_apps.GetAppsToInstall()); + + // The promo shouldn't turn on though, because it would look weird with the + // user's extra, manually installed extensions. + EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids)); + EXPECT_EQ(DefaultApps::kAppsPromoCounterMax, default_apps.GetPromoCounter()); +} diff --git a/chrome/browser/extensions/extension_updater.cc b/chrome/browser/extensions/extension_updater.cc index b2fca2b..42ccfba 100644 --- a/chrome/browser/extensions/extension_updater.cc +++ b/chrome/browser/extensions/extension_updater.cc @@ -182,11 +182,7 @@ void ManifestFetchesBuilder::AddPendingExtension( scoped_ptr<Version> version( Version::GetVersionFromString("0.0.0.0")); - Extension::Location location = - (info.is_from_sync ? Extension::INTERNAL - : Extension::EXTERNAL_PREF_DOWNLOAD); - - AddExtensionData(location, id, *version, + AddExtensionData(info.install_source, id, *version, info.expected_crx_type, info.update_url); } diff --git a/chrome/browser/extensions/extension_updater_unittest.cc b/chrome/browser/extensions/extension_updater_unittest.cc index d183b7b..6ea4410 100644 --- a/chrome/browser/extensions/extension_updater_unittest.cc +++ b/chrome/browser/extensions/extension_updater_unittest.cc @@ -130,7 +130,7 @@ void CreateTestPendingExtensions(int count, const GURL& update_url, (*pending_extensions)[id] = PendingExtensionInfo(update_url, crx_type, kIsFromSync, kInstallSilently, kInitialState, - kInitialIncognitoEnabled); + kInitialIncognitoEnabled, Extension::INTERNAL); } } @@ -568,7 +568,7 @@ class ExtensionUpdaterTest : public testing::Test { pending_extensions[id] = PendingExtensionInfo(test_url, kExpectedCrxType, kIsFromSync, kInstallSilently, kInitialState, - kInitialIncognitoEnabled); + kInitialIncognitoEnabled, Extension::INTERNAL); service.set_pending_extensions(pending_extensions); } @@ -897,13 +897,15 @@ TEST(ExtensionUpdaterTest, TestManifestFetchesBuilderAddExtension) { builder.AddPendingExtension( GenerateId("foo"), PendingExtensionInfo(GURL("http:google.com:foo"), PendingExtensionInfo::EXTENSION, - false, false, true, false)); + false, false, true, false, + Extension::INTERNAL)); EXPECT_TRUE(builder.GetFetches().empty()); // Extensions with empty IDs should be rejected. builder.AddPendingExtension( "", PendingExtensionInfo(GURL(), PendingExtensionInfo::EXTENSION, - false, false, true, false)); + false, false, true, false, + Extension::INTERNAL)); EXPECT_TRUE(builder.GetFetches().empty()); // TODO(akalin): Test that extensions with empty update URLs @@ -914,7 +916,8 @@ TEST(ExtensionUpdaterTest, TestManifestFetchesBuilderAddExtension) { builder.AddPendingExtension( GenerateId("foo"), PendingExtensionInfo(GURL(), PendingExtensionInfo::EXTENSION, - false, false, true, false)); + false, false, true, false, + Extension::INTERNAL)); std::vector<ManifestFetchData*> fetches = builder.GetFetches(); ASSERT_EQ(1u, fetches.size()); scoped_ptr<ManifestFetchData> fetch(fetches[0]); diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc index 4ce8c9f..f86564d 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extensions_service.cc @@ -23,6 +23,7 @@ #include "chrome/browser/chrome_thread.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/extension_accessibility_api.h" #include "chrome/browser/extensions/extension_bookmarks_module.h" #include "chrome/browser/extensions/extension_browser_event_router.h" @@ -129,13 +130,15 @@ PendingExtensionInfo::PendingExtensionInfo( bool is_from_sync, bool install_silently, bool enable_on_install, - bool enable_incognito_on_install) + bool enable_incognito_on_install, + Extension::Location location) : update_url(update_url), expected_crx_type(expected_crx_type), is_from_sync(is_from_sync), install_silently(install_silently), enable_on_install(enable_on_install), - enable_incognito_on_install(enable_incognito_on_install) {} + enable_incognito_on_install(enable_incognito_on_install), + install_source(location) {} PendingExtensionInfo::PendingExtensionInfo() : update_url(), @@ -143,7 +146,8 @@ PendingExtensionInfo::PendingExtensionInfo() is_from_sync(true), install_silently(false), enable_on_install(false), - enable_incognito_on_install(false) {} + enable_incognito_on_install(false), + install_source(Extension::INVALID) {} // ExtensionsService. @@ -561,7 +565,8 @@ ExtensionsService::ExtensionsService(Profile* profile, extensions_enabled_(true), show_extensions_prompts_(true), ready_(false), - ALLOW_THIS_IN_INITIALIZER_LIST(toolbar_model_(this)) { + ALLOW_THIS_IN_INITIALIZER_LIST(toolbar_model_(this)), + default_apps_(profile->GetPrefs()) { // Figure out if extension installation should be enabled. if (command_line->HasSwitch(switches::kDisableExtensions)) { extensions_enabled_ = false; @@ -682,8 +687,8 @@ void ExtensionsService::UpdateExtension(const std::string& id, this, // frontend client)); installer->set_expected_id(id); - if (is_pending_extension && !it->second.is_from_sync) - installer->set_install_source(Extension::EXTERNAL_PREF_DOWNLOAD); + if (is_pending_extension) + installer->set_install_source(it->second.install_source); installer->set_delete_source(true); installer->set_original_url(download_url); installer->InstallCrx(extension_path); @@ -699,15 +704,16 @@ void ExtensionsService::AddPendingExtensionFromSync( << " which already exists"; return; } - AddPendingExtensionInternal( - id, update_url, expected_crx_type, true, install_silently, - enable_on_install, enable_incognito_on_install); + + AddPendingExtensionInternal(id, update_url, expected_crx_type, true, + install_silently, enable_on_install, + enable_incognito_on_install, + Extension::INTERNAL); } void ExtensionsService::AddPendingExtensionFromExternalUpdateUrl( const std::string& id, const GURL& update_url) { // Add the extension to this list of extensions to update. - // We do not know if the id refers to a theme, so make is_theme unknown. const PendingExtensionInfo::ExpectedCrxType kExpectedCrxType = PendingExtensionInfo::UNKNOWN; const bool kIsFromSync = false; @@ -723,18 +729,41 @@ void ExtensionsService::AddPendingExtensionFromExternalUpdateUrl( AddPendingExtensionInternal(id, update_url, kExpectedCrxType, kIsFromSync, kInstallSilently, kEnableOnInstall, - kEnableIncognitoOnInstall); + kEnableIncognitoOnInstall, + Extension::EXTERNAL_PREF_DOWNLOAD); +} + +void ExtensionsService::AddPendingExtensionFromDefaultAppList( + const std::string& id) { + // Add the extension to this list of extensions to update. + const PendingExtensionInfo::ExpectedCrxType kExpectedCrxType = + PendingExtensionInfo::APP; + const bool kIsFromSync = false; + const bool kInstallSilently = true; + const bool kEnableOnInstall = true; + const bool kEnableIncognitoOnInstall = true; + + // This can legitimately happen if the user manually installed one of the + // default apps before this code ran. + if (GetExtensionByIdInternal(id, true, true)) + return; + + AddPendingExtensionInternal(id, GURL(), kExpectedCrxType, kIsFromSync, + kInstallSilently, kEnableOnInstall, + kEnableIncognitoOnInstall, + Extension::INTERNAL); } void ExtensionsService::AddPendingExtensionInternal( const std::string& id, const GURL& update_url, PendingExtensionInfo::ExpectedCrxType expected_crx_type, bool is_from_sync, bool install_silently, - bool enable_on_install, bool enable_incognito_on_install) { + bool enable_on_install, bool enable_incognito_on_install, + Extension::Location install_source) { pending_extensions_[id] = PendingExtensionInfo(update_url, expected_crx_type, is_from_sync, install_silently, enable_on_install, - enable_incognito_on_install); + enable_incognito_on_install, install_source); } void ExtensionsService::ReloadExtension(const std::string& extension_id) { @@ -1514,8 +1543,11 @@ void ExtensionsService::OnExtensionInstalled(Extension* extension, // Set initial state from pending extension data. PendingExtensionInfo::ExpectedCrxType actual_crx_type = - (extension->is_theme() ? PendingExtensionInfo::THEME - : PendingExtensionInfo::EXTENSION); + PendingExtensionInfo::EXTENSION; + if (extension->is_app()) + actual_crx_type = PendingExtensionInfo::APP; + else if (extension->is_theme()) + actual_crx_type = PendingExtensionInfo::THEME; if (expected_crx_type != PendingExtensionInfo::UNKNOWN && expected_crx_type != actual_crx_type) { @@ -1626,6 +1658,12 @@ void ExtensionsService::OnExtensionInstalled(Extension* extension, Details<Extension>(extension)); } + if (extension->is_app()) { + ExtensionIdSet installed_ids = GetAppIds(); + installed_ids.insert(extension->id()); + default_apps_.DidInstallApp(installed_ids); + } + // Transfer ownership of |extension| to OnExtensionLoaded. OnExtensionLoaded(scoped_extension.release(), allow_privilege_increase); } @@ -1825,15 +1863,17 @@ void ExtensionsService::Observe(NotificationType type, } } -bool ExtensionsService::HasApps() { - if (!extensions_enabled_) - return false; +bool ExtensionsService::HasApps() const { + return !GetAppIds().empty(); +} +ExtensionIdSet ExtensionsService::GetAppIds() const { + ExtensionIdSet result; for (ExtensionList::const_iterator it = extensions_.begin(); it != extensions_.end(); ++it) { - if ((*it)->is_app()) - return true; + if ((*it)->is_app() && (*it)->location() != Extension::COMPONENT) + result.insert((*it)->id()); } - return false; + return result; } diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h index 71fbfd9..10f54c6 100644 --- a/chrome/browser/extensions/extensions_service.h +++ b/chrome/browser/extensions/extensions_service.h @@ -20,6 +20,7 @@ #include "base/time.h" #include "base/tuple.h" #include "chrome/browser/chrome_thread.h" +#include "chrome/browser/extensions/default_apps.h" #include "chrome/browser/extensions/extension_icon_manager.h" #include "chrome/browser/extensions/extension_menu_manager.h" #include "chrome/browser/extensions/extension_prefs.h" @@ -51,6 +52,7 @@ struct PendingExtensionInfo { enum ExpectedCrxType { UNKNOWN, // Sometimes we don't know the type of a pending item. An // update URL from external_extensions.json is one such case. + APP, THEME, EXTENSION }; @@ -60,7 +62,8 @@ struct PendingExtensionInfo { bool is_from_sync, bool install_silently, bool enable_on_install, - bool enable_incognito_on_install); + bool enable_incognito_on_install, + Extension::Location install_source); PendingExtensionInfo(); @@ -70,6 +73,7 @@ struct PendingExtensionInfo { bool install_silently; bool enable_on_install; bool enable_incognito_on_install; + Extension::Location install_source; }; // A PendingExtensionMap is a map from IDs of pending extensions to @@ -169,6 +173,10 @@ class ExtensionsService return !(extensions_.empty() && disabled_extensions_.empty()); } + const FilePath& install_directory() const { return install_directory_; } + + DefaultApps* default_apps() { return &default_apps_; } + // Whether this extension can run in an incognito window. bool IsIncognitoEnabled(const Extension* extension); void SetIsIncognitoEnabled(Extension* extension, bool enabled); @@ -177,8 +185,6 @@ class ExtensionsService bool AllowFileAccess(const Extension* extension); void SetAllowFileAccess(Extension* extension, bool allow); - const FilePath& install_directory() const { return install_directory_; } - // Initialize and start all installed extensions. void Init(); @@ -225,6 +231,10 @@ class ExtensionsService void AddPendingExtensionFromExternalUpdateUrl(const std::string& id, const GURL& update_url); + // Like the above. Always installed silently, and defaults update url + // from extension id. + void AddPendingExtensionFromDefaultAppList(const std::string& id); + // Reloads the specified extension. void ReloadExtension(const std::string& extension_id); @@ -386,8 +396,11 @@ class ExtensionsService const NotificationSource& source, const NotificationDetails& details); - // Whether there are any apps installed. - bool HasApps(); + // Whether there are any apps installed. Component apps are not included. + bool HasApps() const; + + // Gets the set of loaded app ids. Component apps are not included. + ExtensionIdSet GetAppIds() const; private: virtual ~ExtensionsService(); @@ -409,7 +422,8 @@ class ExtensionsService const std::string& id, const GURL& update_url, PendingExtensionInfo::ExpectedCrxType crx_type, bool is_from_sync, bool install_silently, - bool enable_on_install, bool enable_incognito_on_install); + bool enable_on_install, bool enable_incognito_on_install, + Extension::Location install_source); // Handles sending notification that |extension| was loaded. void NotifyExtensionLoaded(Extension* extension); @@ -511,6 +525,10 @@ class ExtensionsService typedef std::map<GURL, int> ProtectedStorageMap; ProtectedStorageMap protected_storage_map_; + // Manages the installation of default apps and the promotion of them in the + // app launcher. + DefaultApps default_apps_; + FRIEND_TEST_ALL_PREFIXES(ExtensionsServiceTest, UpdatePendingExtensionAlreadyInstalled); FRIEND_TEST_ALL_PREFIXES(ExtensionsServiceTest, diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc index fc6662e..6d49a3b 100644 --- a/chrome/browser/extensions/extensions_service_unittest.cc +++ b/chrome/browser/extensions/extensions_service_unittest.cc @@ -1716,7 +1716,7 @@ TEST_F(ExtensionsServiceTest, UpdatePendingExtensionAlreadyInstalled) { good->id(), good->update_url(), PendingExtensionInfo::EXTENSION, kGoodIsFromSync, kGoodInstallSilently, kGoodInitialState, - kGoodInitialIncognitoEnabled); + kGoodInitialIncognitoEnabled, Extension::INTERNAL); UpdateExtension(good->id(), path, INSTALLED); EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId)); diff --git a/chrome/browser/profile_impl.cc b/chrome/browser/profile_impl.cc index af95572..899e068daa 100644 --- a/chrome/browser/profile_impl.cc +++ b/chrome/browser/profile_impl.cc @@ -26,6 +26,7 @@ #include "chrome/browser/chrome_thread.h" #include "chrome/browser/dom_ui/ntp_resource_cache.h" #include "chrome/browser/download/download_manager.h" +#include "chrome/browser/extensions/default_apps.h" #include "chrome/browser/extensions/extension_devtools_manager.h" #include "chrome/browser/extensions/extension_error_reporter.h" #include "chrome/browser/extensions/extension_info_map.h" @@ -168,15 +169,6 @@ bool HasACacheSubdir(const FilePath &dir) { file_util::PathExists(GetMediaCachePath(dir)); } -// Returns true if the default apps should be loaded (so that the app panel is -// not empty). -bool IncludeDefaultApps() { -#if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD) - return true; -#endif - return false; -} - // Simple task to log the size of the current profile. class ProfileSizeTask : public Task { public: @@ -240,6 +232,7 @@ Profile* Profile::CreateProfile(const FilePath& path) { // static void ProfileImpl::RegisterUserPrefs(PrefService* prefs) { prefs->RegisterBooleanPref(prefs::kSavingBrowserHistoryDisabled, false); + DefaultApps::RegisterUserPrefs(prefs); } ProfileImpl::ProfileImpl(const FilePath& path) @@ -375,6 +368,18 @@ void ProfileImpl::InitExtensions() { GetPath().AppendASCII(ExtensionsService::kInstallDirectoryName), true); + RegisterComponentExtensions(); + extensions_service_->Init(); + InstallDefaultApps(); + + // Load any extensions specified with --load-extension. + if (command_line->HasSwitch(switches::kLoadExtension)) { + FilePath path = command_line->GetSwitchValuePath(switches::kLoadExtension); + extensions_service_->LoadExtension(path); + } +} + +void ProfileImpl::RegisterComponentExtensions() { // Register the component extensions. typedef std::list<std::pair<std::string, int> > ComponentExtensionList; ComponentExtensionList component_extensions; @@ -392,22 +397,9 @@ void ProfileImpl::InitExtensions() { component_extensions.push_back( std::make_pair("web_store", IDR_WEBSTORE_MANIFEST)); - // Some sample apps to make our lives easier while we are developing extension - // apps. This way we don't have to constantly install these over and over. - if (Extension::AppsAreEnabled() && IncludeDefaultApps()) { - component_extensions.push_back( - std::make_pair("gmail_app", IDR_GMAIL_APP_MANIFEST)); - component_extensions.push_back( - std::make_pair("calendar_app", IDR_CALENDAR_APP_MANIFEST)); - component_extensions.push_back( - std::make_pair("docs_app", IDR_DOCS_APP_MANIFEST)); - } - #if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD) - if (Extension::AppsAreEnabled()) { - component_extensions.push_back( - std::make_pair("chat_manager", IDR_TALK_APP_MANIFEST)); - } + component_extensions.push_back( + std::make_pair("chat_manager", IDR_TALK_APP_MANIFEST)); #endif for (ComponentExtensionList::iterator iter = component_extensions.begin(); @@ -425,13 +417,31 @@ void ProfileImpl::InitExtensions() { extensions_service_->register_component_extension( ExtensionsService::ComponentExtensionInfo(manifest, path)); } +} - extensions_service_->Init(); +void ProfileImpl::InstallDefaultApps() { +#if !defined(OS_CHROMEOS) + // On desktop Chrome, we don't have default apps on by, err, default yet. + if (!CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableDefaultApps)) { + return; + } +#endif - // Load any extensions specified with --load-extension. - if (command_line->HasSwitch(switches::kLoadExtension)) { - FilePath path = command_line->GetSwitchValuePath(switches::kLoadExtension); - extensions_service_->LoadExtension(path); + // The web store only supports en-US at the moment, so we don't install + // default apps in other locales. + if (g_browser_process->GetApplicationLocale() != "en-US") + return; + + ExtensionsService* extensions_service = GetExtensionsService(); + const ExtensionIdSet* app_ids = + extensions_service->default_apps()->GetAppsToInstall(); + if (!app_ids) + return; + + for (ExtensionIdSet::const_iterator iter = app_ids->begin(); + iter != app_ids->end(); ++iter) { + extensions_service->AddPendingExtensionFromDefaultAppList(*iter); } } diff --git a/chrome/browser/profile_impl.h b/chrome/browser/profile_impl.h index efa00c1..7b926e6 100644 --- a/chrome/browser/profile_impl.h +++ b/chrome/browser/profile_impl.h @@ -151,6 +151,9 @@ class ProfileImpl : public Profile, GetSessionService(); } + void RegisterComponentExtensions(); + void InstallDefaultApps(); + NotificationRegistrar registrar_; PrefChangeRegistrar pref_change_registrar_; diff --git a/chrome/browser/resources/calendar_app/128.png b/chrome/browser/resources/calendar_app/128.png Binary files differdeleted file mode 100644 index 5ebe636..0000000 --- a/chrome/browser/resources/calendar_app/128.png +++ /dev/null diff --git a/chrome/browser/resources/calendar_app/24.png b/chrome/browser/resources/calendar_app/24.png Binary files differdeleted file mode 100644 index b3a971d..0000000 --- a/chrome/browser/resources/calendar_app/24.png +++ /dev/null diff --git a/chrome/browser/resources/calendar_app/32.png b/chrome/browser/resources/calendar_app/32.png Binary files differdeleted file mode 100644 index e1ac68d..0000000 --- a/chrome/browser/resources/calendar_app/32.png +++ /dev/null diff --git a/chrome/browser/resources/calendar_app/48.png b/chrome/browser/resources/calendar_app/48.png Binary files differdeleted file mode 100644 index 6bfde15..0000000 --- a/chrome/browser/resources/calendar_app/48.png +++ /dev/null diff --git a/chrome/browser/resources/calendar_app/manifest.json b/chrome/browser/resources/calendar_app/manifest.json deleted file mode 100644 index 8bcf843..0000000 --- a/chrome/browser/resources/calendar_app/manifest.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "key": "XX3fMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCf1MLMJ1mzNVJOVqaFFX+fQ7gJLVeZN+Sq3tKnZM33oWP82xDDs345/TsFTqGV3Nj5KvmjIN5NwcW/AeBOpVeOGFujFDSTOCZv0JDKkTXLyCegSwF+ljBi0TbCrsgv2T+8Jt891+hSyw5LPjXoTX2bKz+bu016tQnGnhb6fXyCBQIDAQAB", - "name": "Google Calendar", - "version": "1.3", - "permissions": [ "notifications" ], - "icons": { - "128": "128.png", - "24": "24.png", - "32": "32.png", - "48": "48.png" - }, - "app": { - "urls": [ - "*://www.google.com/calendar/" - ], - "browse_urls": [ - "https://www.google.com/accounts/" - ], - "launch": { - "container": "tab", - "web_url": "https://www.google.com/calendar/" - } - } -} diff --git a/chrome/browser/resources/docs_app/128.png b/chrome/browser/resources/docs_app/128.png Binary files differdeleted file mode 100644 index 0b514a8..0000000 --- a/chrome/browser/resources/docs_app/128.png +++ /dev/null diff --git a/chrome/browser/resources/docs_app/24.png b/chrome/browser/resources/docs_app/24.png Binary files differdeleted file mode 100644 index 7260ac5..0000000 --- a/chrome/browser/resources/docs_app/24.png +++ /dev/null diff --git a/chrome/browser/resources/docs_app/32.png b/chrome/browser/resources/docs_app/32.png Binary files differdeleted file mode 100644 index 6ed8ecd..0000000 --- a/chrome/browser/resources/docs_app/32.png +++ /dev/null diff --git a/chrome/browser/resources/docs_app/48.png b/chrome/browser/resources/docs_app/48.png Binary files differdeleted file mode 100644 index 7440412..0000000 --- a/chrome/browser/resources/docs_app/48.png +++ /dev/null diff --git a/chrome/browser/resources/docs_app/manifest.json b/chrome/browser/resources/docs_app/manifest.json deleted file mode 100644 index 10e965c..0000000 --- a/chrome/browser/resources/docs_app/manifest.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "key": "XX1fMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCfjDZDDE/CHFEYjpPSDjdI3zphzGo7fSxO3+/pQs++FwvA+OpKKhmBga2Sa+f53ujDlPR8Q6mCvy1lXM4M4zD4Hg3lH2LC1wT/YXxJ28afRYW1yEo6/pbpHazij3+FneGMT2xcTyGvgoacJHXOTUqWyCN7qMOCiFDwQ6Uk1zJOPQIDAQAB", - "name": "Google Docs", - "version": "1", - "icons": { - "128": "128.png", - "24": "24.png", - "32": "32.png", - "48": "48.png" - }, - "app": { - "urls": [ - "*://www.google.com/docs/", - "*://docs.google.com/", - "*://docs0.google.com/", - "*://docs1.google.com/", - "*://docs2.google.com/", - "*://docs3.google.com/", - "*://docs4.google.com/", - "*://docs5.google.com/", - "*://docs6.google.com/", - "*://docs7.google.com/", - "*://docs8.google.com/", - "*://docs9.google.com/", - "*://spreadsheets.google.com/", - "*://spreadsheets0.google.com/", - "*://spreadsheets1.google.com/", - "*://spreadsheets2.google.com/", - "*://spreadsheets3.google.com/", - "*://spreadsheets4.google.com/", - "*://spreadsheets5.google.com/", - "*://spreadsheets6.google.com/", - "*://spreadsheets7.google.com/", - "*://spreadsheets8.google.com/", - "*://spreadsheets9.google.com/" - ], - "browse_urls": [ - "https://www.google.com/accounts/" - ], - "launch": { - "web_url": "https://docs.google.com/" - } - } -} diff --git a/chrome/browser/resources/gmail_app/128.png b/chrome/browser/resources/gmail_app/128.png Binary files differdeleted file mode 100644 index 679e7a2..0000000 --- a/chrome/browser/resources/gmail_app/128.png +++ /dev/null diff --git a/chrome/browser/resources/gmail_app/24.png b/chrome/browser/resources/gmail_app/24.png Binary files differdeleted file mode 100644 index 8b14b22..0000000 --- a/chrome/browser/resources/gmail_app/24.png +++ /dev/null diff --git a/chrome/browser/resources/gmail_app/32.png b/chrome/browser/resources/gmail_app/32.png Binary files differdeleted file mode 100644 index bfd8aa4..0000000 --- a/chrome/browser/resources/gmail_app/32.png +++ /dev/null diff --git a/chrome/browser/resources/gmail_app/48.png b/chrome/browser/resources/gmail_app/48.png Binary files differdeleted file mode 100644 index bc1f9fd..0000000 --- a/chrome/browser/resources/gmail_app/48.png +++ /dev/null diff --git a/chrome/browser/resources/gmail_app/manifest.json b/chrome/browser/resources/gmail_app/manifest.json deleted file mode 100644 index 9dfcf98..0000000 --- a/chrome/browser/resources/gmail_app/manifest.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "key": "XX2fMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCfjDZDDE/CHFEYjpPSDjdI3zphzGo7fSxO3+/pQs++FwvA+OpKKhmBga2Sa+f53ujDlPR8Q6mCvy1lXM4M4zD4Hg3lH2LC1wT/YXxJ28afRYW1yEo6/pbpHazij3+FneGMT2xcTyGvgoacJHXOTUqWyCN7qMOCiFDwQ6Uk1zJOPQIDAQAB", - "name": "Google Mail", - "version": "1", - "icons": { - "128": "128.png", - "24": "24.png", - "32": "32.png", - "48": "48.png" - }, - "permissions": [ "notifications" ], - "app": { - "urls": [ - "*://mail.google.com/mail/", - "*://gmail.com/", - "*://www.gmail.com/" - ], - "browse_urls": [ - "https://www.google.com/accounts/" - ], - "launch": { - "web_url": "https://mail.google.com/mail/" - } - } -} diff --git a/chrome/browser/resources/new_new_tab.html b/chrome/browser/resources/new_new_tab.html index 9f78a10..e0f799e 100644 --- a/chrome/browser/resources/new_new_tab.html +++ b/chrome/browser/resources/new_new_tab.html @@ -5,8 +5,7 @@ hasattribution:hasattribution; anim:anim; syncispresent:syncispresent; - customlogo:customlogo; - appspromovisible:appspromovisible" + customlogo:customlogo" install-animation-enabled="true"> <head> <meta charset="utf-8"> diff --git a/chrome/browser/resources/new_new_tab.js b/chrome/browser/resources/new_new_tab.js index 2373582..0a577d4 100644 --- a/chrome/browser/resources/new_new_tab.js +++ b/chrome/browser/resources/new_new_tab.js @@ -1101,4 +1101,10 @@ document.addEventListener('DOMContentLoaded', function() { var promoText1 = $('apps-promo-text1'); promoText1.innerHTML = promoText1.textContent; promoText1.querySelector('a').href = localStrings.getString('web_store_url'); + + $('apps-promo-hide').addEventListener('click', function() { + chrome.send('hideAppsPromo', []); + document.documentElement.classList.remove('apps-promo-visible'); + layoutSections(); + }); }); diff --git a/chrome/browser/resources/ntp/apps.css b/chrome/browser/resources/ntp/apps.css index 45301ab..c92c7a9 100644 --- a/chrome/browser/resources/ntp/apps.css +++ b/chrome/browser/resources/ntp/apps.css @@ -102,7 +102,7 @@ menu > button.default { display: none; } -html[appspromovisible=true] #apps-promo { +html.apps-promo-visible #apps-promo { display: block; } @@ -132,15 +132,15 @@ html[dir=rtl] #apps-promo-hide { float: left; } -html[appspromovisible=true] .app[app-id=web-store-entry] { +html.apps-promo-visible .app[app-id=web-store-entry] { left: 25px; } -html[appspromovisible=true][dir=rtl] .app[app-id=web-store-entry] { +html.apps-promo-visible[dir=rtl] .app[app-id=web-store-entry] { right: 25px; } -html[appspromovisible=true] .app[app-id=web-store-entry] a { +html.apps-promo-visible .app[app-id=web-store-entry] a { font-weight: bold; } diff --git a/chrome/browser/resources/ntp/apps.js b/chrome/browser/resources/ntp/apps.js index dd44532..e6f79a2 100644 --- a/chrome/browser/resources/ntp/apps.js +++ b/chrome/browser/resources/ntp/apps.js @@ -37,6 +37,10 @@ function getAppsCallback(data) { addClosedMenuFooter(apps.menu, 'apps', MINIMIZED_APPS, Section.APPS); apps.loaded = true; + if (data.showPromo) + document.documentElement.classList.add('apps-promo-visible'); + else + document.documentElement.classList.remove('apps-promo-visible'); maybeDoneLoading(); if (data.apps.length > 0 && isDoneLoading()) { diff --git a/chrome/browser/shell_integration.cc b/chrome/browser/shell_integration.cc index 3ed45ae7..c51ed25 100644 --- a/chrome/browser/shell_integration.cc +++ b/chrome/browser/shell_integration.cc @@ -42,7 +42,7 @@ std::string ShellIntegration::GetCommandLineArgumentsCommon(const GURL& url, // If |extension_app_id| is present, we use the kAppId switch rather than // the kApp switch (the launch url will be read from the extension app // during launch. - if (!cmd.HasSwitch(switches::kDisableApps) && !extension_app_id.empty()) { + if (!extension_app_id.empty()) { arguments_w += std::wstring(L"--") + ASCIIToWide(switches::kAppId) + L"=\"" + ASCIIToWide(UTF16ToASCII(extension_app_id)); } else { diff --git a/chrome/browser/utility_process_host.cc b/chrome/browser/utility_process_host.cc index 5091169..74afd4d 100644 --- a/chrome/browser/utility_process_host.cc +++ b/chrome/browser/utility_process_host.cc @@ -121,9 +121,6 @@ bool UtilityProcessHost::StartProcess(const FilePath& exposed_dir) { if (browser_command_line.HasSwitch(switches::kChromeFrame)) cmd_line->AppendSwitch(switches::kChromeFrame); - if (browser_command_line.HasSwitch(switches::kDisableApps)) - cmd_line->AppendSwitch(switches::kDisableApps); - if (browser_command_line.HasSwitch( switches::kEnableExperimentalExtensionApis)) { cmd_line->AppendSwitch(switches::kEnableExperimentalExtensionApis); diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index f368c8c..bd284b7 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1414,6 +1414,8 @@ 'browser/extensions/crashed_extension_infobar.h', 'browser/extensions/crx_installer.cc', 'browser/extensions/crx_installer.h', + 'browser/extensions/default_apps.cc', + 'browser/extensions/default_apps.h', 'browser/extensions/extension_accessibility_api.cc', 'browser/extensions/extension_accessibility_api.h', 'browser/extensions/extension_accessibility_api_constants.cc', @@ -4033,41 +4035,6 @@ 'target_name': 'component_extensions', 'type': 'none', 'msvs_guid': '50B52703-525F-404C-BFE2-C46D3375D73E', - # TODO(aa): Once the msvs port supports it, change this to recursively - # copy the entire directory instead of listing the files. - # http://code.google.com/p/gyp/issues/detail?id=143. - 'copies': [ - { - 'destination': '<(PRODUCT_DIR)/resources/gmail_app', - 'files': [ - 'browser/resources/gmail_app/manifest.json', - 'browser/resources/gmail_app/128.png', - 'browser/resources/gmail_app/48.png', - 'browser/resources/gmail_app/32.png', - 'browser/resources/gmail_app/24.png', - ] - }, - { - 'destination': '<(PRODUCT_DIR)/resources/calendar_app', - 'files': [ - 'browser/resources/calendar_app/manifest.json', - 'browser/resources/calendar_app/128.png', - 'browser/resources/calendar_app/48.png', - 'browser/resources/calendar_app/32.png', - 'browser/resources/calendar_app/24.png', - ] - }, - { - 'destination': '<(PRODUCT_DIR)/resources/docs_app', - 'files': [ - 'browser/resources/docs_app/manifest.json', - 'browser/resources/docs_app/128.png', - 'browser/resources/docs_app/48.png', - 'browser/resources/docs_app/32.png', - 'browser/resources/docs_app/24.png', - ] - }, - ], 'conditions': [ ['OS=="linux" and chromeos==1 and branding=="Chrome"',{ 'copies': [ diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi index c68a388..0a08369 100644 --- a/chrome/chrome_dll.gypi +++ b/chrome/chrome_dll.gypi @@ -445,9 +445,6 @@ 'destination': '<(PRODUCT_DIR)/$(CONTENTS_FOLDER_PATH)/Resources', 'files': [ '<(PRODUCT_DIR)/resources/inspector/', - '<(PRODUCT_DIR)/resources/gmail_app/', - '<(PRODUCT_DIR)/resources/calendar_app/', - '<(PRODUCT_DIR)/resources/docs_app/', ], 'conditions': [ ['mac_breakpad==1', { diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 08144b3..4bea7d5 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1247,6 +1247,7 @@ 'browser/download/save_package_unittest.cc', 'browser/encoding_menu_controller_unittest.cc', 'browser/extensions/convert_user_script_unittest.cc', + 'browser/extensions/default_apps_unittest.cc', 'browser/extensions/extension_icon_manager_unittest.cc', 'browser/extensions/extension_info_map_unittest.cc', 'browser/extensions/extension_menu_manager_unittest.cc', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 231edea..077e28a 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -131,9 +131,6 @@ const char kDisableAltWinstation[] = "disable-winsta"; // Disable the ApplicationCache. const char kDisableApplicationCache[] = "disable-application-cache"; -// Disable extension apps. -const char kDisableApps[] = "disable-apps"; - // Replaces the audio IPC layer for <audio> and <video> with a mock audio // device, useful when using remote desktop or machines without sound cards. // This is temporary until we fix the underlying problem. @@ -381,10 +378,6 @@ const char kEnableBackgroundMode[] = "enable-background-mode"; // Enables the benchmarking extensions. const char kEnableBenchmarking[] = "enable-benchmarking"; -// This applies only when the process type is "service". Enables the -// Chromoting Host Process within the service process. -const char kEnableRemoting[] = "enable-remoting"; - // This flag enables UI for clearing server data. Temporarily in place // until there's a server endpoint deployed. const char kEnableClearServerData[] = "enable-clear-server-data"; @@ -405,6 +398,10 @@ const char kEnableConnectBackupJobs[] = "enable-connect-backup-jobs"; // Link: headers. const char kEnableContentPrefetch[] = "enable-content-prefetch"; +// Whether default apps should be installed in this profile. This flag has no +// effect on Chrome OS because default apps are always enabled there. +const char kEnableDefaultApps[] = "enable-default-apps"; + // Enables device motion events. const char kEnableDeviceMotion[] = "enable-device-motion"; @@ -471,6 +468,10 @@ const char kEnableNaClDebug[] = "enable-nacl-debug"; // Enable Native Web Worker support. const char kEnableNativeWebWorkers[] = "enable-native-web-workers"; +// This applies only when the process type is "service". Enables the +// Chromoting Host Process within the service process. +const char kEnableRemoting[] = "enable-remoting"; + // Enable content settings based on host *and* plug-in. const char kEnableResourceContentSettings[] = "enable-resource-content-settings"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index d2cc319..13692aa 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -51,7 +51,6 @@ extern const char kDiagnostics[]; extern const char kDisableAcceleratedCompositing[]; extern const char kDisableAltWinstation[]; extern const char kDisableApplicationCache[]; -extern const char kDisableApps[]; extern const char kDisableAudio[]; extern const char kDisableAuthNegotiateCnameLookup[]; extern const char kDisableBackgroundNetworking[]; @@ -119,12 +118,12 @@ extern const char kEnableAeroPeekTabs[]; extern const char kEnableAuthNegotiatePort[]; extern const char kEnableBackgroundMode[]; extern const char kEnableBenchmarking[]; -extern const char kEnableRemoting[]; extern const char kEnableClearServerData[]; extern const char kEnableCloudPrintProxy[]; extern const char kEnableCloudPrint[]; extern const char kEnableConnectBackupJobs[]; extern const char kEnableContentPrefetch[]; +extern const char kEnableDefaultApps[]; extern const char kEnableDeviceMotion[]; extern const char kEnableDNSSECCerts[]; extern const char kEnableExperimentalExtensionApis[]; @@ -147,6 +146,7 @@ extern const char kEnableNativeWebWorkers[]; extern const char kEnablePreconnect[]; extern const char kEnablePreparsedJsCaching[]; extern const char kEnablePrintPreview[]; +extern const char kEnableRemoting[]; extern const char kEnableResourceContentSettings[]; extern const char kEnableSearchProviderApiV2[]; extern const char kEnableSecureInfoBars[]; diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc index b90f446..4a5dbcc 100644 --- a/chrome/common/extensions/extension.cc +++ b/chrome/common/extensions/extension.cc @@ -745,14 +745,8 @@ bool Extension::ContainsNonThemeKeys(const DictionaryValue& source) { bool Extension::LoadIsApp(const DictionaryValue* manifest, std::string* error) { - if (manifest->HasKey(keys::kApp)) { - if (!apps_enabled_) { - *error = errors::kAppsNotEnabled; - return false; - } else { - is_app_ = true; - } - } + if (manifest->HasKey(keys::kApp)) + is_app_ = true; return true; } @@ -971,7 +965,6 @@ Extension::Extension(const FilePath& path) DCHECK(path.IsAbsolute()); static_data_ = mutable_static_data_; - apps_enabled_ = AppsAreEnabled(); location_ = INVALID; #if defined(OS_WIN) @@ -1177,11 +1170,6 @@ GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) { chrome::kStandardSchemeSeparator + extension_id + "/"); } -// static -bool Extension::AppsAreEnabled() { - return !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableApps); -} - bool Extension::InitFromValue(const DictionaryValue& source, bool require_key, std::string* error) { // Unit tests reuse Extension objects, so we need to reset mutable_static_data diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h index fbb4246..0302771 100644 --- a/chrome/common/extensions/extension.h +++ b/chrome/common/extensions/extension.h @@ -170,9 +170,6 @@ class Extension { const URLPatternList& host_patterns); std::vector<std::string> GetDistinctHosts(); - bool apps_enabled() const { return apps_enabled_; } - void set_apps_enabled(bool val) { apps_enabled_ = val; } - // Icon sizes used by the extension system. static const int kIconSizes[]; @@ -316,11 +313,7 @@ class Extension { // Returns the base extension url for a given |extension_id|. static GURL GetBaseURLFromExtensionId(const std::string& extension_id); - // Returns whether the browser has apps enabled (either as the default or if - // it was explicitly turned on via a command line switch). - static bool AppsAreEnabled(); - - // Returns the launch URL for the extension/apps gallery. Can be set via the + // Returns the url prefix for the extension/apps gallery. Can be set via the // --apps-gallery-url switch. The URL returned will not contain a trailing // slash. Do not use this as a prefix/extent for the store. Instead see // ExtensionsService::GetWebStoreApp or @@ -647,10 +640,6 @@ class Extension { // which override the handling of those URLs. URLOverrideMap chrome_url_overrides_; - // Whether apps-related features can be parsed during InitFromValue(). - // Defaults to the value from --enable-extension-apps. - bool apps_enabled_; - // Whether this extension uses app features. bool is_app_; @@ -690,6 +679,7 @@ class Extension { }; typedef std::vector<Extension*> ExtensionList; +typedef std::set<std::string> ExtensionIdSet; // Handy struct to pass core extension info around. struct ExtensionInfo { diff --git a/chrome/common/extensions/extension_manifests_unittest.cc b/chrome/common/extensions/extension_manifests_unittest.cc index 5cdd909..9a660bc 100644 --- a/chrome/common/extensions/extension_manifests_unittest.cc +++ b/chrome/common/extensions/extension_manifests_unittest.cc @@ -46,7 +46,6 @@ class ExtensionManifestTest : public testing::Test { scoped_ptr<Extension> extension(new Extension(path.DirName())); extension->set_location(location); - extension->set_apps_enabled(enable_apps_); if (!extension->InitFromValue(*value, false, error)) return NULL; @@ -119,17 +118,6 @@ class ExtensionManifestTest : public testing::Test { bool enable_apps_; }; -TEST_F(ExtensionManifestTest, AppsDisabledByDefault) { -#if defined(OS_CHROMEOS) - // On ChromeOS, apps are enabled by default. - if (Extension::AppsAreEnabled()) - return; -#endif - - enable_apps_ = false; - LoadAndExpectError("launch_local_path.json", errors::kAppsNotEnabled); -} - TEST_F(ExtensionManifestTest, ValidApp) { scoped_ptr<Extension> extension(LoadAndExpectSuccess("valid_app.json")); ASSERT_EQ(2u, extension->web_extent().patterns().size()); diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 30298e5..6fc57de 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -9,6 +9,13 @@ namespace prefs { // *************** PROFILE PREFS *************** // These are attached to the user profile +// A counter that controls whether the apps promo is shown in the app launcher +// or not. +const char kAppsPromoCounter[] = "apps_promo_counter"; + +// Whether we have installed default apps yet in this profile. +const char kDefaultAppsInstalled[] = "default_apps_installed"; + // A boolean specifying whether the New Tab page is the home page or not. const char kHomePageIsNewTabPage[] = "homepage_is_newtabpage"; diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index c88998c..08e1433 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -13,6 +13,8 @@ namespace prefs { // Profile prefs +extern const char kAppsPromoCounter[]; +extern const char kDefaultAppsInstalled[]; extern const char kHomePageIsNewTabPage[]; extern const char kHomePage[]; extern const char kSessionExitedCleanly[]; diff --git a/chrome/installer/mini_installer/chrome.release b/chrome/installer/mini_installer/chrome.release index 7d26cfc..23225e4 100644 --- a/chrome/installer/mini_installer/chrome.release +++ b/chrome/installer/mini_installer/chrome.release @@ -40,9 +40,6 @@ resources.pak: %(VersionDir)s\ locales\*.dll: %(VersionDir)s\Locales Resources\Inspector\*.*: %(VersionDir)s\Resources\Inspector Resources\Inspector\Images\*.*: %(VersionDir)s\Resources\Inspector\Images -Resources\gmail_app\*.*: %(VersionDir)s\Resources\gmail_app -Resources\calendar_app\*.*: %(VersionDir)s\Resources\calendar_app -Resources\docs_app\*.*: %(VersionDir)s\Resources\docs_app servers\*.dll: %(VersionDir)s\ servers\*.exe: %(VersionDir)s\ chrome_frame_helper.exe: %(VersionDir)s\ |