summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-12 21:59:48 +0000
committerjstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-12 21:59:48 +0000
commitfd131723b6ff17cc408920b22f8de08575dfc91d (patch)
tree67fb4ced778be29e8cbde52ef6e12c9dc5ada89d
parent4790db572ffcb4f10ec64abaa77696e8ee6ace03 (diff)
downloadchromium_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.cc154
-rw-r--r--chrome/browser/dom_ui/app_launcher_handler.h24
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.cc4
-rw-r--r--chrome/browser/extensions/default_apps.cc10
-rw-r--r--chrome/browser/resources/new_new_tab.js5
-rw-r--r--chrome/browser/resources/ntp/apps.js18
-rw-r--r--chrome/common/extensions/extension_constants.cc1
-rw-r--r--chrome/common/extensions/extension_constants.h12
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, '+', &params);
+
+ 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_