chromium/ash/system/time/calendar_metrics.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/system/time/calendar_metrics.h"

#include "ash/public/cpp/metrics_util.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "base/time/time.h"
#include "google_apis/common/api_error_codes.h"
#include "ui/compositor/animation_throughput_reporter.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/events/event.h"
#include "ui/views/view.h"

namespace ash {

namespace calendar_metrics {

namespace {

constexpr char kCalendarViewShowSourcePrefix[] = "Ash.Calendar.ShowSource.";
constexpr char kCalendarDateCellActivated[] = "Ash.Calendar.DateCell.Activated";
constexpr char kCalendarEventListItemActivated[] =
    "Ash.Calendar.EventListItem.Activated";
constexpr char kCalendarMonthDownArrowButtonActivated[] =
    "Ash.Calendar.MonthDownArrowButton.Activated";
constexpr char kCalendarMonthUpArrowButtonActivated[] =
    "Ash.Calendar.MonthUpArrowButton.Activated";
constexpr char kCalendarMonthDwellTime[] = "Ash.Calendar.MonthDwellTime";
constexpr char kCalendarScrollSource[] = "Ash.Calendar.ScrollSource";
constexpr char kCalendarKeyboardNavigation[] =
    "Ash.Calendar.KeyboardNavigation";
constexpr char kCalendarEventListItemInUpNextPressed[] =
    "Ash.Calendar.UpNextView.EventListItem.Pressed";
constexpr char kCalendarUpNextEventDisplayedCount[] =
    "Ash.Calendar.UpNextView.EventDisplayedCount";
constexpr char kCalendarEventListItemJoinButtonPressed[] =
    "Ash.Calendar.EventListView.JoinMeetingButton.Pressed";
constexpr char kCalendarUpNextJoinButtonPressed[] =
    "Ash.Calendar.UpNextView.JoinMeetingButton.Pressed";
constexpr char kCalendarEventListEventDisplayedCount[] =
    "Ash.Calendar.EventListViewJelly.EventDisplayedCount";
constexpr char kCalendarEventsDisplayedToUser[] =
    "Ash.Calendar.EventsDisplayedToUser";
constexpr char kCalendarUserAction[] = "Ash.Calendar.UserAction";
constexpr char kCalendarWebUiOpened[] =
    "Ash.Calendar.UserActionToOpenCalendarWebUi";
constexpr char kCalendarFetchCalendarsFetchDuration[] =
    "Ash.Calendar.FetchCalendars.FetchDuration";
constexpr char kCalendarFetchCalendarsResult[] =
    "Ash.Calendar.FetchCalendars.Result";
constexpr char kCalendarFetchCalendarsTimeout[] =
    "Ash.Calendar.FetchCalendars.Timeout";
constexpr char kCalendarFetchEventsFetchDuration[] =
    "Ash.Calendar.FetchEvents.FetchDuration";
constexpr char kCalendarFetchEventsResult[] = "Ash.Calendar.FetchEvents.Result";
constexpr char kCalendarFetchEventsSingleMonthSize[] =
    "Ash.Calendar.FetchEvents.SingleMonthSize";
constexpr char kCalendarFetchEventsTimeout[] =
    "Ash.Calendar.FetchEvents.Timeout";
constexpr char kCalendarFetchEventsTotalCacheSizeMonths[] =
    "Ash.Calendar.FetchEvents.TotalCacheSizeMonths";
constexpr char kCalendarFetchEventsTotalFetchDuration[] =
    "Ash.Calendar.FetchEvents.TotalFetchDuration";
constexpr char kCalendarFetchCalendarsTotalSelectedCalendars[] =
    "Ash.Calendar.FetchCalendars.TotalSelectedCalendars";
constexpr char kCalendarTimeToSeeTodaysEventDots[] =
    "Ash.Calendar.TimeToSeeTodaysEventDots";
constexpr char kCalendarTimeToSeeTodaysEventDotsForMultiCalendar[] =
    "Ash.Calendar.TimeToSeeTodaysEventDotsForMultiCalendar";

// This enum is used in histograms. These values are persisted to logs. Entries
// should not be renumbered and numeric values should never be reused, only add
// at the end and. Also remember to update the CalendarUserAction enum in
// tools/metrics/histograms/metadata/ash/enums.xml.
enum class CalendarUserActionType {
  kDateCellActivated = 0,
  kMonthDownArrowActivated = 1,
  kMonthUpArrowActivated = 2,
  kScrolled = 3,
  kKeyboardNavigation = 4,
  kEventListItemPressed = 5,
  kUpNextItemPressed = 6,
  kEventListItemJoinButtonPressed = 7,
  kUpNextJoinButtonPressed = 8,
  kResetToTodayPressed = 9,
  kTodaysEventsInUpNextPressed = 10,
  kScrollInUpNext = 11,
  kCalendarLaunchedFromEmptyEventList = 12,
  kEventListClosed = 13,
  kSettingsButtonPressed = 14,
  kMaxValue = kSettingsButtonPressed,
};

bool ActionOpensCalendarWebUi(CalendarUserActionType action) {
  switch (action) {
    case CalendarUserActionType::kDateCellActivated:
    case CalendarUserActionType::kMonthDownArrowActivated:
    case CalendarUserActionType::kMonthUpArrowActivated:
    case CalendarUserActionType::kScrolled:
    case CalendarUserActionType::kKeyboardNavigation:
    case CalendarUserActionType::kResetToTodayPressed:
    case CalendarUserActionType::kTodaysEventsInUpNextPressed:
    case CalendarUserActionType::kScrollInUpNext:
    case CalendarUserActionType::kEventListClosed:
    case CalendarUserActionType::kSettingsButtonPressed:
      return false;
    case CalendarUserActionType::kEventListItemPressed:
    case CalendarUserActionType::kUpNextItemPressed:
    case CalendarUserActionType::kEventListItemJoinButtonPressed:
    case CalendarUserActionType::kUpNextJoinButtonPressed:
    case CalendarUserActionType::kCalendarLaunchedFromEmptyEventList:
      return true;
  }
}

void RecordCalendarUserAction(CalendarUserActionType action) {
  if (ActionOpensCalendarWebUi(action)) {
    base::UmaHistogramEnumeration(kCalendarWebUiOpened, action);
  }
  base::UmaHistogramEnumeration(kCalendarUserAction, action);
}

}  // namespace

CalendarEventSource GetEventType(const ui::Event& event) {
  if (event.IsGestureEvent())
    return CalendarEventSource::kTap;

  if (event.IsMouseEvent())
    return CalendarEventSource::kClick;

  if (event.IsKeyEvent())
    return CalendarEventSource::kKeyboard;

  if (event.IsTouchEvent())
    return CalendarEventSource::kStylus;

  NOTREACHED();
}

void RecordCalendarShowMetrics(
    CalendarViewShowSource show_source,
    calendar_metrics::CalendarEventSource event_source) {
  std::string histogram_name = kCalendarViewShowSourcePrefix;
  switch (show_source) {
    case CalendarViewShowSource::kDateView:
      histogram_name += "DateView";
      break;
    case CalendarViewShowSource::kTimeView:
      histogram_name += "TimeView";
      break;
    case CalendarViewShowSource::kAccelerator:
      histogram_name += "Keyboard";
      break;
  }

  base::UmaHistogramEnumeration(histogram_name, event_source);
}

void RecordCalendarDateCellActivated(const ui::Event& event) {
  RecordCalendarUserAction(CalendarUserActionType::kDateCellActivated);

  base::UmaHistogramEnumeration(kCalendarDateCellActivated,
                                GetEventType(event));
}

void RecordMonthArrowButtonActivated(bool up, const ui::Event& event) {
  RecordCalendarUserAction(
      up ? CalendarUserActionType::kMonthUpArrowActivated
         : CalendarUserActionType::kMonthDownArrowActivated);

  base::UmaHistogramEnumeration(up ? kCalendarMonthUpArrowButtonActivated
                                   : kCalendarMonthDownArrowButtonActivated,
                                GetEventType(event));
}

void RecordEventListItemActivated(const ui::Event& event) {
  RecordCalendarUserAction(CalendarUserActionType::kEventListItemPressed);

  base::UmaHistogramEnumeration(kCalendarEventListItemActivated,
                                GetEventType(event));
}

void RecordEventListForTodayActivated() {
  RecordCalendarUserAction(
      CalendarUserActionType::kTodaysEventsInUpNextPressed);
}

void RecordMonthDwellTime(const base::TimeDelta& dwell_time) {
  base::UmaHistogramMediumTimes(kCalendarMonthDwellTime, dwell_time);
}

void RecordResetToTodayPressed() {
  RecordCalendarUserAction(CalendarUserActionType::kResetToTodayPressed);
}

void RecordScrollSource(CalendarViewScrollSource source) {
  RecordCalendarUserAction(CalendarUserActionType::kScrolled);

  base::UmaHistogramEnumeration(kCalendarScrollSource, source);
}

ui::AnimationThroughputReporter CreateAnimationReporter(
    views::View* view,
    const std::string& animation_histogram_name) {
  // TODO(crbug.com/1297376): Add unit tests for animation metrics recording.
  return ui::AnimationThroughputReporter(
      view->layer()->GetAnimator(),
      metrics_util::ForSmoothnessV3(base::BindRepeating(
          [](const std::string& animation_histogram_name, int smoothness) {
            base::UmaHistogramPercentage(animation_histogram_name, smoothness);
          },
          animation_histogram_name)));
}

void RecordCalendarKeyboardNavigation(
    const CalendarKeyboardNavigationSource key_source) {
  RecordCalendarUserAction(CalendarUserActionType::kKeyboardNavigation);

  base::UmaHistogramEnumeration(kCalendarKeyboardNavigation, key_source);
}

void RecordEventListItemInUpNextLaunched(const ui::Event& event) {
  RecordCalendarUserAction(CalendarUserActionType::kUpNextItemPressed);

  base::UmaHistogramEnumeration(kCalendarEventListItemInUpNextPressed,
                                GetEventType(event));
}

void RecordUpNextEventCount(const int event_count) {
  base::UmaHistogramCounts100(kCalendarUpNextEventDisplayedCount, event_count);
}

void RecordJoinButtonPressedFromEventListView(const ui::Event& event) {
  RecordCalendarUserAction(
      CalendarUserActionType::kEventListItemJoinButtonPressed);

  base::UmaHistogramEnumeration(kCalendarEventListItemJoinButtonPressed,
                                GetEventType(event));
}

void RecordJoinButtonPressedFromUpNextView(const ui::Event& event) {
  RecordCalendarUserAction(CalendarUserActionType::kUpNextJoinButtonPressed);

  base::UmaHistogramEnumeration(kCalendarUpNextJoinButtonPressed,
                                GetEventType(event));
}

void RecordEventListEventCount(const int event_count) {
  base::UmaHistogramCounts100(kCalendarEventListEventDisplayedCount,
                              event_count);
}

void RecordEventsDisplayedToUser() {
  base::UmaHistogramBoolean(kCalendarEventsDisplayedToUser, true);
}

void RecordScrollEventInUpNext() {
  RecordCalendarUserAction(CalendarUserActionType::kScrollInUpNext);
}

void RecordCalendarLaunchedFromEmptyEventList() {
  RecordCalendarUserAction(
      CalendarUserActionType::kCalendarLaunchedFromEmptyEventList);
}

void RecordEventListClosed() {
  RecordCalendarUserAction(CalendarUserActionType::kEventListClosed);
}

void RecordSettingsButtonPressed() {
  RecordCalendarUserAction(CalendarUserActionType::kSettingsButtonPressed);
}

void RecordCalendarListFetchDuration(const base::TimeDelta fetch_duration) {
  base::UmaHistogramTimes(kCalendarFetchCalendarsFetchDuration, fetch_duration);
}

void RecordCalendarListFetchErrorCode(google_apis::ApiErrorCode error) {
  base::UmaHistogramSparse(kCalendarFetchCalendarsResult, error);
}

void RecordCalendarListFetchTimeout(bool fetch_timed_out) {
  base::UmaHistogramBoolean(kCalendarFetchCalendarsTimeout, fetch_timed_out);
}

void RecordEventListFetchDuration(const base::TimeDelta fetch_duration) {
  base::UmaHistogramTimes(kCalendarFetchEventsFetchDuration, fetch_duration);
}

void RecordEventListFetchErrorCode(google_apis::ApiErrorCode error) {
  base::UmaHistogramSparse(kCalendarFetchEventsResult, error);
}

void RecordEventListFetchTimeout(bool fetch_timed_out) {
  base::UmaHistogramBoolean(kCalendarFetchEventsTimeout, fetch_timed_out);
}

void RecordEventListFetchesTotalDuration(const base::TimeDelta fetch_duration) {
  base::UmaHistogramTimes(kCalendarFetchEventsTotalFetchDuration,
                          fetch_duration);
}

void RecordSingleMonthSizeInBytes(size_t single_month_cache_size) {
  base::UmaHistogramCounts1M(kCalendarFetchEventsSingleMonthSize,
                             single_month_cache_size);
}

void RecordTotalEventsCacheSizeInMonths(unsigned int events_cache_size) {
  base::UmaHistogramCounts100000(kCalendarFetchEventsTotalCacheSizeMonths,
                                 events_cache_size);
}

void RecordTotalSelectedCalendars(unsigned int selected_calendars) {
  base::UmaHistogramCounts100000(kCalendarFetchCalendarsTotalSelectedCalendars,
                                 selected_calendars);
}

void RecordTimeToSeeTodaysEventDots(const base::TimeDelta time_elapsed,
                                    bool multi_calendar_enabled) {
  if (multi_calendar_enabled) {
    base::UmaHistogramMediumTimes(
        kCalendarTimeToSeeTodaysEventDotsForMultiCalendar, time_elapsed);
  } else {
    base::UmaHistogramMediumTimes(kCalendarTimeToSeeTodaysEventDots,
                                  time_elapsed);
  }
}

}  // namespace calendar_metrics

}  // namespace ash