1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
|
// Copyright 2020 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/capture_mode/capture_mode_metrics.h"
#include "ash/capture_mode/capture_mode_behavior.h"
#include "ash/capture_mode/capture_mode_types.h"
#include "ash/shell.h"
#include "ash/system/toast/anchored_nudge_manager_impl.h"
#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
namespace ash {
namespace {
constexpr char kCaptureModeMetricCommonPrefix[] = "Ash.CaptureModeController.";
constexpr char kEndRecordingReasonHistogramRootWord[] = "EndRecordingReason";
constexpr char kBarButtonHistogramRootWord[] = "BarButtons";
constexpr char kCaptureAudioRecordingModeHistogramRootWord[] =
"AudioRecordingMode";
constexpr char kCaptureConfigurationHistogramRootWord[] =
"CaptureConfiguration";
constexpr char kCaptureRegionAdjustmentHistogramRootWord[] =
"CaptureRegionAdjusted";
constexpr char kDemoToolsEnabledOnRecordingStartRootWord[] =
"DemoToolsEnabledOnRecordingStart";
constexpr char kEntryPointHistogramRootWord[] = "EntryPoint";
constexpr char kRecordingDurationHistogramRootWord[] = "ScreenRecordingLength";
constexpr char kGifRecordingDurationHistogramRootWord[] = "GIFRecordingLength";
constexpr char kGifRecordingRegionToScreenRatioHistogramRootWord[] =
"GIFRecordingRegionToScreenRatio";
constexpr char kSaveToLocationHistogramRootWord[] = "SaveLocation";
constexpr char kSwitchToDefaultFolderReasonHistogramRootWord[] =
"SwitchToDefaultReason";
constexpr char kRecordingStartsWithCameraRootWord[] =
"RecordingStartsWithCamera";
constexpr char kCameraDisconnectionsDuringRecordingsRootWord[] =
"CameraDisconnectionsDuringRecordings";
constexpr char kCameraReconnectDurationRootWord[] = "CameraReconnectDuration";
constexpr char kRecordingCameraSizeOnStartRootWord[] =
"RecordingCameraSizeOnStart";
constexpr char kRecordingCameraPositionOnStartRootWord[] =
"RecordingCameraPositionOnStart";
constexpr char kGifRecordingFileSizeRootWord[] = "GIFRecordingFileSize";
constexpr char kScreenRecordingFileSizeRootWord[] = "ScreenRecordingFileSize";
constexpr char kNumberOfConnectedCamerasRootWord[] = "NumberOfConnectedCameras";
constexpr char kConsecutiveScreenshotRootWord[] = "ConsecutiveScreenshots";
constexpr char kQuickActionRootWord[] = "QuickAction";
constexpr char kScreenshotsPerDayRootWord[] = "ScreenshotsPerDay";
constexpr char kScreenshotsPerWeekRootWord[] = "ScreenshotsPerWeek";
constexpr char kSearchButtonPressedRootWord[] = "SearchButtonPressed";
constexpr char kSearchButtonShownRootWord[] = "SearchButtonShown";
constexpr char kSwitchesFromInitialModeRootWord[] =
"SwitchesFromInitialCaptureMode";
constexpr char kSearchResultsPanelEntryPointHistogramRootWord[] =
"SearchResultsPanelEntryPoint";
constexpr char kSearchResultsPanelShown[] = "SearchResultsPanelShown";
constexpr char kSearchResultClickedRootWord[] = "SearchResultClicked";
void RecordCaptureModeRecordingDurationInternal(
const std::string& histogram_name,
base::TimeDelta recording_duration) {
// Use the custom counts function instead of custom times so we can record in
// seconds instead of milliseconds. The max bucket is 3 hours.
base::UmaHistogramCustomCounts(histogram_name, recording_duration.InSeconds(),
/*min=*/1,
/*exclusive_max=*/base::Hours(3).InSeconds(),
/*buckets=*/50);
}
// Records capture mode education nudge actions, if the corresponding nudges
// were shown within a particular timeframe or the current session.
void MaybeRecordCaptureModeEducationNudgeActions() {
// Nudge action metrics are only recorded if the corresponding nudge was
// shown, so we can trigger all three arms here.
auto* nudge_manager = AnchoredNudgeManager::Get();
nudge_manager->MaybeRecordNudgeAction(
NudgeCatalogName::kCaptureModeEducationShortcutNudge);
nudge_manager->MaybeRecordNudgeAction(
NudgeCatalogName::kCaptureModeEducationShortcutTutorial);
nudge_manager->MaybeRecordNudgeAction(
NudgeCatalogName::kCaptureModeEducationQuickSettingsNudge);
}
std::string BuildHistogramNameInternal(const char* root_word,
const char* client_metric_component,
bool append_ui_mode_suffix) {
std::string histogram_name(kCaptureModeMetricCommonPrefix);
if (client_metric_component) {
histogram_name.append(client_metric_component);
}
histogram_name.append(root_word);
if (append_ui_mode_suffix) {
histogram_name.append(Shell::Get()->IsInTabletMode() ? ".TabletMode"
: ".ClamshellMode");
}
return histogram_name;
}
} // namespace
void RecordEndRecordingReason(EndRecordingReason reason) {
base::UmaHistogramEnumeration(
BuildHistogramName(kEndRecordingReasonHistogramRootWord,
/*behavior=*/nullptr,
/*append_ui_mode_suffix=*/true),
reason);
}
void RecordCaptureModeBarButtonType(CaptureModeBarButtonType button_type) {
base::UmaHistogramEnumeration(
BuildHistogramName(kBarButtonHistogramRootWord, /*behavior=*/nullptr,
/*append_ui_mode_suffix=*/true),
button_type);
}
void RecordCaptureModeConfiguration(CaptureModeType type,
CaptureModeSource source,
RecordingType recording_type,
AudioRecordingMode audio_mode,
const CaptureModeBehavior* behavior) {
std::string configuration_histogram_name =
BuildHistogramName(kCaptureConfigurationHistogramRootWord, behavior,
/*append_ui_mode_suffix=*/true);
base::UmaHistogramEnumeration(configuration_histogram_name,
GetConfiguration(type, source, recording_type));
if (type == CaptureModeType::kVideo &&
recording_type != RecordingType::kGif) {
base::UmaHistogramEnumeration(
BuildHistogramName(kCaptureAudioRecordingModeHistogramRootWord,
behavior,
/*append_ui_mode_suffix=*/true),
audio_mode);
}
}
void RecordGifRegionToScreenRatio(float ratio_percent) {
base::UmaHistogramPercentage(
BuildHistogramName(kGifRecordingRegionToScreenRatioHistogramRootWord,
/*behavior=*/nullptr, /*append_ui_mode_suffix=*/true),
ratio_percent);
}
void RecordCaptureModeEntryType(CaptureModeEntryType entry_type) {
base::UmaHistogramEnumeration(
BuildHistogramName(kEntryPointHistogramRootWord, /*behavior=*/nullptr,
/*append_ui_mode_suffix=*/true),
entry_type);
MaybeRecordCaptureModeEducationNudgeActions();
}
void RecordCaptureModeRecordingDuration(base::TimeDelta recording_duration,
const CaptureModeBehavior* behavior,
bool is_gif) {
RecordCaptureModeRecordingDurationInternal(
BuildHistogramName(!behavior->ShouldGifBeSupported() || !is_gif
? kRecordingDurationHistogramRootWord
: kGifRecordingDurationHistogramRootWord,
behavior,
/*append_ui_mode_suffix=*/true),
recording_duration);
}
void RecordVideoFileSizeKB(bool is_gif,
const char* client_metric_component,
int size_in_kb) {
if (!Shell::HasInstance()) {
// This function can be called asynchronously after the `Shell` instance had
// already been destroyed.
return;
}
if (size_in_kb < 0) {
LOG(ERROR) << "Failed to calculate the video file size. Is GIF: " << is_gif;
return;
}
base::UmaHistogramMemoryKB(
BuildHistogramNameInternal(is_gif ? kGifRecordingFileSizeRootWord
: kScreenRecordingFileSizeRootWord,
client_metric_component,
/*append_ui_mode_suffix=*/true),
size_in_kb);
}
void RecordCaptureModeSwitchesFromInitialMode(bool switched) {
base::UmaHistogramBoolean(
BuildHistogramName(kSwitchesFromInitialModeRootWord, /*behavior=*/nullptr,
/*append_ui_mode_suffix=*/false),
switched);
}
void RecordNumberOfCaptureRegionAdjustments(
int num_adjustments,
const CaptureModeBehavior* behavior) {
base::UmaHistogramCounts100(
BuildHistogramName(kCaptureRegionAdjustmentHistogramRootWord, behavior,
/*append_ui_mode_suffix=*/true),
num_adjustments);
}
void RecordNumberOfConsecutiveScreenshots(int num_consecutive_screenshots) {
if (num_consecutive_screenshots > 1) {
base::UmaHistogramCounts100(
BuildHistogramName(kConsecutiveScreenshotRootWord, /*behavior=*/nullptr,
/*append_ui_mode_suffix=*/false),
num_consecutive_screenshots);
}
}
void RecordNumberOfScreenshotsTakenInLastDay(
int num_screenshots_taken_in_last_day) {
base::UmaHistogramCounts100(
BuildHistogramName(kScreenshotsPerDayRootWord, /*behavior=*/nullptr,
/*append_ui_mode_suffix=*/false),
num_screenshots_taken_in_last_day);
}
void RecordNumberOfScreenshotsTakenInLastWeek(
int num_screenshots_taken_in_last_week) {
base::UmaHistogramCounts100(
BuildHistogramName(kScreenshotsPerWeekRootWord, /*behavior=*/nullptr,
/*append_ui_mode_suffix=*/false),
num_screenshots_taken_in_last_week);
}
void RecordScreenshotNotificationQuickAction(CaptureQuickAction action) {
base::UmaHistogramEnumeration(
BuildHistogramName(kQuickActionRootWord, /*behavior=*/nullptr,
/*append_ui_mode_suffix=*/false),
action);
}
void RecordSaveToLocation(CaptureModeSaveToLocation save_location,
const CaptureModeBehavior* behavior) {
// Save-to location metrics should not be recorded for the
// projector-inititated capture mode session.
const CaptureModeBehavior* modified_behavior =
behavior->behavior_type() == BehaviorType::kProjector ? nullptr
: behavior;
base::UmaHistogramEnumeration(
BuildHistogramName(kSaveToLocationHistogramRootWord, modified_behavior,
/*append_ui_mode_suffix=*/true),
save_location);
}
void RecordSwitchToDefaultFolderReason(
CaptureModeSwitchToDefaultReason reason) {
base::UmaHistogramEnumeration(
BuildHistogramName(kSwitchToDefaultFolderReasonHistogramRootWord,
/*behavior=*/nullptr,
/*append_ui_mode_suffix=*/true),
reason);
}
CaptureModeConfiguration GetConfiguration(CaptureModeType type,
CaptureModeSource source,
RecordingType recording_type) {
switch (source) {
case CaptureModeSource::kFullscreen:
return type == CaptureModeType::kImage
? CaptureModeConfiguration::kFullscreenScreenshot
: CaptureModeConfiguration::kFullscreenRecording;
case CaptureModeSource::kRegion:
if (type == CaptureModeType::kImage) {
return CaptureModeConfiguration::kRegionScreenshot;
}
return recording_type == RecordingType::kGif
? CaptureModeConfiguration::kRegionGifRecording
: CaptureModeConfiguration::kRegionRecording;
case CaptureModeSource::kWindow:
return type == CaptureModeType::kImage
? CaptureModeConfiguration::kWindowScreenshot
: CaptureModeConfiguration::kWindowRecording;
}
}
void RecordRecordingStartsWithCamera(bool starts_with_camera,
const CaptureModeBehavior* behavior) {
base::UmaHistogramBoolean(
BuildHistogramName(kRecordingStartsWithCameraRootWord, behavior,
/*append_ui_mode_suffix=*/true),
starts_with_camera);
}
void RecordCameraDisconnectionsDuringRecordings(int num_camera_disconnections) {
base::UmaHistogramCounts100(
BuildHistogramName(kCameraDisconnectionsDuringRecordingsRootWord,
/*behavior=*/nullptr,
/*append_ui_mode_suffix=*/true),
num_camera_disconnections);
}
void RecordNumberOfConnectedCameras(int num_camera_connected) {
base::UmaHistogramCounts100(
BuildHistogramName(kNumberOfConnectedCamerasRootWord,
/*behavior=*/nullptr,
/*append_ui_mode_suffix=*/false),
num_camera_connected);
}
void RecordCameraReconnectDuration(int length_in_seconds,
int grace_period_in_seconds) {
base::UmaHistogramCustomCounts(
BuildHistogramName(kCameraReconnectDurationRootWord, nullptr,
/*append_ui_mode_suffix=*/true),
length_in_seconds, 0, grace_period_in_seconds, grace_period_in_seconds);
}
void RecordCameraSizeOnStart(CaptureModeCameraSize camera_size) {
base::UmaHistogramEnumeration(
BuildHistogramName(kRecordingCameraSizeOnStartRootWord,
/*behavior=*/nullptr,
/*append_ui_mode_suffix=*/true),
camera_size);
}
void RecordCameraPositionOnStart(CameraPreviewSnapPosition camera_position) {
base::UmaHistogramEnumeration(
BuildHistogramName(kRecordingCameraPositionOnStartRootWord,
/*behavior=*/nullptr,
/*append_ui_mode_suffix=*/true),
camera_position);
}
void RecordRecordingStartsWithDemoTools(bool demo_tools_enabled,
const CaptureModeBehavior* behavior) {
base::UmaHistogramBoolean(
BuildHistogramName(kDemoToolsEnabledOnRecordingStartRootWord, behavior,
/*append_ui_mode_suffix=*/true),
demo_tools_enabled);
}
void RecordSearchButtonPressed() {
base::UmaHistogramBoolean(BuildHistogramName(kSearchButtonPressedRootWord,
/*behavior=*/nullptr,
/*append_ui_mode_suffix=*/true),
true);
}
void RecordSearchButtonShown() {
base::UmaHistogramBoolean(BuildHistogramName(kSearchButtonShownRootWord,
/*behavior=*/nullptr,
/*append_ui_mode_suffix=*/true),
true);
}
void RecordSearchResultsPanelEntryType(const CaptureModeBehavior* behavior) {
base::UmaHistogramEnumeration(
BuildHistogramName(kSearchResultsPanelEntryPointHistogramRootWord,
/*behavior=*/nullptr,
/*append_ui_mode_suffix=*/true),
behavior->behavior_type() == BehaviorType::kSunfish
? SearchResultsPanelEntryType::kSunfishRegionSelection
: SearchResultsPanelEntryType::kDefaultSearchButton);
}
void RecordSearchResultsPanelShown() {
base::UmaHistogramBoolean(BuildHistogramName(kSearchResultsPanelShown,
/*behavior=*/nullptr,
/*append_ui_mode_suffix=*/true),
true);
}
void RecordSearchResultClicked() {
base::UmaHistogramBoolean(BuildHistogramName(kSearchResultClickedRootWord,
/*behavior=*/nullptr,
/*append_ui_mode_suffix=*/true),
true);
}
std::string BuildHistogramName(const char* const root_word,
const CaptureModeBehavior* behavior,
bool append_ui_mode_suffix) {
return BuildHistogramNameInternal(
root_word, behavior ? behavior->GetClientMetricComponent() : nullptr,
append_ui_mode_suffix);
}
} // namespace ash
|