diff options
author | jstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-12 21:59:48 +0000 |
---|---|---|
committer | jstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-12 21:59:48 +0000 |
commit | fd131723b6ff17cc408920b22f8de08575dfc91d (patch) | |
tree | 67fb4ced778be29e8cbde52ef6e12c9dc5ada89d | |
parent | 4790db572ffcb4f10ec64abaa77696e8ee6ace03 (diff) | |
download | chromium_src-fd131723b6ff17cc408920b22f8de08575dfc91d.zip chromium_src-fd131723b6ff17cc408920b22f8de08575dfc91d.tar.gz chromium_src-fd131723b6ff17cc408920b22f8de08575dfc91d.tar.bz2 |
Add a histogram for tracking web store promo
Creates an enumeration histogram called Extensions.AppsPromo with the following buckets:
0: launched an application from the promo
1: launched the web store from the promo
2: manually closed the promo (and uninstalled the applications)
3: promo expired
BUG=61017
TEST=
Review URL: http://codereview.chromium.org/4708002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66006 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/dom_ui/app_launcher_handler.cc | 154 | ||||
-rw-r--r-- | chrome/browser/dom_ui/app_launcher_handler.h | 24 | ||||
-rw-r--r-- | chrome/browser/dom_ui/new_tab_ui.cc | 4 | ||||
-rw-r--r-- | chrome/browser/extensions/default_apps.cc | 10 | ||||
-rw-r--r-- | chrome/browser/resources/new_new_tab.js | 5 | ||||
-rw-r--r-- | chrome/browser/resources/ntp/apps.js | 18 | ||||
-rw-r--r-- | chrome/common/extensions/extension_constants.cc | 1 | ||||
-rw-r--r-- | chrome/common/extensions/extension_constants.h | 12 |
8 files changed, 171 insertions, 57 deletions
diff --git a/chrome/browser/dom_ui/app_launcher_handler.cc b/chrome/browser/dom_ui/app_launcher_handler.cc index 9bc27d2..f550525 100644 --- a/chrome/browser/dom_ui/app_launcher_handler.cc +++ b/chrome/browser/dom_ui/app_launcher_handler.cc @@ -5,7 +5,9 @@ #include "chrome/browser/dom_ui/app_launcher_handler.h" #include "app/animation.h" +#include "base/metrics/histogram.h" #include "base/string_number_conversions.h" +#include "base/string_split.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "base/values.h" @@ -32,6 +34,11 @@ namespace { +// The URL prefixes used by the NTP to signal when the web store or an app +// has launched. These are used for histogram purposes. +const char* kLaunchAppPingURL = "record-app-launch"; +const char* kLaunchWebStorePingURL = "record-webstore-launch"; + // This extracts an int from a ListValue at the given |index|. bool ExtractInt(const ListValue* list, size_t index, int* out_int) { std::string string_value; @@ -53,14 +60,67 @@ std::string GetIconURL(const Extension* extension, Extension::Icons icon, return default_val; } +// Extracts the promo parameter from the |path| generated by a ping on the NTP. +bool IsPromoActive(const std::string& path) { + std::vector<std::string> params; + base::SplitString(path, '+', ¶ms); + + CHECK(params.size() == 2); + + return params.at(1) == "true"; +} + } // namespace AppLauncherHandler::AppLauncherHandler(ExtensionsService* extension_service) - : extensions_service_(extension_service) { + : extensions_service_(extension_service), + promo_active_(false) { } AppLauncherHandler::~AppLauncherHandler() {} +// static +void AppLauncherHandler::CreateAppInfo(const Extension* extension, + ExtensionPrefs* extension_prefs, + DictionaryValue* value) { + value->Clear(); + value->SetString("id", extension->id()); + value->SetString("name", extension->name()); + value->SetString("description", extension->description()); + value->SetString("launch_url", extension->GetFullLaunchURL().spec()); + value->SetString("options_url", extension->options_url().spec()); + value->SetString("icon_big", GetIconURL( + extension, Extension::EXTENSION_ICON_LARGE, + "chrome://theme/IDR_APP_DEFAULT_ICON")); + value->SetString("icon_small", GetIconURL( + extension, Extension::EXTENSION_ICON_BITTY, + std::string("chrome://favicon/") + extension->GetFullLaunchURL().spec())); + value->SetInteger("launch_container", extension->launch_container()); + value->SetInteger("launch_type", + extension_prefs->GetLaunchType(extension->id())); + + int app_launch_index = extension_prefs->GetAppLaunchIndex(extension->id()); + if (app_launch_index == -1) { + // Make sure every app has a launch index (some predate the launch index). + app_launch_index = extension_prefs->GetNextAppLaunchIndex(); + extension_prefs->SetAppLaunchIndex(extension->id(), app_launch_index); + } + value->SetInteger("app_launch_index", app_launch_index); +} + +// static +bool AppLauncherHandler::HandlePing(const std::string& path) { + if (path.find(kLaunchWebStorePingURL) != std::string::npos) { + RecordWebStoreLaunch(IsPromoActive(path)); + return true; + } else if (path.find(kLaunchAppPingURL) != std::string::npos) { + RecordAppLaunch(IsPromoActive(path)); + return true; + } + + return false; +} + DOMMessageHandler* AppLauncherHandler::Attach(DOMUI* dom_ui) { // TODO(arv): Add initialization code to the Apps store etc. return DOMMessageHandler::Attach(dom_ui); @@ -102,35 +162,6 @@ void AppLauncherHandler::Observe(NotificationType type, } } -// static -void AppLauncherHandler::CreateAppInfo(const Extension* extension, - ExtensionPrefs* extension_prefs, - DictionaryValue* value) { - value->Clear(); - value->SetString("id", extension->id()); - value->SetString("name", extension->name()); - value->SetString("description", extension->description()); - value->SetString("launch_url", extension->GetFullLaunchURL().spec()); - value->SetString("options_url", extension->options_url().spec()); - value->SetString("icon_big", GetIconURL( - extension, Extension::EXTENSION_ICON_LARGE, - "chrome://theme/IDR_APP_DEFAULT_ICON")); - value->SetString("icon_small", GetIconURL( - extension, Extension::EXTENSION_ICON_BITTY, - std::string("chrome://favicon/") + extension->GetFullLaunchURL().spec())); - value->SetInteger("launch_container", extension->launch_container()); - value->SetInteger("launch_type", - extension_prefs->GetLaunchType(extension->id())); - - int app_launch_index = extension_prefs->GetAppLaunchIndex(extension->id()); - if (app_launch_index == -1) { - // Make sure every app has a launch index (some predate the launch index). - app_launch_index = extension_prefs->GetNextAppLaunchIndex(); - extension_prefs->SetAppLaunchIndex(extension->id(), app_launch_index); - } - value->SetInteger("app_launch_index", app_launch_index); -} - void AppLauncherHandler::FillAppDictionary(DictionaryValue* dictionary) { ListValue* list = new ListValue(); const ExtensionList* extensions = extensions_service_->extensions(); @@ -150,8 +181,10 @@ void AppLauncherHandler::FillAppDictionary(DictionaryValue* dictionary) { if (default_apps->ShouldShowPromo(extensions_service_->GetAppIds())) { dictionary->SetBoolean("showPromo", true); default_apps->DidShowPromo(); + promo_active_ = true; } else { dictionary->SetBoolean("showPromo", false); + promo_active_ = false; } bool showLauncher = @@ -220,6 +253,9 @@ void AppLauncherHandler::HandleLaunchApp(const ListValue* args) { if (new_contents != old_contents && browser->tab_count() > 1) browser->CloseTabContents(old_contents); + + if (extension_id != extension_misc::kWebStoreAppId) + RecordAppLaunch(promo_active_); } void AppLauncherHandler::HandleSetLaunchType(const ListValue* args) { @@ -240,19 +276,6 @@ void AppLauncherHandler::HandleSetLaunchType(const ListValue* args) { static_cast<ExtensionPrefs::LaunchType>(launch_type)); } -void AppLauncherHandler::AnimateAppIcon(const Extension* extension, - const gfx::Rect& rect) { - // We make this check for the case of minimized windows, unit tests, etc. - if (platform_util::IsVisible(dom_ui_->tab_contents()->GetNativeView()) && - Animation::ShouldRenderRichAnimation()) { -#if defined(OS_WIN) - AppLaunchedAnimation::Show(extension, rect); -#else - NOTIMPLEMENTED(); -#endif - } -} - void AppLauncherHandler::HandleUninstallApp(const ListValue* args) { std::string extension_id = WideToUTF8(ExtractStringValue(args)); const Extension* extension = extensions_service_->GetExtensionById( @@ -271,6 +294,9 @@ void AppLauncherHandler::HandleHideAppsPromo(const ListValue* args) { // If the user has intentionally hidden the promotion, we'll uninstall all the // default apps (we know the user hasn't installed any apps on their own at // this point, or the promotion wouldn't have been shown). + UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, + extension_misc::PROMO_CLOSE, + extension_misc::PROMO_BUCKET_BOUNDARY); DefaultApps* default_apps = extensions_service_->default_apps(); const ExtensionIdSet* app_ids = default_apps->GetDefaultApps(); DCHECK(*app_ids == extensions_service_->GetAppIds()); @@ -284,10 +310,25 @@ 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())); - return install_ui_.get(); +//static +void AppLauncherHandler::RecordWebStoreLaunch(bool promo_active) { + if (!promo_active) return; + + UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, + extension_misc::PROMO_LAUNCH_WEB_STORE, + extension_misc::PROMO_BUCKET_BOUNDARY); +} + +//static +void AppLauncherHandler::RecordAppLaunch(bool promo_active) { + // TODO(jstritar): record app launches that occur when the promo is not + // active using a different histogram. + + if (!promo_active) return; + + UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, + extension_misc::PROMO_LAUNCH_APP, + extension_misc::PROMO_BUCKET_BOUNDARY); } void AppLauncherHandler::InstallUIProceed() { @@ -308,3 +349,22 @@ void AppLauncherHandler::InstallUIProceed() { void AppLauncherHandler::InstallUIAbort() { extension_id_prompting_ = ""; } + +ExtensionInstallUI* AppLauncherHandler::GetExtensionInstallUI() { + if (!install_ui_.get()) + install_ui_.reset(new ExtensionInstallUI(dom_ui_->GetProfile())); + return install_ui_.get(); +} + +void AppLauncherHandler::AnimateAppIcon(const Extension* extension, + const gfx::Rect& rect) { + // We make this check for the case of minimized windows, unit tests, etc. + if (platform_util::IsVisible(dom_ui_->tab_contents()->GetNativeView()) && + Animation::ShouldRenderRichAnimation()) { +#if defined(OS_WIN) + AppLaunchedAnimation::Show(extension, rect); +#else + NOTIMPLEMENTED(); +#endif + } +} diff --git a/chrome/browser/dom_ui/app_launcher_handler.h b/chrome/browser/dom_ui/app_launcher_handler.h index 5a3478e..1ebeaf7 100644 --- a/chrome/browser/dom_ui/app_launcher_handler.h +++ b/chrome/browser/dom_ui/app_launcher_handler.h @@ -32,6 +32,14 @@ class AppLauncherHandler explicit AppLauncherHandler(ExtensionsService* extension_service); virtual ~AppLauncherHandler(); + // Populate a dictionary with the information from an extension. + static void CreateAppInfo(const Extension* extension, + ExtensionPrefs* extension_prefs, + DictionaryValue* value); + + // Callback for pings related to launching apps on the NTP. + static bool HandlePing(const std::string& path); + // DOMMessageHandler implementation. virtual DOMMessageHandler* Attach(DOMUI* dom_ui); virtual void RegisterMessages(); @@ -41,11 +49,6 @@ class AppLauncherHandler const NotificationSource& source, const NotificationDetails& details); - // Populate a dictionary with the information from an extension. - static void CreateAppInfo(const Extension* extension, - ExtensionPrefs* extension_prefs, - DictionaryValue* value); - // Populate the given dictionary with all installed app info. void FillAppDictionary(DictionaryValue* value); @@ -65,6 +68,14 @@ class AppLauncherHandler void HandleHideAppsPromo(const ListValue* args); private: + // Records a web store launch in the appropriate histograms. |promo_active| + // specifies if the web store promotion was active. + static void RecordWebStoreLaunch(bool promo_active); + + // Records an app launch in the appropriate histograms. |promo_active| + // specifies if the web store promotion was active. + static void RecordAppLaunch(bool promo_active); + // ExtensionInstallUI::Delegate implementation, used for receiving // notification about uninstall confirmation dialog selections. virtual void InstallUIProceed(); @@ -94,6 +105,9 @@ class AppLauncherHandler // The id of the extension we are prompting the user about. std::string extension_id_prompting_; + // Whether the promo is currently being shown. + bool promo_active_; + DISALLOW_COPY_AND_ASSIGN(AppLauncherHandler); }; diff --git a/chrome/browser/dom_ui/new_tab_ui.cc b/chrome/browser/dom_ui/new_tab_ui.cc index a662102..e102471 100644 --- a/chrome/browser/dom_ui/new_tab_ui.cc +++ b/chrome/browser/dom_ui/new_tab_ui.cc @@ -620,7 +620,9 @@ void NewTabUI::NewTabHTMLSource::StartDataRequest(const std::string& path, int request_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (!path.empty() && path[0] != '#') { + if (AppLauncherHandler::HandlePing(path)) { + return; + } else if (!path.empty() && path[0] != '#') { // A path under new-tab was requested; it's likely a bad relative // URL from the new tab page, but in any case it's an error. NOTREACHED(); diff --git a/chrome/browser/extensions/default_apps.cc b/chrome/browser/extensions/default_apps.cc index 4cf313b..9dae119 100644 --- a/chrome/browser/extensions/default_apps.cc +++ b/chrome/browser/extensions/default_apps.cc @@ -5,6 +5,7 @@ #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" @@ -88,10 +89,15 @@ void DefaultApps::DidShowPromo() { return; } - if (promo_counter < kAppsPromoCounterMax) + if (promo_counter < kAppsPromoCounterMax) { + if (promo_counter + 1 == kAppsPromoCounterMax) + UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, + extension_misc::PROMO_EXPIRE, + extension_misc::PROMO_BUCKET_BOUNDARY); SetPromoCounter(++promo_counter); - else + } else { SetPromoHidden(); + } } void DefaultApps::SetPromoHidden() { diff --git a/chrome/browser/resources/new_new_tab.js b/chrome/browser/resources/new_new_tab.js index 6b3be4a..89deeef 100644 --- a/chrome/browser/resources/new_new_tab.js +++ b/chrome/browser/resources/new_new_tab.js @@ -1206,7 +1206,10 @@ function isDoneLoading() { document.addEventListener('DOMContentLoaded', function() { var promoText1 = $('apps-promo-text1'); promoText1.innerHTML = promoText1.textContent; - promoText1.querySelector('a').href = localStrings.getString('web_store_url'); + + var promoLink = promoText1.querySelector('a'); + promoLink.id = 'apps-promo-link'; + promoLink.href = localStrings.getString('web_store_url'); $('apps-promo-hide').addEventListener('click', function() { chrome.send('hideAppsPromo', []); diff --git a/chrome/browser/resources/ntp/apps.js b/chrome/browser/resources/ntp/apps.js index 81d7eb0..7069231 100644 --- a/chrome/browser/resources/ntp/apps.js +++ b/chrome/browser/resources/ntp/apps.js @@ -6,19 +6,28 @@ var MAX_APPS_PER_ROW = []; MAX_APPS_PER_ROW[LayoutMode.SMALL] = 4; MAX_APPS_PER_ROW[LayoutMode.NORMAL] = 6; +// The URL prefix used in the app link 'ping' attributes. +var PING_APP_LAUNCH_PREFIX = 'record-app-launch'; + +// The URL prefix used in the webstore link 'ping' attributes. +var PING_WEBSTORE_LAUNCH_PREFIX = 'record-webstore-launch'; + function getAppsCallback(data) { logEvent('received apps'); var appsSection = $('apps'); var appsSectionContent = $('apps-content'); var appsMiniview = appsSection.getElementsByClassName('miniview')[0]; var appsPromo = $('apps-promo'); + var appsPromoPing = PING_WEBSTORE_LAUNCH_PREFIX + '+' + data.showPromo; var webStoreEntry; appsMiniview.textContent = ''; appsSectionContent.textContent = ''; + apps.showPromo = data.showPromo; + data.apps.sort(function(a,b) { - return a.app_launch_index - b.app_launch_index + return a.app_launch_index - b.app_launch_index; }); clearClosedMenu(apps.menu); @@ -31,6 +40,7 @@ function getAppsCallback(data) { }); webStoreEntry = apps.createWebStoreElement(); + webStoreEntry.querySelector('a').setAttribute('ping', appsPromoPing); appsSectionContent.appendChild(webStoreEntry); data.apps.slice(0, MAX_MINIVIEW_ITEMS).forEach(function(app) { @@ -49,6 +59,7 @@ function getAppsCallback(data) { document.documentElement.classList.add('apps-promo-visible'); else document.documentElement.classList.remove('apps-promo-visible'); + $('apps-promo-link').setAttribute('ping', appsPromoPing); maybeDoneLoading(); if (data.apps.length > 0 && isDoneLoading()) { @@ -227,11 +238,14 @@ var apps = (function() { menu: $('apps-menu'), + showPromo: false, + createElement: function(app) { var div = createElement(app); var a = div.firstChild; a.onclick = handleClick; + a.setAttribute('ping', PING_APP_LAUNCH_PREFIX + '+' + this.showPromo); a.style.backgroundImage = url(app['icon_big']); if (hashParams['app-id'] == app['id']) { div.setAttribute('new', 'new'); @@ -271,6 +285,7 @@ var apps = (function() { a.textContent = app['name']; a.href = app['launch_url']; a.onclick = handleClick; + a.setAttribute('ping', PING_APP_LAUNCH_PREFIX + '+' + this.showPromo); a.style.backgroundImage = url(app['icon_small']); a.className = 'item'; span.appendChild(a); @@ -286,6 +301,7 @@ var apps = (function() { a.textContent = app['name']; a.href = app['launch_url']; a.onclick = handleClick; + a.setAttribute('ping', PING_APP_LAUNCH_PREFIX + '+' + this.showPromo); a.style.backgroundImage = url(app['icon_small']); a.className = 'item'; return a; diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc index 5e418b5..9516f39 100644 --- a/chrome/common/extensions/extension_constants.cc +++ b/chrome/common/extensions/extension_constants.cc @@ -304,4 +304,5 @@ const char* kDecodedMessageCatalogsFilename = "DECODED_MESSAGE_CATALOGS"; namespace extension_misc { const char* kBookmarkManagerId = "eemcgdkfndhakfknompkggombfjjjeno"; const char* kWebStoreAppId = "ahfgeienlihckogmohjhadlkjgocpleb"; +const char* kAppsPromoHistogram = "Extensions.AppsPromo"; } diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h index 332f386..a32231e 100644 --- a/chrome/common/extensions/extension_constants.h +++ b/chrome/common/extensions/extension_constants.h @@ -239,6 +239,18 @@ namespace extension_misc { LAUNCH_PANEL, LAUNCH_TAB }; + + // The name of the apps promo histogram. + extern const char* kAppsPromoHistogram; + + // The buckets used in the apps promo histogram. + enum AppsPromoBuckets { + PROMO_LAUNCH_APP, + PROMO_LAUNCH_WEB_STORE, + PROMO_CLOSE, + PROMO_EXPIRE, + PROMO_BUCKET_BOUNDARY = PROMO_EXPIRE + 1 + }; } // extension_misc #endif // CHROME_COMMON_EXTENSIONS_EXTENSION_CONSTANTS_H_ |