Commit ceb9035f authored by Kyle Horimoto's avatar Kyle Horimoto Committed by Chromium LUCI CQ

[CrOS PhoneHub] Create UserActionRecorder which logs 28DA usage

This class logs metrics when core Phone Hub functionality is used,
which will be used to log our 28DA user count.

Note that this class is not actually instantiated; a follow-up CL
creates an instance of this class and calls its instance functions.

Bug: 1150634, 1106937
Change-Id: I224a1dd25d5d7f48b601392843d1a31a72d6743c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2576474Reviewed-by: default avatarRobert Kaplow <rkaplow@chromium.org>
Reviewed-by: default avatarRegan Hsu <hsuregan@chromium.org>
Commit-Queue: Kyle Horimoto <khorimoto@chromium.org>
Auto-Submit: Kyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#835664}
parent 43591904
...@@ -80,6 +80,9 @@ static_library("phonehub") { ...@@ -80,6 +80,9 @@ static_library("phonehub") {
"tether_controller.h", "tether_controller.h",
"tether_controller_impl.cc", "tether_controller_impl.cc",
"tether_controller_impl.h", "tether_controller_impl.h",
"user_action_recorder.h",
"user_action_recorder_impl.cc",
"user_action_recorder_impl.h",
"util/histogram_util.cc", "util/histogram_util.cc",
"util/histogram_util.h", "util/histogram_util.h",
] ]
...@@ -127,6 +130,8 @@ static_library("debug") { ...@@ -127,6 +130,8 @@ static_library("debug") {
"fake_phone_hub_manager.h", "fake_phone_hub_manager.h",
"fake_tether_controller.cc", "fake_tether_controller.cc",
"fake_tether_controller.h", "fake_tether_controller.h",
"fake_user_action_recorder.cc",
"fake_user_action_recorder.h",
] ]
public_deps = [ ":phonehub" ] public_deps = [ ":phonehub" ]
...@@ -184,6 +189,7 @@ source_set("unit_tests") { ...@@ -184,6 +189,7 @@ source_set("unit_tests") {
"phone_status_model_unittest.cc", "phone_status_model_unittest.cc",
"phone_status_processor_unittest.cc", "phone_status_processor_unittest.cc",
"tether_controller_impl_unittest.cc", "tether_controller_impl_unittest.cc",
"user_action_recorder_impl_unittest.cc",
] ]
deps = [ deps = [
......
// Copyright 2020 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 "chromeos/components/phonehub/fake_user_action_recorder.h"
namespace chromeos {
namespace phonehub {
FakeUserActionRecorder::FakeUserActionRecorder() = default;
FakeUserActionRecorder::~FakeUserActionRecorder() = default;
void FakeUserActionRecorder::RecordUiOpened() {
++num_ui_opened_events_;
}
void FakeUserActionRecorder::RecordTetherConnectionAttempt() {
++num_tether_attempts_;
}
void FakeUserActionRecorder::RecordDndAttempt() {
++num_dnd_attempts_;
}
void FakeUserActionRecorder::RecordFindMyDeviceAttempt() {
++num_find_my_device_attempts_;
}
void FakeUserActionRecorder::RecordBrowserTabOpened() {
++num_browser_tabs_opened_;
}
void FakeUserActionRecorder::RecordNotificationDismissAttempt() {
++num_notification_dismissals_;
}
void FakeUserActionRecorder::RecordNotificationReplyAttempt() {
++num_notification_replies_;
}
} // namespace phonehub
} // namespace chromeos
// Copyright 2020 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 CHROMEOS_COMPONENTS_PHONEHUB_FAKE_USER_ACTION_RECORDER_H_
#define CHROMEOS_COMPONENTS_PHONEHUB_FAKE_USER_ACTION_RECORDER_H_
#include <stddef.h>
#include "chromeos/components/phonehub/user_action_recorder.h"
namespace chromeos {
namespace phonehub {
class FakeUserActionRecorder : public UserActionRecorder {
public:
FakeUserActionRecorder();
~FakeUserActionRecorder() override;
size_t num_ui_opened_events() const { return num_ui_opened_events_; }
size_t num_tether_attempts() const { return num_tether_attempts_; }
size_t num_dnd_attempts() const { return num_dnd_attempts_; }
size_t num_find_my_device_attempts() const {
return num_find_my_device_attempts_;
}
size_t num_browser_tabs_opened() const { return num_browser_tabs_opened_; }
size_t num_notification_dismissals() const {
return num_notification_dismissals_;
}
size_t num_notification_replies() const { return num_notification_replies_; }
private:
// UserActionRecorder:
void RecordUiOpened() override;
void RecordTetherConnectionAttempt() override;
void RecordDndAttempt() override;
void RecordFindMyDeviceAttempt() override;
void RecordBrowserTabOpened() override;
void RecordNotificationDismissAttempt() override;
void RecordNotificationReplyAttempt() override;
size_t num_ui_opened_events_ = 0u;
size_t num_tether_attempts_ = 0u;
size_t num_dnd_attempts_ = 0u;
size_t num_find_my_device_attempts_ = 0u;
size_t num_browser_tabs_opened_ = 0u;
size_t num_notification_dismissals_ = 0u;
size_t num_notification_replies_ = 0u;
};
} // namespace phonehub
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_PHONEHUB_FAKE_USER_ACTION_RECORDER_H_
// Copyright 2020 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 CHROMEOS_COMPONENTS_PHONEHUB_USER_ACTION_RECORDER_H_
#define CHROMEOS_COMPONENTS_PHONEHUB_USER_ACTION_RECORDER_H_
namespace chromeos {
namespace phonehub {
// Records actions that a user may take via Phone Hub.
class UserActionRecorder {
public:
virtual ~UserActionRecorder() = default;
// Records that the Phone Hub UI has been opened.
virtual void RecordUiOpened() = 0;
// Records that an Instant Tethering connection has been attempted via the
// Phone Hub UI.
virtual void RecordTetherConnectionAttempt() = 0;
// Records that an attempt to change the Do Not Disturb status has been
// attempted via the Phone Hub UI.
virtual void RecordDndAttempt() = 0;
// Records that an attempt to start or stop ringing the user's phone via the
// Find My Device feature has been attempted via the Phone Hub UI.
virtual void RecordFindMyDeviceAttempt() = 0;
// Records that the user has opened a browser tab synced via the "task
// continuation" feature.
virtual void RecordBrowserTabOpened() = 0;
// Records that an attempt to dismiss a notification generated via Phone Hub
// has been attempted.
virtual void RecordNotificationDismissAttempt() = 0;
// Records that an attempt to reply to a notification generated via Phone Hub
// has been attempted.
virtual void RecordNotificationReplyAttempt() = 0;
protected:
UserActionRecorder() = default;
};
} // namespace phonehub
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_PHONEHUB_USER_ACTION_RECORDER_H_
// Copyright 2020 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 "chromeos/components/phonehub/user_action_recorder_impl.h"
#include "base/metrics/histogram_functions.h"
namespace chromeos {
namespace phonehub {
UserActionRecorderImpl::UserActionRecorderImpl() = default;
UserActionRecorderImpl::~UserActionRecorderImpl() = default;
void UserActionRecorderImpl::RecordUiOpened() {
HandleUserAction(UserAction::kUiOpened);
}
void UserActionRecorderImpl::RecordTetherConnectionAttempt() {
HandleUserAction(UserAction::kTether);
}
void UserActionRecorderImpl::RecordDndAttempt() {
HandleUserAction(UserAction::kDnd);
}
void UserActionRecorderImpl::RecordFindMyDeviceAttempt() {
HandleUserAction(UserAction::kFindMyDevice);
}
void UserActionRecorderImpl::RecordBrowserTabOpened() {
HandleUserAction(UserAction::kBrowserTab);
}
void UserActionRecorderImpl::RecordNotificationDismissAttempt() {
HandleUserAction(UserAction::kNotificationDismissal);
}
void UserActionRecorderImpl::RecordNotificationReplyAttempt() {
HandleUserAction(UserAction::kNotificationReply);
}
void UserActionRecorderImpl::HandleUserAction(UserAction action) {
base::UmaHistogramEnumeration("PhoneHub.CompletedUserAction", action);
}
} // namespace phonehub
} // namespace chromeos
// Copyright 2020 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 CHROMEOS_COMPONENTS_PHONEHUB_USER_ACTION_RECORDER_IMPL_H_
#define CHROMEOS_COMPONENTS_PHONEHUB_USER_ACTION_RECORDER_IMPL_H_
#include <memory>
#include "base/gtest_prod_util.h"
#include "base/time/time.h"
#include "chromeos/components/phonehub/user_action_recorder.h"
namespace chromeos {
namespace phonehub {
// UserActionRecorder implementation which generates engagement metrics for
// Phone Hub.
class UserActionRecorderImpl : public UserActionRecorder {
public:
UserActionRecorderImpl();
~UserActionRecorderImpl() override;
private:
friend class UserActionRecorderImplTest;
FRIEND_TEST_ALL_PREFIXES(UserActionRecorderImplTest, Enabled_RecordActions);
// Types of user actions; numerical value should not be reused or reordered
// since this enum is used in metrics.
enum class UserAction {
kUiOpened = 0,
kTether = 1,
kDnd = 2,
kFindMyDevice = 3,
kBrowserTab = 4,
kNotificationDismissal = 5,
kNotificationReply = 6,
kMaxValue = kNotificationReply,
};
// UserActionRecorder:
void RecordUiOpened() override;
void RecordTetherConnectionAttempt() override;
void RecordDndAttempt() override;
void RecordFindMyDeviceAttempt() override;
void RecordBrowserTabOpened() override;
void RecordNotificationDismissAttempt() override;
void RecordNotificationReplyAttempt() override;
void HandleUserAction(UserAction action);
};
} // namespace phonehub
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_PHONEHUB_USER_ACTION_RECORDER_IMPL_H_
// Copyright 2020 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 "chromeos/components/phonehub/user_action_recorder_impl.h"
#include <memory>
#include "base/test/metrics/histogram_tester.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace phonehub {
namespace {
const char kCompletedActionMetricName[] = "PhoneHub.CompletedUserAction";
} // namespace
class UserActionRecorderImplTest : public testing::Test {
protected:
UserActionRecorderImplTest() = default;
UserActionRecorderImplTest(const UserActionRecorderImplTest&) = delete;
UserActionRecorderImplTest& operator=(const UserActionRecorderImplTest&) =
delete;
~UserActionRecorderImplTest() override = default;
UserActionRecorderImpl recorder_;
base::HistogramTester histogram_tester_;
};
TEST_F(UserActionRecorderImplTest, Enabled_RecordActions) {
recorder_.RecordUiOpened();
recorder_.RecordTetherConnectionAttempt();
recorder_.RecordDndAttempt();
recorder_.RecordFindMyDeviceAttempt();
recorder_.RecordBrowserTabOpened();
recorder_.RecordNotificationDismissAttempt();
recorder_.RecordNotificationReplyAttempt();
// Each of the actions should have been completed
histogram_tester_.ExpectBucketCount(
kCompletedActionMetricName, UserActionRecorderImpl::UserAction::kUiOpened,
/*expected_count=*/1);
histogram_tester_.ExpectBucketCount(
kCompletedActionMetricName, UserActionRecorderImpl::UserAction::kTether,
/*expected_count=*/1);
histogram_tester_.ExpectBucketCount(kCompletedActionMetricName,
UserActionRecorderImpl::UserAction::kDnd,
/*expected_count=*/1);
histogram_tester_.ExpectBucketCount(
kCompletedActionMetricName,
UserActionRecorderImpl::UserAction::kFindMyDevice,
/*expected_count=*/1);
histogram_tester_.ExpectBucketCount(
kCompletedActionMetricName,
UserActionRecorderImpl::UserAction::kBrowserTab,
/*expected_count=*/1);
histogram_tester_.ExpectBucketCount(
kCompletedActionMetricName,
UserActionRecorderImpl::UserAction::kNotificationDismissal,
/*expected_count=*/1);
histogram_tester_.ExpectBucketCount(
kCompletedActionMetricName,
UserActionRecorderImpl::UserAction::kNotificationReply,
/*expected_count=*/1);
}
} // namespace phonehub
} // namespace chromeos
...@@ -58434,6 +58434,16 @@ Called by update_net_trust_anchors.py.--> ...@@ -58434,6 +58434,16 @@ Called by update_net_trust_anchors.py.-->
<int value="1" label="Attempt was successful"/> <int value="1" label="Attempt was successful"/>
</enum> </enum>
<enum name="PhoneHubUserAction">
<int value="0" label="UI opened"/>
<int value="1" label="Tether connection attempted"/>
<int value="2" label="Do Not Disturb toggled"/>
<int value="3" label="Find My Device toggled"/>
<int value="4" label="Synced browser tab opened"/>
<int value="5" label="Notification dismissed"/>
<int value="6" label="Notification inline reply attempted"/>
</enum>
<enum name="PhoneNumberRegexVariantResult"> <enum name="PhoneNumberRegexVariantResult">
<obsolete> <obsolete>
Removed in M82 as the experiment has been stopped. Removed in M82 as the experiment has been stopped.
...@@ -39,6 +39,18 @@ reviews. Googlers can read more about this at go/gwsq-gerrit. ...@@ -39,6 +39,18 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
<summary>The steady state feature status of PhoneHub on user login.</summary> <summary>The steady state feature status of PhoneHub on user login.</summary>
</histogram> </histogram>
<histogram name="PhoneHub.CompletedUserAction" enum="PhoneHubUserAction"
expires_after="2021-12-01">
<owner>khorimoto@chromium.org</owner>
<owner>better-together-dev@google.com</owner>
<summary>
Measures actions taken by the user as part of the Phone Hub feature; emitted
when the user attempts the actions described in the PhoneHubUserAction enum.
Used to measure engagement and track 28DA user counts.
</summary>
</histogram>
<histogram name="PhoneHub.Connection.Result" enum="BooleanSuccess" <histogram name="PhoneHub.Connection.Result" enum="BooleanSuccess"
expires_after="2021-11-30"> expires_after="2021-11-30">
<owner>khorimoto@chromium.org</owner> <owner>khorimoto@chromium.org</owner>
......
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