blob: f26ef612275f8c8a05e98c0de2be119a13fdb23f [file] [log] [blame]
// 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 "ash/app_list/app_list_metrics.h"
#include <algorithm>
#include "ash/app_list/model/app_list_model.h"
#include "ash/app_list/model/search/search_model.h"
#include "ash/app_list/model/search/search_result.h"
#include "ash/public/cpp/app_menu_constants.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "ui/compositor/compositor.h"
namespace ash {
namespace {
// These constants affect logging, and should not be changed without
// deprecating the following UMA histograms:
// - Apps.AppListTileClickIndexAndQueryLength
// - Apps.AppListResultClickIndexAndQueryLength
constexpr int kMaxLoggedQueryLength = 10;
constexpr int kMaxLoggedSuggestionIndex = 6;
constexpr int kMaxLoggedHistogramValue =
(kMaxLoggedSuggestionIndex + 1) * kMaxLoggedQueryLength +
kMaxLoggedSuggestionIndex;
} // namespace
// The UMA histogram that logs smoothness of folder show/hide animation.
constexpr char kFolderShowHideAnimationSmoothness[] =
"Apps.AppListFolder.ShowHide.AnimationSmoothness";
// The UMA histogram that logs smoothness of pagination animation.
constexpr char kPaginationTransitionAnimationSmoothness[] =
"Apps.PaginationTransition.AnimationSmoothness";
constexpr char kPaginationTransitionAnimationSmoothnessInTablet[] =
"Apps.PaginationTransition.AnimationSmoothness.TabletMode";
constexpr char kPaginationTransitionAnimationSmoothnessInClamshell[] =
"Apps.PaginationTransition.AnimationSmoothness.ClamshellMode";
// The UMA histogram that logs which state search results are opened from.
constexpr char kAppListSearchResultOpenSourceHistogram[] =
"Apps.AppListSearchResultOpenedSource";
// The UMA hisotogram that logs the action user performs on zero state
// search result.
constexpr char kAppListZeroStateSearchResultUserActionHistogram[] =
"Apps.AppList.ZeroStateSearchResultUserActionType";
// The UMA histogram that logs user's decision(remove or cancel) for zero state
// search result removal confirmation.
constexpr char kAppListZeroStateSearchResultRemovalHistogram[] =
"Apps.AppList.ZeroStateSearchResultRemovalDecision";
// The UMA histogram that logs the length of the query when user abandons
// results of a queried search or recommendations of zero state(zero length
// query) in launcher UI.
constexpr char kSearchAbandonQueryLengthHistogram[] =
"Apps.AppListSearchAbandonQueryLength";
// The base UMA histogram that logs app launches within the AppList and shelf.
constexpr char kAppListAppLaunched[] = "Apps.AppListAppLaunchedV2";
// The UMA histograms that log app launches within the AppList and shelf. The
// app launches are divided by histogram for each of the the different AppList
// states.
constexpr char kAppListAppLaunchedClosed[] = "Apps.AppListAppLaunchedV2.Closed";
constexpr char kAppListAppLaunchedPeeking[] =
"Apps.AppListAppLaunchedV2.Peeking";
constexpr char kAppListAppLaunchedHalf[] = "Apps.AppListAppLaunchedV2.Half";
constexpr char kAppListAppLaunchedFullscreenAllApps[] =
"Apps.AppListAppLaunchedV2.FullscreenAllApps";
constexpr char kAppListAppLaunchedFullscreenSearch[] =
"Apps.AppListAppLaunchedV2.FullscreenSearch";
constexpr char kAppListAppLaunchedHomecherClosed[] =
"Apps.AppListAppLaunchedV2.HomecherClosed";
constexpr char kAppListAppLaunchedHomecherAllApps[] =
"Apps.AppListAppLaunchedV2.HomecherAllApps";
constexpr char kAppListAppLaunchedHomecherSearch[] =
"Apps.AppListAppLaunchedV2.HomecherSearch";
// The different sources from which a search result is displayed. These values
// are written to logs. New enum values can be added, but existing enums must
// never be renumbered or deleted and reused.
enum class ApplistSearchResultOpenedSource {
kHalfClamshell = 0,
kFullscreenClamshell = 1,
kFullscreenTablet = 2,
kMaxApplistSearchResultOpenedSource = 3,
};
void AppListRecordPageSwitcherSourceByEventType(ui::EventType type,
bool is_tablet_mode) {
AppListPageSwitcherSource source;
switch (type) {
case ui::ET_MOUSEWHEEL:
source = kMouseWheelScroll;
break;
case ui::ET_SCROLL:
source = kMousePadScroll;
break;
case ui::ET_GESTURE_SCROLL_END:
source = kSwipeAppGrid;
break;
case ui::ET_SCROLL_FLING_START:
source = kFlingAppGrid;
break;
case ui::ET_MOUSE_RELEASED:
source = kMouseDrag;
break;
default:
NOTREACHED();
return;
}
RecordPageSwitcherSource(source, is_tablet_mode);
}
void RecordPageSwitcherSource(AppListPageSwitcherSource source,
bool is_tablet_mode) {
UMA_HISTOGRAM_ENUMERATION(kAppListPageSwitcherSourceHistogram, source,
kMaxAppListPageSwitcherSource);
if (is_tablet_mode) {
UMA_HISTOGRAM_ENUMERATION(kAppListPageSwitcherSourceHistogramInTablet,
source, kMaxAppListPageSwitcherSource);
} else {
UMA_HISTOGRAM_ENUMERATION(kAppListPageSwitcherSourceHistogramInClamshell,
source, kMaxAppListPageSwitcherSource);
}
}
APP_LIST_EXPORT void RecordSearchResultOpenSource(
const SearchResult* result,
const AppListModel* model,
const SearchModel* search_model) {
// Record the search metric if the SearchResult is not a suggested app.
if (result->is_recommendation())
return;
ApplistSearchResultOpenedSource source;
AppListViewState state = model->state_fullscreen();
if (search_model->tablet_mode()) {
source = ApplistSearchResultOpenedSource::kFullscreenTablet;
} else {
source = state == AppListViewState::kHalf
? ApplistSearchResultOpenedSource::kHalfClamshell
: ApplistSearchResultOpenedSource::kFullscreenClamshell;
}
UMA_HISTOGRAM_ENUMERATION(
kAppListSearchResultOpenSourceHistogram, source,
ApplistSearchResultOpenedSource::kMaxApplistSearchResultOpenedSource);
}
void RecordSearchLaunchIndexAndQueryLength(
SearchResultLaunchLocation launch_location,
int query_length,
int suggestion_index) {
if (suggestion_index < 0) {
LOG(ERROR) << "Received invalid suggestion index.";
return;
}
query_length = std::min(query_length, kMaxLoggedQueryLength);
suggestion_index = std::min(suggestion_index, kMaxLoggedSuggestionIndex);
const int logged_value =
(kMaxLoggedSuggestionIndex + 1) * query_length + suggestion_index;
if (launch_location == SearchResultLaunchLocation::kResultList) {
UMA_HISTOGRAM_EXACT_LINEAR(kAppListResultLaunchIndexAndQueryLength,
logged_value, kMaxLoggedHistogramValue);
UMA_HISTOGRAM_BOOLEAN(kAppListResultLaunchIsEmptyQuery, query_length == 0);
} else if (launch_location == SearchResultLaunchLocation::kTileList) {
UMA_HISTOGRAM_EXACT_LINEAR(kAppListTileLaunchIndexAndQueryLength,
logged_value, kMaxLoggedHistogramValue);
}
}
void RecordSearchAbandonWithQueryLengthHistogram(int query_length) {
UMA_HISTOGRAM_EXACT_LINEAR(kSearchAbandonQueryLengthHistogram,
std::min(query_length, kMaxLoggedQueryLength),
kMaxLoggedQueryLength);
}
void RecordZeroStateSearchResultUserActionHistogram(
ZeroStateSearchResultUserActionType action) {
UMA_HISTOGRAM_ENUMERATION(kAppListZeroStateSearchResultUserActionHistogram,
action);
}
void RecordZeroStateSearchResultRemovalHistogram(
ZeroStateSearchResutRemovalConfirmation removal_decision) {
UMA_HISTOGRAM_ENUMERATION(kAppListZeroStateSearchResultRemovalHistogram,
removal_decision);
}
void RecordAppListAppLaunched(AppListLaunchedFrom launched_from,
AppListViewState app_list_state,
bool is_tablet_mode,
bool home_launcher_shown) {
UMA_HISTOGRAM_ENUMERATION(kAppListAppLaunched, launched_from);
switch (app_list_state) {
case AppListViewState::kClosed:
UMA_HISTOGRAM_ENUMERATION(kAppListAppLaunchedClosed, launched_from);
break;
case AppListViewState::kPeeking:
UMA_HISTOGRAM_ENUMERATION(kAppListAppLaunchedPeeking, launched_from);
break;
case AppListViewState::kHalf:
UMA_HISTOGRAM_ENUMERATION(kAppListAppLaunchedHalf, launched_from);
break;
case AppListViewState::kFullscreenAllApps:
if (is_tablet_mode) {
if (home_launcher_shown) {
UMA_HISTOGRAM_ENUMERATION(kAppListAppLaunchedHomecherAllApps,
launched_from);
} else {
UMA_HISTOGRAM_ENUMERATION(kAppListAppLaunchedHomecherClosed,
launched_from);
}
} else {
UMA_HISTOGRAM_ENUMERATION(kAppListAppLaunchedFullscreenAllApps,
launched_from);
}
break;
case AppListViewState::kFullscreenSearch:
if (is_tablet_mode) {
if (home_launcher_shown) {
UMA_HISTOGRAM_ENUMERATION(kAppListAppLaunchedHomecherSearch,
launched_from);
} else {
// (http://crbug.com/947729) Search box still expanded when opening
// launcher in tablet mode
UMA_HISTOGRAM_ENUMERATION(kAppListAppLaunchedHomecherClosed,
launched_from);
}
} else {
UMA_HISTOGRAM_ENUMERATION(kAppListAppLaunchedFullscreenSearch,
launched_from);
}
break;
}
}
bool IsCommandIdAnAppLaunch(int command_id_number) {
CommandId command_id = static_cast<CommandId>(command_id_number);
// Consider all platform app menu options as launches.
if (command_id >= CommandId::EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
command_id < CommandId::EXTENSIONS_CONTEXT_CUSTOM_LAST) {
return true;
}
// Consider all arc app shortcut options as launches.
if (command_id >= CommandId::LAUNCH_APP_SHORTCUT_FIRST &&
command_id < CommandId::LAUNCH_APP_SHORTCUT_LAST) {
return true;
}
switch (command_id) {
// Used by ShelfContextMenu (shelf).
case CommandId::MENU_OPEN_NEW:
case CommandId::MENU_NEW_WINDOW:
case CommandId::MENU_NEW_INCOGNITO_WINDOW:
// Used by AppContextMenu and/or ShelfContextMenu.
case CommandId::LAUNCH_NEW:
case CommandId::SHOW_APP_INFO:
case CommandId::OPTIONS:
case CommandId::APP_CONTEXT_MENU_NEW_WINDOW:
case CommandId::APP_CONTEXT_MENU_NEW_INCOGNITO_WINDOW:
case CommandId::SETTINGS:
// Used by both AppContextMenu and ShelfContextMenu for app shortcuts.
case CommandId::LAUNCH_APP_SHORTCUT_FIRST:
case CommandId::LAUNCH_APP_SHORTCUT_LAST:
return true;
// Used by ShelfContextMenu (shelf).
case CommandId::MENU_CLOSE:
case CommandId::MENU_PIN:
case CommandId::LAUNCH_TYPE_PINNED_TAB:
case CommandId::LAUNCH_TYPE_REGULAR_TAB:
case CommandId::LAUNCH_TYPE_FULLSCREEN:
case CommandId::LAUNCH_TYPE_WINDOW:
case CommandId::LAUNCH_TYPE_TABBED_WINDOW:
case CommandId::SWAP_WITH_NEXT:
case CommandId::SWAP_WITH_PREVIOUS:
// Used by AppMenuModelAdapter
case CommandId::NOTIFICATION_CONTAINER:
// Used by CrostiniShelfContextMenu.
case CommandId::CROSTINI_USE_LOW_DENSITY:
case CommandId::CROSTINI_USE_HIGH_DENSITY:
// Used by AppContextMenu.
case CommandId::TOGGLE_PIN:
case CommandId::UNINSTALL:
case CommandId::REMOVE_FROM_FOLDER:
case CommandId::INSTALL:
case CommandId::USE_LAUNCH_TYPE_PINNED:
case CommandId::USE_LAUNCH_TYPE_REGULAR:
case CommandId::USE_LAUNCH_TYPE_FULLSCREEN:
case CommandId::USE_LAUNCH_TYPE_WINDOW:
case CommandId::USE_LAUNCH_TYPE_TABBED_WINDOW:
case CommandId::USE_LAUNCH_TYPE_COMMAND_END:
case CommandId::STOP_APP:
case CommandId::EXTENSIONS_CONTEXT_CUSTOM_FIRST:
case CommandId::EXTENSIONS_CONTEXT_CUSTOM_LAST:
case CommandId::COMMAND_ID_COUNT:
return false;
}
NOTREACHED();
return false;
}
FolderShowHideAnimationReporter::FolderShowHideAnimationReporter() = default;
FolderShowHideAnimationReporter::~FolderShowHideAnimationReporter() = default;
void FolderShowHideAnimationReporter::Report(int value) {
UMA_HISTOGRAM_PERCENTAGE(kFolderShowHideAnimationSmoothness, value);
}
PaginationTransitionAnimationReporter::PaginationTransitionAnimationReporter() =
default;
PaginationTransitionAnimationReporter::
~PaginationTransitionAnimationReporter() = default;
void PaginationTransitionAnimationReporter::Report(int value) {
UMA_HISTOGRAM_PERCENTAGE(kPaginationTransitionAnimationSmoothness, value);
if (is_tablet_mode_) {
UMA_HISTOGRAM_PERCENTAGE(kPaginationTransitionAnimationSmoothnessInTablet,
value);
} else {
UMA_HISTOGRAM_PERCENTAGE(
kPaginationTransitionAnimationSmoothnessInClamshell, value);
}
}
AppListAnimationMetricsRecorder::AppListAnimationMetricsRecorder(
ui::AnimationMetricsReporter* reporter)
: ui::AnimationMetricsRecorder(reporter) {}
AppListAnimationMetricsRecorder::~AppListAnimationMetricsRecorder() = default;
void AppListAnimationMetricsRecorder::OnAnimationStart(
base::TimeDelta expected_duration,
ui::Compositor* compositor) {
if (!compositor)
return;
animation_started_ = true;
ui::AnimationMetricsRecorder::OnAnimationStart(
compositor->activated_frame_count(), base::TimeTicks::Now(),
expected_duration);
}
void AppListAnimationMetricsRecorder::OnAnimationEnd(
ui::Compositor* compositor) {
if (!animation_started_)
return;
animation_started_ = false;
if (!compositor)
return;
ui::AnimationMetricsRecorder::OnAnimationEnd(
compositor->activated_frame_count(), compositor->refresh_rate());
}
} // namespace ash