Commit 9d1dd4de authored by Takumi Fujimoto's avatar Takumi Fujimoto Committed by Commit Bot

[Harmony Cast Dialog] Add CastDialogMetrics

Add CastDialogMetrics, which will be used by CastDialogView to
record various UI metrics. The recorder will keep track of when/if
certain events (init, paint, load sinks, first user action) happened,
to record when an event happens for the first time, and the durations
between events.

MediaRouterMetrics calls that CastDialogView was making directly will
now go through CastDialogMetrics.

Metrics recorded by CastDialogMetrics via MediaRouterMetrics:
MediaRouter.Ui.Device.Count
MediaRouter.Ui.Dialog.Paint
MediaRouter.Ui.Dialog.LoadedWithData (new)
MediaRouter.Ui.Action.StartLocalPosition
MediaRouter.Ui.Action.CloseLatency (new)
MediaRouter.Ui.Action.StartLocal.Latency (new)
(MediaRouter.Ui.FirstAction will be added later)
(MediaRouter.Ui.Action.StopRoute will be added later)

Bug: 853369
Change-Id: Ib27ecc9293fd148d8592b76b22c9fbab3910a5e5
Reviewed-on: https://chromium-review.googlesource.com/1135582
Commit-Queue: Takumi Fujimoto <takumif@chromium.org>
Reviewed-by: default avatarmark a. foltz <mfoltz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#575129}
parent 3797cf42
......@@ -4,6 +4,8 @@
#include "chrome/browser/media/router/media_router_metrics.h"
#include <algorithm>
#include "base/macros.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
......@@ -43,6 +45,8 @@ MediaRouterMetrics::MediaRouterMetrics() {}
MediaRouterMetrics::~MediaRouterMetrics() = default;
// static
const char MediaRouterMetrics::kHistogramCloseLatency[] =
"MediaRouter.Ui.Action.CloseLatency";
const char MediaRouterMetrics::kHistogramDialParsingError[] =
"MediaRouter.Dial.ParsingError";
const char MediaRouterMetrics::kHistogramIconClickLocation[] =
......@@ -59,6 +63,12 @@ const char MediaRouterMetrics::kHistogramPresentationUrlType[] =
"MediaRouter.PresentationRequest.AvailabilityUrlType";
const char MediaRouterMetrics::kHistogramRouteCreationOutcome[] =
"MediaRouter.Route.CreationOutcome";
const char MediaRouterMetrics::kHistogramStartLocalLatency[] =
"MediaRouter.Ui.Action.StartLocal.Latency";
const char MediaRouterMetrics::kHistogramStartLocalPosition[] =
"MediaRouter.Ui.Action.StartLocalPosition";
const char MediaRouterMetrics::kHistogramStartLocalSessionSuccessful[] =
"MediaRouter.Ui.Action.StartLocalSessionSuccessful";
const char MediaRouterMetrics::kHistogramUiDeviceCount[] =
"MediaRouter.Ui.Device.Count";
const char MediaRouterMetrics::kHistogramUiDialogPaint[] =
......@@ -67,10 +77,6 @@ const char MediaRouterMetrics::kHistogramUiDialogLoadedWithData[] =
"MediaRouter.Ui.Dialog.LoadedWithData";
const char MediaRouterMetrics::kHistogramUiFirstAction[] =
"MediaRouter.Ui.FirstAction";
const char MediaRouterMetrics::kHistogramStartLocalPosition[] =
"MediaRouter.Ui.Action.StartLocalPosition";
const char MediaRouterMetrics::kHistogramStartLocalSessionSuccessful[] =
"MediaRouter.Ui.Action.StartLocalSessionSuccessful";
// static
void MediaRouterMetrics::RecordMediaRouterDialogOrigin(
......@@ -84,16 +90,22 @@ void MediaRouterMetrics::RecordMediaRouterDialogOrigin(
// static
void MediaRouterMetrics::RecordMediaRouterDialogPaint(
const base::TimeDelta delta) {
const base::TimeDelta& delta) {
UMA_HISTOGRAM_TIMES(kHistogramUiDialogPaint, delta);
}
// static
void MediaRouterMetrics::RecordMediaRouterDialogLoaded(
const base::TimeDelta delta) {
const base::TimeDelta& delta) {
UMA_HISTOGRAM_TIMES(kHistogramUiDialogLoadedWithData, delta);
}
// static
void MediaRouterMetrics::RecordCloseDialogLatency(
const base::TimeDelta& delta) {
UMA_HISTOGRAM_TIMES(kHistogramCloseLatency, delta);
}
// static
void MediaRouterMetrics::RecordMediaRouterInitialUserAction(
MediaRouterUserAction action) {
......@@ -164,6 +176,12 @@ void MediaRouterMetrics::RecordStartRouteDeviceIndex(int index) {
base::UmaHistogramSparse(kHistogramStartLocalPosition, std::min(index, 100));
}
// static
void MediaRouterMetrics::RecordStartLocalSessionLatency(
const base::TimeDelta& delta) {
UMA_HISTOGRAM_TIMES(kHistogramStartLocalLatency, delta);
}
// static
void MediaRouterMetrics::RecordStartLocalSessionSuccessful(bool success) {
UMA_HISTOGRAM_BOOLEAN(kHistogramStartLocalSessionSuccessful, success);
......
......@@ -81,6 +81,7 @@ class MediaRouterMetrics {
~MediaRouterMetrics();
// UMA histogram names.
static const char kHistogramCloseLatency[];
static const char kHistogramDialParsingError[];
static const char kHistogramIconClickLocation[];
static const char kHistogramMediaRouterCastingSource[];
......@@ -89,12 +90,13 @@ class MediaRouterMetrics {
static const char kHistogramMediaSinkType[];
static const char kHistogramPresentationUrlType[];
static const char kHistogramRouteCreationOutcome[];
static const char kHistogramStartLocalLatency[];
static const char kHistogramStartLocalPosition[];
static const char kHistogramStartLocalSessionSuccessful[];
static const char kHistogramUiDeviceCount[];
static const char kHistogramUiDialogPaint[];
static const char kHistogramUiDialogLoadedWithData[];
static const char kHistogramUiFirstAction[];
static const char kHistogramStartLocalPosition[];
static const char kHistogramStartLocalSessionSuccessful[];
// Records where the user clicked to open the Media Router dialog.
static void RecordMediaRouterDialogOrigin(
......@@ -102,13 +104,16 @@ class MediaRouterMetrics {
// Records the duration it takes for the Media Router dialog to open and
// finish painting after a user clicks to open the dialog.
static void RecordMediaRouterDialogPaint(
const base::TimeDelta delta);
static void RecordMediaRouterDialogPaint(const base::TimeDelta& delta);
// Records the duration it takes for the Media Router dialog to load its
// initial data after a user clicks to open the dialog.
static void RecordMediaRouterDialogLoaded(
const base::TimeDelta delta);
static void RecordMediaRouterDialogLoaded(const base::TimeDelta& delta);
// Records the duration it takes from the user opening the Media Router dialog
// to the user closing the dialog. This is only called if closing the dialog
// is the first action the user takes.
static void RecordCloseDialogLatency(const base::TimeDelta& delta);
// Records the first action the user took after the Media Router dialog
// opened.
......@@ -147,6 +152,11 @@ class MediaRouterMetrics {
// devices list. The index starts at 0.
static void RecordStartRouteDeviceIndex(int index);
// Records the time it takes from the Media Router dialog showing at least one
// device to the user starting to cast. This is called only if casting is the
// first action taken by the user, aside from selecting the sink to cast to.
static void RecordStartLocalSessionLatency(const base::TimeDelta& delta);
// Records whether or not an attempt to start casting was successful.
static void RecordStartLocalSessionSuccessful(bool success);
};
......
......@@ -4,6 +4,9 @@
#include "chrome/browser/media/router/media_router_metrics.h"
#include <string>
#include "base/bind.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/test/metrics/histogram_tester.h"
......@@ -20,6 +23,23 @@ using testing::ElementsAre;
namespace media_router {
namespace {
// Tests that calling |recording_cb| with a TimeDelta records it in
// |histogram_name|.
void TestRecordTimeDeltaMetric(
base::RepeatingCallback<void(const base::TimeDelta&)> recording_cb,
const std::string& histogram_name) {
base::HistogramTester tester;
const base::TimeDelta delta = base::TimeDelta::FromMilliseconds(10);
tester.ExpectTotalCount(histogram_name, 0);
recording_cb.Run(delta);
tester.ExpectUniqueSample(histogram_name, delta.InMilliseconds(), 1);
}
} // namespace
using DialParsingError = SafeDialDeviceDescriptionParser::ParsingError;
TEST(MediaRouterMetricsTest, RecordMediaRouterDialogOrigin) {
......@@ -41,25 +61,21 @@ TEST(MediaRouterMetricsTest, RecordMediaRouterDialogOrigin) {
}
TEST(MediaRouterMetricsTest, RecordMediaRouterDialogPaint) {
base::HistogramTester tester;
const base::TimeDelta delta = base::TimeDelta::FromMilliseconds(10);
tester.ExpectTotalCount(MediaRouterMetrics::kHistogramUiDialogPaint, 0);
MediaRouterMetrics::RecordMediaRouterDialogPaint(delta);
tester.ExpectUniqueSample(MediaRouterMetrics::kHistogramUiDialogPaint,
delta.InMilliseconds(), 1);
TestRecordTimeDeltaMetric(
base::BindRepeating(&MediaRouterMetrics::RecordMediaRouterDialogPaint),
MediaRouterMetrics::kHistogramUiDialogPaint);
}
TEST(MediaRouterMetricsTest, RecordMediaRouterDialogLoaded) {
base::HistogramTester tester;
const base::TimeDelta delta = base::TimeDelta::FromMilliseconds(10);
TestRecordTimeDeltaMetric(
base::BindRepeating(&MediaRouterMetrics::RecordMediaRouterDialogLoaded),
MediaRouterMetrics::kHistogramUiDialogLoadedWithData);
}
tester.ExpectTotalCount(MediaRouterMetrics::kHistogramUiDialogLoadedWithData,
0);
MediaRouterMetrics::RecordMediaRouterDialogLoaded(delta);
tester.ExpectUniqueSample(
MediaRouterMetrics::kHistogramUiDialogLoadedWithData,
delta.InMilliseconds(), 1);
TEST(MediaRouterMetricsTest, RecordCloseDialogLatency) {
TestRecordTimeDeltaMetric(
base::BindRepeating(&MediaRouterMetrics::RecordCloseDialogLatency),
MediaRouterMetrics::kHistogramCloseLatency);
}
TEST(MediaRouterMetricsTest, RecordMediaRouterInitialUserAction) {
......@@ -214,6 +230,12 @@ TEST(MediaRouterMetricsTest, RecordStartRouteDeviceIndex) {
ElementsAre(Bucket(0, 1), Bucket(30, 1)));
}
TEST(MediaRouterMetricsTest, RecordStartLocalSessionLatency) {
TestRecordTimeDeltaMetric(
base::BindRepeating(&MediaRouterMetrics::RecordStartLocalSessionLatency),
MediaRouterMetrics::kHistogramStartLocalLatency);
}
TEST(MediaRouterMetricsTest, RecordStartLocalSessionSuccessful) {
base::HistogramTester tester;
tester.ExpectTotalCount(
......
......@@ -3215,6 +3215,8 @@ split_static_library("ui") {
"views/location_bar/selected_keyword_view.h",
"views/location_bar/star_view.cc",
"views/location_bar/star_view.h",
"views/media_router/cast_dialog_metrics.cc",
"views/media_router/cast_dialog_metrics.h",
"views/media_router/cast_dialog_no_sinks_view.cc",
"views/media_router/cast_dialog_no_sinks_view.h",
"views/media_router/cast_dialog_sink_button.cc",
......
// Copyright 2018 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 "chrome/browser/ui/views/media_router/cast_dialog_metrics.h"
namespace media_router {
CastDialogMetrics::CastDialogMetrics(const base::Time& initialization_time)
: initialization_time_(initialization_time) {}
CastDialogMetrics::~CastDialogMetrics() = default;
void CastDialogMetrics::OnSinksLoaded(const base::Time& sinks_load_time) {
if (!sinks_load_time_.is_null())
return;
MediaRouterMetrics::RecordMediaRouterDialogLoaded(sinks_load_time -
initialization_time_);
sinks_load_time_ = sinks_load_time;
}
void CastDialogMetrics::OnPaint(const base::Time& paint_time) {
if (!paint_time_.is_null())
return;
MediaRouterMetrics::RecordMediaRouterDialogPaint(paint_time -
initialization_time_);
paint_time_ = paint_time;
}
void CastDialogMetrics::OnStartCasting(const base::Time& start_time,
int selected_sink_index) {
DCHECK(!sinks_load_time_.is_null());
MediaRouterMetrics::RecordStartRouteDeviceIndex(selected_sink_index);
if (!first_action_recorded_) {
MediaRouterMetrics::RecordStartLocalSessionLatency(start_time -
sinks_load_time_);
}
MaybeRecordFirstAction(MediaRouterUserAction::START_LOCAL);
}
void CastDialogMetrics::OnStopCasting() {
// TODO(https://crbug.com/853369): In order to record this as the first user
// action, we must determine whether we're stopping a local or non-local
// route.
}
void CastDialogMetrics::OnCastModeSelected() {
MaybeRecordFirstAction(MediaRouterUserAction::CHANGE_MODE);
}
void CastDialogMetrics::OnCloseDialog(const base::Time& close_time) {
if (!first_action_recorded_ && !paint_time_.is_null())
MediaRouterMetrics::RecordCloseDialogLatency(close_time - paint_time_);
MaybeRecordFirstAction(MediaRouterUserAction::CLOSE);
}
void CastDialogMetrics::OnRecordSinkCount(int sink_count) {
media_router::MediaRouterMetrics::RecordDeviceCount(sink_count);
}
void CastDialogMetrics::MaybeRecordFirstAction(MediaRouterUserAction action) {
if (first_action_recorded_)
return;
// TODO(https://crbug.com/853369): Record initial user action once we can
// determine whether a OnStopCasting() call is for a local or non-local route.
first_action_recorded_ = true;
}
} // namespace media_router
// Copyright 2018 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 CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_METRICS_H_
#define CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_METRICS_H_
#include "base/macros.h"
#include "base/time/time.h"
#include "chrome/browser/media/router/media_router_metrics.h"
namespace media_router {
// Records UMA metrics for the behavior of a Cast dialog. A new recorder
// instance should be used each time the dialog is opened.
// TODO(takumif): Once we have removed the WebUI Cast dialog, we should move
// MediaRouter.Ui.* metrics from media_router_metrics.h into this file, and move
// this file to chrome/browser/ui/media_router/.
class CastDialogMetrics {
public:
// |initialization_time| is when the dialog UI started initializing. We use
// this value as the baseline for how long the dialog took to paint, load
// sinks, etc.
explicit CastDialogMetrics(const base::Time& initialization_time);
virtual ~CastDialogMetrics();
// Records the time it took to load sinks when called for the first time. This
// is called when the list of sinks becomes non-empty.
void OnSinksLoaded(const base::Time& sinks_load_time);
// Records the time it took to paint when called for the first time.
void OnPaint(const base::Time& paint_time);
// Records the index of the selected sink in the sink list. Also records how
// long it took to start casting if no other action (aside from selecting a
// sink) was taken prior to that.
void OnStartCasting(const base::Time& start_time, int selected_sink_index);
void OnStopCasting();
void OnCastModeSelected();
// Records the time it took to close the dialog, if no other action was taken
// prior to that after opening the dialog.
void OnCloseDialog(const base::Time& close_time);
// Records the number of sinks, which may be 0.
void OnRecordSinkCount(int sink_count);
private:
// Records the first user action if it hasn't already been recorded.
void MaybeRecordFirstAction(MediaRouterUserAction action);
// The time when the dialog UI started initializing.
base::Time initialization_time_;
// The time when the dialog was painted.
base::Time paint_time_;
// The time when a non-empty list of sinks was loaded.
base::Time sinks_load_time_;
// Whether we have already recorded the first user action taken in this dialog
// instance.
bool first_action_recorded_ = false;
DISALLOW_COPY_AND_ASSIGN(CastDialogMetrics);
};
} // namespace media_router
#endif // CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_METRICS_H_
// Copyright 2018 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 "chrome/browser/ui/views/media_router/cast_dialog_metrics.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/time/time.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::Bucket;
using testing::ElementsAre;
namespace media_router {
namespace {
const base::Time init_time = base::Time::Now();
const base::Time paint_time = init_time + base::TimeDelta::FromMilliseconds(50);
const base::Time sink_load_time =
init_time + base::TimeDelta::FromMilliseconds(300);
const base::Time start_casting_time =
init_time + base::TimeDelta::FromMilliseconds(2000);
const base::Time close_dialog_time =
init_time + base::TimeDelta::FromMilliseconds(3000);
} // namespace
class CastDialogMetricsTest : public testing::Test {
public:
CastDialogMetricsTest() : metrics_(init_time) {}
~CastDialogMetricsTest() override = default;
protected:
CastDialogMetrics metrics_;
base::HistogramTester tester_;
};
TEST_F(CastDialogMetricsTest, OnSinksLoaded) {
metrics_.OnSinksLoaded(sink_load_time);
tester_.ExpectUniqueSample(
MediaRouterMetrics::kHistogramUiDialogLoadedWithData,
(sink_load_time - init_time).InMilliseconds(), 1);
}
TEST_F(CastDialogMetricsTest, OnPaint) {
metrics_.OnPaint(paint_time);
tester_.ExpectUniqueSample(MediaRouterMetrics::kHistogramUiDialogPaint,
(paint_time - init_time).InMilliseconds(), 1);
}
TEST_F(CastDialogMetricsTest, OnStartCasting) {
constexpr int kSinkIndex = 4;
metrics_.OnSinksLoaded(sink_load_time);
metrics_.OnStartCasting(start_casting_time, kSinkIndex);
tester_.ExpectUniqueSample(
MediaRouterMetrics::kHistogramStartLocalLatency,
(start_casting_time - sink_load_time).InMilliseconds(), 1);
}
TEST_F(CastDialogMetricsTest, OnCloseDialog) {
metrics_.OnPaint(paint_time);
metrics_.OnCloseDialog(close_dialog_time);
tester_.ExpectUniqueSample(MediaRouterMetrics::kHistogramCloseLatency,
(close_dialog_time - paint_time).InMilliseconds(),
1);
}
TEST_F(CastDialogMetricsTest, OnRecordSinkCount) {
constexpr int kSinkCount = 3;
metrics_.OnRecordSinkCount(kSinkCount);
tester_.ExpectUniqueSample(MediaRouterMetrics::kHistogramUiDeviceCount,
kSinkCount, 1);
}
} // namespace media_router
......@@ -125,14 +125,15 @@ bool CastDialogView::Accept() {
const UIMediaSink& sink = GetSelectedSink();
if (!sink.route_id.empty()) {
controller_->StopCasting(sink.route_id);
metrics_.OnStopCasting();
} else {
// Go through cast modes in the order of preference to find one that is
// supported and selected.
for (MediaCastMode cast_mode : {PRESENTATION, TAB_MIRROR, DESKTOP_MIRROR}) {
if ((cast_mode & selected_source_) &&
base::ContainsKey(sink.cast_modes, cast_mode)) {
MediaRouterMetrics::RecordStartRouteDeviceIndex(selected_sink_index_);
controller_->StartCasting(sink.id, cast_mode);
metrics_.OnStartCasting(base::Time::Now(), selected_sink_index_);
break;
}
}
......@@ -156,6 +157,7 @@ void CastDialogView::OnModelUpdated(const CastDialogModel& model) {
ShowScrollView();
PopulateScrollView(model.media_sinks());
RestoreSinkListState();
metrics_.OnSinksLoaded(base::Time::Now());
}
dialog_title_ = model.dialog_header();
MaybeSizeToContents();
......@@ -184,11 +186,7 @@ gfx::Size CastDialogView::CalculatePreferredSize() const {
void CastDialogView::OnPaint(gfx::Canvas* canvas) {
views::BubbleDialogDelegateView::OnPaint(canvas);
if (!start_time_.is_null()) {
MediaRouterMetrics::RecordMediaRouterDialogPaint(base::Time::Now() -
start_time_);
start_time_ = base::Time();
}
metrics_.OnPaint(base::Time::Now());
}
bool CastDialogView::IsCommandIdChecked(int command_id) const {
......@@ -201,6 +199,7 @@ bool CastDialogView::IsCommandIdEnabled(int command_id) const {
void CastDialogView::ExecuteCommand(int command_id, int event_flags) {
selected_source_ = command_id;
metrics_.OnCastModeSelected();
}
CastDialogView::CastDialogView(views::View* anchor_view,
......@@ -211,7 +210,7 @@ CastDialogView::CastDialogView(views::View* anchor_view,
selected_source_(kTabSource),
controller_(controller),
browser_(browser),
start_time_(start_time),
metrics_(start_time),
weak_factory_(this) {
ShowNoSinksView();
}
......@@ -238,6 +237,7 @@ void CastDialogView::Init() {
void CastDialogView::WindowClosing() {
if (instance_ == this)
instance_ = nullptr;
metrics_.OnCloseDialog(base::Time::Now());
}
void CastDialogView::ShowNoSinksView() {
......@@ -368,7 +368,7 @@ void CastDialogView::RecordSinkCountWithDelay() {
}
void CastDialogView::RecordSinkCount() {
media_router::MediaRouterMetrics::RecordDeviceCount(sink_buttons_.size());
metrics_.OnRecordSinkCount(sink_buttons_.size());
}
// static
......
......@@ -10,6 +10,7 @@
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ui/media_router/cast_dialog_controller.h"
#include "chrome/browser/ui/views/media_router/cast_dialog_metrics.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/views/bubble/bubble_dialog_delegate.h"
#include "ui/views/controls/button/button.h"
......@@ -128,10 +129,11 @@ class CastDialogView : public views::BubbleDialogDelegateView,
void MaybeSizeToContents();
// Posts a delayed task to record an UMA metric for the number of sinks shown.
// Posts a delayed task to record the number of sinks shown with the metrics
// recorder.
void RecordSinkCountWithDelay();
// Records an UMA metric for the number of sinks shown.
// Records the number of sinks shown with the metrics recorder.
void RecordSinkCount();
// The singleton dialog instance. This is a nullptr when a dialog is not
......@@ -173,8 +175,8 @@ class CastDialogView : public views::BubbleDialogDelegateView,
std::unique_ptr<ui::SimpleMenuModel> sources_menu_model_;
std::unique_ptr<views::MenuRunner> sources_menu_runner_;
// The time when the dialog UI started initializing.
base::Time start_time_;
// Records UMA metrics for the dialog's behavior.
CastDialogMetrics metrics_;
base::WeakPtrFactory<CastDialogView> weak_factory_;
......
......@@ -850,8 +850,8 @@ void MediaRouterWebUIMessageHandler::OnReportTimeToClickSink(
DVLOG(1) << "Unable to extract args.";
return;
}
UMA_HISTOGRAM_TIMES("MediaRouter.Ui.Action.StartLocal.Latency",
base::TimeDelta::FromMillisecondsD(time_to_click));
MediaRouterMetrics::RecordStartLocalSessionLatency(
base::TimeDelta::FromMillisecondsD(time_to_click));
}
void MediaRouterWebUIMessageHandler::OnReportWebUIRouteControllerLoaded(
......@@ -874,8 +874,8 @@ void MediaRouterWebUIMessageHandler::OnReportTimeToInitialActionClose(
DVLOG(1) << "Unable to extract args.";
return;
}
UMA_HISTOGRAM_TIMES("MediaRouter.Ui.Action.CloseLatency",
base::TimeDelta::FromMillisecondsD(time_to_close));
MediaRouterMetrics::RecordCloseDialogLatency(
base::TimeDelta::FromMillisecondsD(time_to_close));
}
void MediaRouterWebUIMessageHandler::OnSearchSinksAndCreateRoute(
......
......@@ -4349,6 +4349,7 @@ test("unit_tests") {
"../browser/ui/views/global_error_bubble_view_unittest.cc",
"../browser/ui/views/harmony/layout_provider_unittest.cc",
"../browser/ui/views/hover_button_unittest.cc",
"../browser/ui/views/media_router/cast_dialog_metrics_unittest.cc",
"../browser/ui/views/media_router/cast_dialog_no_sinks_view_unittest.cc",
"../browser/ui/views/media_router/cast_dialog_sink_button_unittest.cc",
"../browser/ui/views/media_router/cast_dialog_view_unittest.cc",
......
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