Commit c17ca9d2 authored by tapted@chromium.org's avatar tapted@chromium.org

UMA for Windows 8 Secondary Tile pinning/unpinning user actions

triggered from hotdog -> Bookmarks when in Metro mode.

To perform the metrics recording, this CL includes changes
to provide a callback mechanism for the asynchronous tile
creation in metro_driver.dll to report back the result of
the use gesture to the browser process. Note that both
metro_driver.dll and chrome.dll link statically to base, so
they have distinct data segments holding UMA histograms,
hence the callback.

BUG=160840
TEST=In Windows 8 Metro Mode, Hotdog -> Bookmarks -> Pin to start page:
 - pin and cancel (escape/click/touch off popup)
 - pin and confirm
 - (when pinned) unpin and cancel
 - unpin and confirm
Above should all work (and report UMA histogram data).

Review URL: https://chromiumcodereview.appspot.com/11280112

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170916 0039d316-1c4b-4281-b951-d872f2087c98
parent 1b6d1307
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include <wpcapi.h> #include <wpcapi.h>
#include "base/base_export.h" #include "base/base_export.h"
#include "base/callback.h"
#include "base/file_path.h"
#include "base/string16.h" #include "base/string16.h"
namespace base { namespace base {
...@@ -36,6 +38,26 @@ enum MetroPreviousExecutionState { ...@@ -36,6 +38,26 @@ enum MetroPreviousExecutionState {
LASTEXECUTIONSTATE, LASTEXECUTIONSTATE,
}; };
// Enum values for UMA histogram reporting of site-specific tile pinning.
// TODO(tapted): Move this to win8/util when ready (http://crbug.com/160288).
enum MetroSecondaryTilePinUmaResult {
METRO_PIN_STATE_NONE,
METRO_PIN_INITIATED,
METRO_PIN_LOGO_READY,
METRO_PIN_REQUEST_SHOW_ERROR,
METRO_PIN_RESULT_CANCEL,
METRO_PIN_RESULT_OK,
METRO_PIN_RESULT_OTHER,
METRO_PIN_RESULT_ERROR,
METRO_UNPIN_INITIATED,
METRO_UNPIN_REQUEST_SHOW_ERROR,
METRO_UNPIN_RESULT_CANCEL,
METRO_UNPIN_RESULT_OK,
METRO_UNPIN_RESULT_OTHER,
METRO_UNPIN_RESULT_ERROR,
METRO_PIN_STATE_LIMIT
};
// Contains information about the currently displayed tab in metro mode. // Contains information about the currently displayed tab in metro mode.
struct CurrentTabInfo { struct CurrentTabInfo {
wchar_t* title; wchar_t* title;
...@@ -97,6 +119,23 @@ typedef void (*MetroNotification)(const char* origin_url, ...@@ -97,6 +119,23 @@ typedef void (*MetroNotification)(const char* origin_url,
MetroNotificationClickedHandler handler, MetroNotificationClickedHandler handler,
const wchar_t* handler_context); const wchar_t* handler_context);
// Callback for UMA invoked by Metro Pin and UnPin functions after user gesture.
typedef base::Callback<void(MetroSecondaryTilePinUmaResult)>
MetroPinUmaResultCallback;
// Function to pin a site-specific tile (bookmark) to the start screen.
typedef void (*MetroPinToStartScreen)(
const string16& tile_id,
const string16& title,
const string16& url,
const FilePath& logo_path,
const MetroPinUmaResultCallback& callback);
// Function to un-pin a site-specific tile (bookmark) from the start screen.
typedef void (*MetroUnPinFromStartScreen)(
const string16& title_id,
const MetroPinUmaResultCallback& callback);
} // namespace win } // namespace win
} // namespace base } // namespace base
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/ref_counted_memory.h" #include "base/memory/ref_counted_memory.h"
#include "base/metrics/histogram.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/string_number_conversions.h" #include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h" #include "base/utf_string_conversions.h"
...@@ -40,6 +41,9 @@ DEFINE_WEB_CONTENTS_USER_DATA_KEY(MetroPinTabHelper) ...@@ -40,6 +41,9 @@ DEFINE_WEB_CONTENTS_USER_DATA_KEY(MetroPinTabHelper)
namespace { namespace {
// Histogram name for site-specific tile pinning metrics.
const char kMetroPinMetric[] = "Metro.SecondaryTilePin";
// Generate an ID for the tile based on |url_str|. The ID is simply a hash of // Generate an ID for the tile based on |url_str|. The ID is simply a hash of
// the URL. // the URL.
string16 GenerateTileId(const string16& url_str) { string16 GenerateTileId(const string16& url_str) {
...@@ -158,6 +162,14 @@ bool GetPathToBackupLogo(const FilePath& logo_dir, ...@@ -158,6 +162,14 @@ bool GetPathToBackupLogo(const FilePath& logo_dir,
return file_util::CopyFile(default_logo_path, *logo_path); return file_util::CopyFile(default_logo_path, *logo_path);
} }
// UMA reporting callback for site-specific secondary tile creation.
void PinPageReportUmaCallback(
base::win::MetroSecondaryTilePinUmaResult result) {
UMA_HISTOGRAM_ENUMERATION(kMetroPinMetric,
result,
base::win::METRO_PIN_STATE_LIMIT);
}
// The PinPageTaskRunner class performs the necessary FILE thread actions to // The PinPageTaskRunner class performs the necessary FILE thread actions to
// pin a page, such as generating or copying the tile image file. When it // pin a page, such as generating or copying the tile image file. When it
// has performed these actions it will send the tile creation request to the // has performed these actions it will send the tile creation request to the
...@@ -219,21 +231,27 @@ void PinPageTaskRunner::RunOnFileThread() { ...@@ -219,21 +231,27 @@ void PinPageTaskRunner::RunOnFileThread() {
return; return;
} }
UMA_HISTOGRAM_ENUMERATION(kMetroPinMetric,
base::win::METRO_PIN_LOGO_READY,
base::win::METRO_PIN_STATE_LIMIT);
HMODULE metro_module = base::win::GetMetroModule(); HMODULE metro_module = base::win::GetMetroModule();
if (!metro_module) if (!metro_module)
return; return;
typedef void (*MetroPinToStartScreen)(const string16&, const string16&, base::win::MetroPinToStartScreen metro_pin_to_start_screen =
const string16&, const FilePath&); reinterpret_cast<base::win::MetroPinToStartScreen>(
MetroPinToStartScreen metro_pin_to_start_screen =
reinterpret_cast<MetroPinToStartScreen>(
::GetProcAddress(metro_module, "MetroPinToStartScreen")); ::GetProcAddress(metro_module, "MetroPinToStartScreen"));
if (!metro_pin_to_start_screen) { if (!metro_pin_to_start_screen) {
NOTREACHED(); NOTREACHED();
return; return;
} }
metro_pin_to_start_screen(tile_id, title_, url_, logo_path); metro_pin_to_start_screen(tile_id,
title_,
url_,
logo_path,
base::Bind(&PinPageReportUmaCallback));
} }
} // namespace } // namespace
...@@ -378,10 +396,16 @@ bool MetroPinTabHelper::IsPinned() const { ...@@ -378,10 +396,16 @@ bool MetroPinTabHelper::IsPinned() const {
void MetroPinTabHelper::TogglePinnedToStartScreen() { void MetroPinTabHelper::TogglePinnedToStartScreen() {
if (IsPinned()) { if (IsPinned()) {
UMA_HISTOGRAM_ENUMERATION(kMetroPinMetric,
base::win::METRO_UNPIN_INITIATED,
base::win::METRO_PIN_STATE_LIMIT);
UnPinPageFromStartScreen(); UnPinPageFromStartScreen();
return; return;
} }
UMA_HISTOGRAM_ENUMERATION(kMetroPinMetric,
base::win::METRO_PIN_INITIATED,
base::win::METRO_PIN_STATE_LIMIT);
GURL url = web_contents()->GetURL(); GURL url = web_contents()->GetURL();
string16 url_str = UTF8ToUTF16(url.spec()); string16 url_str = UTF8ToUTF16(url.spec());
string16 title = web_contents()->GetTitle(); string16 title = web_contents()->GetTitle();
...@@ -445,9 +469,8 @@ void MetroPinTabHelper::UnPinPageFromStartScreen() { ...@@ -445,9 +469,8 @@ void MetroPinTabHelper::UnPinPageFromStartScreen() {
if (!metro_module) if (!metro_module)
return; return;
typedef void (*MetroUnPinFromStartScreen)(const string16&); base::win::MetroUnPinFromStartScreen metro_un_pin_from_start_screen =
MetroUnPinFromStartScreen metro_un_pin_from_start_screen = reinterpret_cast<base::win::MetroUnPinFromStartScreen>(
reinterpret_cast<MetroUnPinFromStartScreen>(
::GetProcAddress(metro_module, "MetroUnPinFromStartScreen")); ::GetProcAddress(metro_module, "MetroUnPinFromStartScreen"));
if (!metro_un_pin_from_start_screen) { if (!metro_un_pin_from_start_screen) {
NOTREACHED(); NOTREACHED();
...@@ -456,7 +479,8 @@ void MetroPinTabHelper::UnPinPageFromStartScreen() { ...@@ -456,7 +479,8 @@ void MetroPinTabHelper::UnPinPageFromStartScreen() {
GURL url = web_contents()->GetURL(); GURL url = web_contents()->GetURL();
string16 tile_id = GenerateTileId(UTF8ToUTF16(url.spec())); string16 tile_id = GenerateTileId(UTF8ToUTF16(url.spec()));
metro_un_pin_from_start_screen(tile_id); metro_un_pin_from_start_screen(tile_id,
base::Bind(&PinPageReportUmaCallback));
} }
void MetroPinTabHelper::FaviconDownloaderFinished() { void MetroPinTabHelper::FaviconDownloaderFinished() {
......
...@@ -305,20 +305,6 @@ void FlipFrameWindowsInternal() { ...@@ -305,20 +305,6 @@ void FlipFrameWindowsInternal() {
} // namespace } // namespace
HRESULT ChromeAppView::TileRequestCreateDone(
winfoundtn::IAsyncOperation<bool>* async,
AsyncStatus status) {
if (status == Completed) {
unsigned char result;
CheckHR(async->GetResults(&result));
DVLOG(1) << __FUNCTION__ << " result " << static_cast<int>(result);
} else {
LOG(ERROR) << __FUNCTION__ << " Unexpected async status " << status;
}
return S_OK;
}
void ChromeAppView::DisplayNotification( void ChromeAppView::DisplayNotification(
const ToastNotificationHandler::DesktopNotification& notification) { const ToastNotificationHandler::DesktopNotification& notification) {
DVLOG(1) << __FUNCTION__; DVLOG(1) << __FUNCTION__;
......
...@@ -45,9 +45,6 @@ class ChromeAppView ...@@ -45,9 +45,6 @@ class ChromeAppView
static LRESULT CALLBACK CoreWindowProc(HWND window, UINT message, WPARAM wp, static LRESULT CALLBACK CoreWindowProc(HWND window, UINT message, WPARAM wp,
LPARAM lp); LPARAM lp);
HRESULT TileRequestCreateDone(winfoundtn::IAsyncOperation<bool>* async,
AsyncStatus status);
bool osk_visible_notification_received() const { bool osk_visible_notification_received() const {
return osk_visible_notification_received_; return osk_visible_notification_received_;
} }
......
...@@ -16,7 +16,80 @@ ...@@ -16,7 +16,80 @@
namespace { namespace {
void DeleteTileFromStartScreen(const string16& tile_id) { using base::win::MetroPinUmaResultCallback;
// Callback for asynchronous pin requests.
class TileRequestCompleter {
public:
enum PinType {
PIN,
UNPIN
};
TileRequestCompleter(PinType type, const MetroPinUmaResultCallback& callback)
: type_(type), callback_(callback) {}
void Complete(mswr::ComPtr<winfoundtn::IAsyncOperation<bool>>& completion);
private:
// Callback that responds to user input on the pin request pop-up. This will
// run |callback_|, then delete |this| before returning.
HRESULT Respond(winfoundtn::IAsyncOperation<bool>* async,
AsyncStatus status);
PinType type_;
MetroPinUmaResultCallback callback_;
};
void TileRequestCompleter::Complete(
mswr::ComPtr<winfoundtn::IAsyncOperation<bool>>& completion) {
typedef winfoundtn::IAsyncOperationCompletedHandler<bool> RequestDoneType;
mswr::ComPtr<RequestDoneType> handler(mswr::Callback<RequestDoneType>(
this, &TileRequestCompleter::Respond));
DCHECK(handler.Get() != NULL);
HRESULT hr = completion->put_Completed(handler.Get());
CheckHR(hr, "Failed to put_Completed");
}
HRESULT TileRequestCompleter::Respond(winfoundtn::IAsyncOperation<bool>* async,
AsyncStatus status) {
base::win::MetroSecondaryTilePinUmaResult pin_state =
base::win::METRO_PIN_STATE_NONE;
if (status == Completed) {
unsigned char result;
CheckHR(async->GetResults(&result));
LOG(INFO) << __FUNCTION__ << " result " << static_cast<int>(result);
switch (result) {
case 0:
pin_state = type_ == PIN ?
base::win::METRO_PIN_RESULT_CANCEL :
base::win::METRO_UNPIN_RESULT_CANCEL;
break;
case 1:
pin_state = type_ == PIN ?
base::win::METRO_PIN_RESULT_OK :
base::win::METRO_UNPIN_RESULT_OK;
break;
default:
pin_state = type_ == PIN ?
base::win::METRO_PIN_RESULT_OTHER :
base::win::METRO_UNPIN_RESULT_OTHER;
break;
}
} else {
LOG(ERROR) << __FUNCTION__ << " Unexpected async status " << status;
pin_state = type_ == PIN ?
base::win::METRO_PIN_RESULT_ERROR :
base::win::METRO_UNPIN_RESULT_ERROR;
}
callback_.Run(pin_state);
delete this;
return S_OK;
}
void DeleteTileFromStartScreen(const string16& tile_id,
const MetroPinUmaResultCallback& callback) {
DVLOG(1) << __FUNCTION__; DVLOG(1) << __FUNCTION__;
mswr::ComPtr<winui::StartScreen::ISecondaryTileFactory> tile_factory; mswr::ComPtr<winui::StartScreen::ISecondaryTileFactory> tile_factory;
HRESULT hr = winrt_utils::CreateActivationFactory( HRESULT hr = winrt_utils::CreateActivationFactory(
...@@ -35,18 +108,23 @@ void DeleteTileFromStartScreen(const string16& tile_id) { ...@@ -35,18 +108,23 @@ void DeleteTileFromStartScreen(const string16& tile_id) {
hr = tile->RequestDeleteAsync(completion.GetAddressOf()); hr = tile->RequestDeleteAsync(completion.GetAddressOf());
CheckHR(hr, "RequestDeleteAsync failed"); CheckHR(hr, "RequestDeleteAsync failed");
typedef winfoundtn::IAsyncOperationCompletedHandler<bool> RequestDoneType; if (FAILED(hr)) {
mswr::ComPtr<RequestDoneType> handler(mswr::Callback<RequestDoneType>( callback.Run(base::win::METRO_UNPIN_REQUEST_SHOW_ERROR);
globals.view, &ChromeAppView::TileRequestCreateDone)); return;
DCHECK(handler.Get() != NULL); }
hr = completion->put_Completed(handler.Get());
CheckHR(hr, "Failed to put_Completed"); // Deleted in TileRequestCompleter::Respond when the async operation
// completes.
TileRequestCompleter* completer =
new TileRequestCompleter(TileRequestCompleter::UNPIN, callback);
completer->Complete(completion);
} }
void CreateTileOnStartScreen(const string16& tile_id, void CreateTileOnStartScreen(const string16& tile_id,
const string16& title_str, const string16& title_str,
const string16& url_str, const string16& url_str,
const FilePath& logo_path) { const FilePath& logo_path,
const MetroPinUmaResultCallback& callback) {
VLOG(1) << __FUNCTION__; VLOG(1) << __FUNCTION__;
mswr::ComPtr<winui::StartScreen::ISecondaryTileFactory> tile_factory; mswr::ComPtr<winui::StartScreen::ISecondaryTileFactory> tile_factory;
...@@ -99,12 +177,16 @@ void CreateTileOnStartScreen(const string16& tile_id, ...@@ -99,12 +177,16 @@ void CreateTileOnStartScreen(const string16& tile_id,
hr = tile->RequestCreateAsync(completion.GetAddressOf()); hr = tile->RequestCreateAsync(completion.GetAddressOf());
CheckHR(hr, "RequestCreateAsync failed"); CheckHR(hr, "RequestCreateAsync failed");
typedef winfoundtn::IAsyncOperationCompletedHandler<bool> RequestDoneType; if (FAILED(hr)) {
mswr::ComPtr<RequestDoneType> handler(mswr::Callback<RequestDoneType>( callback.Run(base::win::METRO_PIN_REQUEST_SHOW_ERROR);
globals.view, &ChromeAppView::TileRequestCreateDone)); return;
DCHECK(handler.Get() != NULL); }
hr = completion->put_Completed(handler.Get());
CheckHR(hr, "Failed to put_Completed"); // Deleted in TileRequestCompleter::Respond when the async operation
// completes.
TileRequestCompleter* completer =
new TileRequestCompleter(TileRequestCompleter::PIN, callback);
completer->Complete(completion);
} }
} // namespace } // namespace
...@@ -122,19 +204,24 @@ BOOL MetroIsPinnedToStartScreen(const string16& tile_id) { ...@@ -122,19 +204,24 @@ BOOL MetroIsPinnedToStartScreen(const string16& tile_id) {
return exists; return exists;
} }
void MetroUnPinFromStartScreen(const string16& tile_id) { void MetroUnPinFromStartScreen(const string16& tile_id,
const MetroPinUmaResultCallback& callback) {
globals.appview_msg_loop->PostTask( globals.appview_msg_loop->PostTask(
FROM_HERE, base::Bind(&DeleteTileFromStartScreen, tile_id)); FROM_HERE, base::Bind(&DeleteTileFromStartScreen,
tile_id,
callback));
} }
void MetroPinToStartScreen(const string16& tile_id, void MetroPinToStartScreen(const string16& tile_id,
const string16& title, const string16& title,
const string16& url, const string16& url,
const FilePath& logo_path) { const FilePath& logo_path,
const MetroPinUmaResultCallback& callback) {
globals.appview_msg_loop->PostTask( globals.appview_msg_loop->PostTask(
FROM_HERE, base::Bind(&CreateTileOnStartScreen, FROM_HERE, base::Bind(&CreateTileOnStartScreen,
tile_id, tile_id,
title, title,
url, url,
logo_path)); logo_path,
callback));
} }
...@@ -6,18 +6,22 @@ ...@@ -6,18 +6,22 @@
#include "base/file_path.h" #include "base/file_path.h"
#include "base/string16.h" #include "base/string16.h"
#include "base/win/metro.h"
extern "C" __declspec(dllexport) extern "C" __declspec(dllexport)
BOOL MetroIsPinnedToStartScreen(const string16& tile_id); BOOL MetroIsPinnedToStartScreen(const string16& tile_id);
extern "C" __declspec(dllexport) extern "C" __declspec(dllexport)
void MetroUnPinFromStartScreen(const string16& tile_id); void MetroUnPinFromStartScreen(
const string16& tile_id,
const base::win::MetroPinUmaResultCallback& callback);
extern "C" __declspec(dllexport) extern "C" __declspec(dllexport)
void MetroPinToStartScreen(const string16& tile_id, void MetroPinToStartScreen(
const string16& title, const string16& tile_id,
const string16& url, const string16& title,
const FilePath& logo_path); const string16& url,
const FilePath& logo_path,
const base::win::MetroPinUmaResultCallback& callback);
#endif // CHROME_BROWSER_UI_METRO_DRIVER_SECONDARY_TILE_H_ #endif // CHROME_BROWSER_UI_METRO_DRIVER_SECONDARY_TILE_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment