Skip to content

Commit

Permalink
cros: Add user action metrics for logout of demo sessions
Browse files Browse the repository at this point in the history
Record metrics when user logs out the demo session by using the buttons
on shelf and system tray.

Bug: 900263
Change-Id: I23ad6bf89b3b0e7a0edee265792cbffe8a9b9951
Reviewed-on: https://chromium-review.googlesource.com/c/1328231
Reviewed-by: Ilya Sherman <isherman@chromium.org>
Reviewed-by: Xiyuan Xia <xiyuan@chromium.org>
Reviewed-by: Michael Giuffrida <michaelpg@chromium.org>
Commit-Queue: Wenzhao (Colin) Zang <wzang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611499}
  • Loading branch information
Wenzhao Zang authored and Commit Bot committed Nov 28, 2018
1 parent 246821d commit b06aeea
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 37 deletions.
1 change: 1 addition & 0 deletions ash/session/test_session_controller_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ void TestSessionControllerClient::RequestLockScreen() {

void TestSessionControllerClient::RequestSignOut() {
Reset();
++request_sign_out_count_;
}

void TestSessionControllerClient::SwitchActiveUser(
Expand Down
3 changes: 3 additions & 0 deletions ash/session/test_session_controller_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class TestSessionControllerClient : public ash::mojom::SessionControllerClient {
use_lower_case_user_id_ = value;
}

int request_sign_out_count() const { return request_sign_out_count_; }

// Helpers to set SessionController state.
void SetCanLockScreen(bool can_lock);
void SetShouldLockScreenAutomatically(bool should_lock);
Expand Down Expand Up @@ -100,6 +102,7 @@ class TestSessionControllerClient : public ash::mojom::SessionControllerClient {
mojom::SessionInfoPtr session_info_;

bool use_lower_case_user_id_ = true;
int request_sign_out_count_ = 0;

DISALLOW_COPY_AND_ASSIGN(TestSessionControllerClient);
};
Expand Down
6 changes: 5 additions & 1 deletion ash/system/session/logout_button_tray.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray/tray_container.h"
#include "ash/system/user/login_status.h"
#include "base/metrics/user_metrics.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
Expand Down Expand Up @@ -72,11 +73,14 @@ void LogoutButtonTray::ButtonPressed(views::Button* sender,
DCHECK_EQ(button_, sender);

if (dialog_duration_ <= base::TimeDelta()) {
if (Shell::Get()->session_controller()->IsDemoSession())
base::RecordAction(base::UserMetricsAction("DemoMode.ExitFromShelf"));
// Sign out immediately if |dialog_duration_| is non-positive.
Shell::Get()->session_controller()->RequestSignOut();
} else if (Shell::Get()->logout_confirmation_controller()) {
Shell::Get()->logout_confirmation_controller()->ConfirmLogout(
base::TimeTicks::Now() + dialog_duration_);
base::TimeTicks::Now() + dialog_duration_,
LogoutConfirmationController::Source::kShelfExitButton);
}
}

Expand Down
2 changes: 2 additions & 0 deletions ash/system/session/logout_button_tray.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class ASH_EXPORT LogoutButtonTray : public views::View,
// SessionObserver:
void OnActiveUserPrefServiceChanged(PrefService* prefs) override;

views::MdTextButton* button_for_test() const { return button_; }

private:
void UpdateShowLogoutButtonInTray();
void UpdateLogoutDialogDuration();
Expand Down
65 changes: 65 additions & 0 deletions ash/system/session/logout_button_tray_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@
#include "ash/session/session_controller.h"
#include "ash/session/test_session_controller_client.h"
#include "ash/shell.h"
#include "ash/system/session/logout_confirmation_controller.h"
#include "ash/system/status_area_widget.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/ash_test_helper.h"
#include "ash/test_shell_delegate.h"
#include "base/macros.h"
#include "base/test/metrics/user_action_tester.h"
#include "components/prefs/pref_service.h"
#include "ui/events/base_event_utils.h"
#include "ui/views/controls/button/md_text_button.h"

namespace ash {
namespace {
Expand Down Expand Up @@ -70,5 +74,66 @@ TEST_F(LogoutButtonTrayTest, Visibility) {
EXPECT_FALSE(button->visible());
}

TEST_F(LogoutButtonTrayTest, ButtonPressed) {
constexpr char kUserEmail[] = "user1@test.com";
constexpr char kUserAction[] = "DemoMode.ExitFromShelf";

LogoutButtonTray* const tray = Shell::GetPrimaryRootWindowController()
->GetStatusAreaWidget()
->logout_button_tray_for_testing();
ASSERT_TRUE(tray);
views::MdTextButton* const button = tray->button_for_test();
SessionController* const session_controller =
Shell::Get()->session_controller();
TestSessionControllerClient* const session_client =
GetSessionControllerClient();
base::UserActionTester user_action_tester;
const ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), 0, 0);
PrefService* const pref_service =
Shell::Get()->session_controller()->GetUserPrefServiceForUser(
AccountId::FromUserEmail(kUserEmail));

SimulateUserLogin(kUserEmail);
EXPECT_EQ(0, session_client->request_sign_out_count());
EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction));
EXPECT_EQ(0, Shell::Get()
->logout_confirmation_controller()
->confirm_logout_count_for_test());

// Sign out immediately when duration is zero.
pref_service->SetInteger(prefs::kLogoutDialogDurationMs, 0);
tray->ButtonPressed(button, event);
session_controller->FlushMojoForTest();
EXPECT_EQ(1, session_client->request_sign_out_count());
EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction));
EXPECT_EQ(0, Shell::Get()
->logout_confirmation_controller()
->confirm_logout_count_for_test());

// Call |LogoutConfirmationController::ConfirmLogout| when duration is
// non-zero.
pref_service->SetInteger(prefs::kLogoutDialogDurationMs, 1000);
tray->ButtonPressed(button, event);
session_controller->FlushMojoForTest();
EXPECT_EQ(1, session_client->request_sign_out_count());
EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction));
EXPECT_EQ(1, Shell::Get()
->logout_confirmation_controller()
->confirm_logout_count_for_test());

// Sign out immediately and record user action when duration is zero and it is
// demo session.
pref_service->SetInteger(prefs::kLogoutDialogDurationMs, 0);
session_client->SetIsDemoSession();
tray->ButtonPressed(button, event);
session_controller->FlushMojoForTest();
EXPECT_EQ(2, session_client->request_sign_out_count());
EXPECT_EQ(1, user_action_tester.GetActionCount(kUserAction));
EXPECT_EQ(1, Shell::Get()
->logout_confirmation_controller()
->confirm_logout_count_for_test());
}

} // namespace
} // namespace ash
27 changes: 18 additions & 9 deletions ash/system/session/logout_confirmation_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "ash/system/session/logout_confirmation_dialog.h"
#include "base/callback.h"
#include "base/location.h"
#include "base/metrics/user_metrics.h"
#include "base/time/default_tick_clock.h"
#include "base/time/tick_clock.h"
#include "ui/aura/window.h"
Expand All @@ -29,7 +30,11 @@ const int kLogoutConfirmationDelayInSeconds = 20;
const int kLastWindowClosedContainerIds[] = {
kShellWindowId_DefaultContainer, kShellWindowId_AlwaysOnTopContainer};

void SignOut() {
void SignOut(LogoutConfirmationController::Source source) {
if (Shell::Get()->session_controller()->IsDemoSession() &&
source == LogoutConfirmationController::Source::kShelfExitButton) {
base::RecordAction(base::UserMetricsAction("DemoMode.ExitFromShelf"));
}
Shell::Get()->session_controller()->RequestSignOut();
}

Expand Down Expand Up @@ -94,7 +99,8 @@ class LogoutConfirmationController::LastWindowClosedObserver
// No more windows except currently removing. Show logout time.
Shell::Get()->logout_confirmation_controller()->ConfirmLogout(
base::TimeTicks::Now() +
base::TimeDelta::FromSeconds(kLogoutConfirmationDelayInSeconds));
base::TimeDelta::FromSeconds(kLogoutConfirmationDelayInSeconds),
Source::kCloseAllWindows);
}

// ShellObserver:
Expand All @@ -120,7 +126,7 @@ class LogoutConfirmationController::LastWindowClosedObserver

LogoutConfirmationController::LogoutConfirmationController()
: clock_(base::DefaultTickClock::GetInstance()),
logout_closure_(base::Bind(&SignOut)) {
logout_callback_(base::BindRepeating(&SignOut)) {
if (Shell::HasInstance()) // Null in testing::Test.
Shell::Get()->session_controller()->AddObserver(this);
}
Expand All @@ -133,7 +139,8 @@ LogoutConfirmationController::~LogoutConfirmationController() {
Shell::Get()->session_controller()->RemoveObserver(this);
}

void LogoutConfirmationController::ConfirmLogout(base::TimeTicks logout_time) {
void LogoutConfirmationController::ConfirmLogout(base::TimeTicks logout_time,
Source source) {
if (!logout_time_.is_null() && logout_time >= logout_time_) {
// If a confirmation dialog is already being shown and its countdown expires
// no later than the |logout_time| requested now, keep the current dialog
Expand All @@ -150,8 +157,10 @@ void LogoutConfirmationController::ConfirmLogout(base::TimeTicks logout_time) {
dialog_->Update(logout_time_);
}

source_ = source;
logout_timer_.Start(FROM_HERE, logout_time_ - clock_->NowTicks(),
logout_closure_);
base::BindOnce(logout_callback_, source));
++confirm_logout_count_for_test_;
}

void LogoutConfirmationController::OnLoginStatusChanged(
Expand All @@ -178,7 +187,7 @@ void LogoutConfirmationController::OnLockStateChanged(bool locked) {

void LogoutConfirmationController::OnLogoutConfirmed() {
logout_timer_.Stop();
logout_closure_.Run();
logout_callback_.Run(source_);
}

void LogoutConfirmationController::OnDialogClosed() {
Expand All @@ -192,9 +201,9 @@ void LogoutConfirmationController::SetClockForTesting(
clock_ = clock;
}

void LogoutConfirmationController::SetLogoutClosureForTesting(
const base::Closure& logout_closure) {
logout_closure_ = logout_closure;
void LogoutConfirmationController::SetLogoutCallbackForTesting(
const base::RepeatingCallback<void(Source)>& logout_callback) {
logout_callback_ = logout_callback;
}

} // namespace ash
17 changes: 14 additions & 3 deletions ash/system/session/logout_confirmation_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class LogoutConfirmationDialog;
// closed.
class ASH_EXPORT LogoutConfirmationController : public SessionObserver {
public:
enum class Source { kShelfExitButton, kCloseAllWindows };

LogoutConfirmationController();
~LogoutConfirmationController() override;

Expand All @@ -42,7 +44,7 @@ class ASH_EXPORT LogoutConfirmationController : public SessionObserver {
// Shows a LogoutConfirmationDialog. If a confirmation dialog is already being
// shown, it is closed and a new one opened if |logout_time| is earlier than
// the current dialog's |logout_time_|.
void ConfirmLogout(base::TimeTicks logout_time);
void ConfirmLogout(base::TimeTicks logout_time, Source source);

// SessionObserver:
void OnLoginStatusChanged(LoginStatus login_status) override;
Expand All @@ -58,20 +60,29 @@ class ASH_EXPORT LogoutConfirmationController : public SessionObserver {
// of the clock. |clock| must outlive the LogoutConfirmationController
// instance.
void SetClockForTesting(const base::TickClock* clock);
void SetLogoutClosureForTesting(const base::Closure& logout_closure);
void SetLogoutCallbackForTesting(
const base::RepeatingCallback<void(Source)>& logout_callback);
LogoutConfirmationDialog* dialog_for_testing() const { return dialog_; }

int confirm_logout_count_for_test() const {
return confirm_logout_count_for_test_;
}

private:
class LastWindowClosedObserver;
std::unique_ptr<LastWindowClosedObserver> last_window_closed_observer_;

const base::TickClock* clock_;
base::Closure logout_closure_;

base::RepeatingCallback<void(Source)> logout_callback_;
Source source_;

base::TimeTicks logout_time_;
LogoutConfirmationDialog* dialog_ = nullptr; // Owned by the Views hierarchy.
base::OneShotTimer logout_timer_;

int confirm_logout_count_for_test_ = 0;

DISALLOW_COPY_AND_ASSIGN(LogoutConfirmationController);
};

Expand Down
Loading

0 comments on commit b06aeea

Please sign in to comment.