user_metrics_recorder.cc 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Copyright 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/metrics/user_metrics_recorder.h"
  5. #include <memory>
  6. #include <vector>
  7. #include "ash/app_list/app_list_metrics.h"
  8. #include "ash/constants/ash_pref_names.h"
  9. #include "ash/login/ui/lock_screen.h"
  10. #include "ash/metrics/demo_session_metrics_recorder.h"
  11. #include "ash/metrics/desktop_task_switch_metric_recorder.h"
  12. #include "ash/metrics/pointer_metrics_recorder.h"
  13. #include "ash/metrics/stylus_metrics_recorder.h"
  14. #include "ash/public/cpp/accessibility_controller_enums.h"
  15. #include "ash/public/cpp/shelf_item.h"
  16. #include "ash/public/cpp/shelf_model.h"
  17. #include "ash/session/session_controller_impl.h"
  18. #include "ash/shelf/shelf.h"
  19. #include "ash/shelf/shelf_view.h"
  20. #include "ash/shell.h"
  21. #include "ash/wm/window_state.h"
  22. #include "base/metrics/histogram_macros.h"
  23. #include "base/metrics/user_metrics.h"
  24. #include "components/prefs/pref_service.h"
  25. namespace ash {
  26. namespace {
  27. using ::chromeos::WindowStateType;
  28. // Time between calls to "RecordPeriodicMetrics".
  29. constexpr base::TimeDelta kRecordPeriodicMetricsInterval = base::Minutes(30);
  30. enum ActiveWindowStateType {
  31. ACTIVE_WINDOW_STATE_TYPE_NO_ACTIVE_WINDOW,
  32. ACTIVE_WINDOW_STATE_TYPE_OTHER,
  33. ACTIVE_WINDOW_STATE_TYPE_MAXIMIZED,
  34. ACTIVE_WINDOW_STATE_TYPE_FULLSCREEN,
  35. ACTIVE_WINDOW_STATE_TYPE_SNAPPED,
  36. ACTIVE_WINDOW_STATE_TYPE_PINNED,
  37. ACTIVE_WINDOW_STATE_TYPE_TRUSTED_PINNED,
  38. ACTIVE_WINDOW_STATE_TYPE_PIP,
  39. ACTIVE_WINDOW_STATE_TYPE_FLOATED,
  40. ACTIVE_WINDOW_STATE_TYPE_COUNT,
  41. };
  42. ActiveWindowStateType GetActiveWindowState() {
  43. ActiveWindowStateType active_window_state_type =
  44. ACTIVE_WINDOW_STATE_TYPE_NO_ACTIVE_WINDOW;
  45. WindowState* active_window_state = WindowState::ForActiveWindow();
  46. if (active_window_state) {
  47. switch (active_window_state->GetStateType()) {
  48. case WindowStateType::kMaximized:
  49. active_window_state_type = ACTIVE_WINDOW_STATE_TYPE_MAXIMIZED;
  50. break;
  51. case WindowStateType::kFullscreen:
  52. active_window_state_type = ACTIVE_WINDOW_STATE_TYPE_FULLSCREEN;
  53. break;
  54. case WindowStateType::kPrimarySnapped:
  55. case WindowStateType::kSecondarySnapped:
  56. active_window_state_type = ACTIVE_WINDOW_STATE_TYPE_SNAPPED;
  57. break;
  58. case WindowStateType::kPinned:
  59. active_window_state_type = ACTIVE_WINDOW_STATE_TYPE_PINNED;
  60. break;
  61. case WindowStateType::kTrustedPinned:
  62. active_window_state_type = ACTIVE_WINDOW_STATE_TYPE_TRUSTED_PINNED;
  63. break;
  64. case WindowStateType::kPip:
  65. active_window_state_type = ACTIVE_WINDOW_STATE_TYPE_PIP;
  66. break;
  67. case WindowStateType::kFloated:
  68. active_window_state_type = ACTIVE_WINDOW_STATE_TYPE_FLOATED;
  69. break;
  70. case WindowStateType::kDefault:
  71. case WindowStateType::kNormal:
  72. case WindowStateType::kMinimized:
  73. case WindowStateType::kInactive:
  74. active_window_state_type = ACTIVE_WINDOW_STATE_TYPE_OTHER;
  75. break;
  76. }
  77. }
  78. return active_window_state_type;
  79. }
  80. // Returns true if kiosk mode is active.
  81. bool IsKioskModeActive() {
  82. return Shell::Get()->session_controller()->login_status() ==
  83. LoginStatus::KIOSK_APP;
  84. }
  85. // Returns true if there is an active user and their session isn't currently
  86. // locked.
  87. bool IsUserActive() {
  88. SessionControllerImpl* session = Shell::Get()->session_controller();
  89. return session->IsActiveUserSessionStarted() && !session->IsScreenLocked();
  90. }
  91. // Records the number of items in the shelf as an UMA statistic.
  92. void RecordShelfItemCounts() {
  93. int pinned_item_count = 0;
  94. int unpinned_item_count = 0;
  95. for (const ShelfItem& item : ShelfModel::Get()->items()) {
  96. if (item.type == TYPE_PINNED_APP || item.type == TYPE_BROWSER_SHORTCUT)
  97. ++pinned_item_count;
  98. else
  99. ++unpinned_item_count;
  100. }
  101. UMA_HISTOGRAM_COUNTS_100("Ash.Shelf.NumberOfItems",
  102. pinned_item_count + unpinned_item_count);
  103. UMA_HISTOGRAM_COUNTS_100("Ash.Shelf.NumberOfPinnedItems", pinned_item_count);
  104. UMA_HISTOGRAM_COUNTS_100("Ash.Shelf.NumberOfUnpinnedItems",
  105. unpinned_item_count);
  106. }
  107. } // namespace
  108. UserMetricsRecorder::UserMetricsRecorder() {
  109. StartTimer();
  110. login_metrics_recorder_ = std::make_unique<LoginMetricsRecorder>();
  111. }
  112. UserMetricsRecorder::UserMetricsRecorder(bool record_periodic_metrics) {
  113. if (record_periodic_metrics)
  114. StartTimer();
  115. }
  116. UserMetricsRecorder::~UserMetricsRecorder() {
  117. timer_.Stop();
  118. }
  119. // static
  120. void UserMetricsRecorder::RecordUserClickOnTray(
  121. LoginMetricsRecorder::TrayClickTarget target) {
  122. LoginMetricsRecorder* recorder =
  123. Shell::Get()->metrics()->login_metrics_recorder();
  124. recorder->RecordUserTrayClick(target);
  125. }
  126. // static
  127. void UserMetricsRecorder::RecordUserClickOnShelfButton(
  128. LoginMetricsRecorder::ShelfButtonClickTarget target) {
  129. LoginMetricsRecorder* recorder =
  130. Shell::Get()->metrics()->login_metrics_recorder();
  131. recorder->RecordUserShelfButtonClick(target);
  132. }
  133. void UserMetricsRecorder::StartDemoSessionMetricsRecording() {
  134. demo_session_metrics_recorder_ =
  135. std::make_unique<DemoSessionMetricsRecorder>();
  136. Shell::Get()->AddPreTargetHandler(demo_session_metrics_recorder_.get());
  137. }
  138. void UserMetricsRecorder::OnShellInitialized() {
  139. // Lazy creation of the DesktopTaskSwitchMetricRecorder because it accesses
  140. // Shell::Get() which is not available when |this| is instantiated.
  141. if (!desktop_task_switch_metric_recorder_) {
  142. desktop_task_switch_metric_recorder_ =
  143. std::make_unique<DesktopTaskSwitchMetricRecorder>();
  144. }
  145. pointer_metrics_recorder_ = std::make_unique<PointerMetricsRecorder>();
  146. stylus_metrics_recorder_ = std::make_unique<StylusMetricsRecorder>();
  147. }
  148. void UserMetricsRecorder::OnShellShuttingDown() {
  149. // Doing the nullptr check as the recorder is not initialized outside demo
  150. // session. It was initialized during StartDemoSessionMetricsRecording().
  151. if (demo_session_metrics_recorder_ != nullptr) {
  152. Shell::Get()->RemovePreTargetHandler(demo_session_metrics_recorder_.get());
  153. demo_session_metrics_recorder_.reset();
  154. }
  155. desktop_task_switch_metric_recorder_.reset();
  156. // To clean up pointer_metrics_recorder_ and stylus_metrics_recorder_
  157. // properly, a valid shell instance is required, so explicitly delete them
  158. // before the shell instance becomes invalid.
  159. pointer_metrics_recorder_.reset();
  160. stylus_metrics_recorder_.reset();
  161. }
  162. void UserMetricsRecorder::RecordPeriodicMetrics() {
  163. Shelf* shelf = Shelf::ForWindow(Shell::GetPrimaryRootWindow());
  164. // TODO(bruthig): Investigating whether the check for |manager| is necessary
  165. // and add tests if it is.
  166. if (shelf) {
  167. // TODO(bruthig): Consider tracking the time spent in each alignment.
  168. UMA_HISTOGRAM_ENUMERATION("Ash.ShelfAlignmentOverTime",
  169. static_cast<ShelfAlignmentUmaEnumValue>(
  170. shelf->SelectValueForShelfAlignment(
  171. SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM,
  172. SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT,
  173. SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT)),
  174. SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT);
  175. }
  176. if (IsUserInActiveDesktopEnvironment()) {
  177. RecordShelfItemCounts();
  178. RecordPeriodicAppListMetrics();
  179. base::UmaHistogramBoolean(
  180. "Ash.AppNotificationBadgingPref",
  181. Shell::Get()->session_controller()->GetActivePrefService()->GetBoolean(
  182. prefs::kAppNotificationBadgingEnabled));
  183. }
  184. // TODO(bruthig): Find out if this should only be logged when the user is
  185. // active.
  186. // TODO(bruthig): Consider tracking how long a particular type of window is
  187. // active at a time.
  188. UMA_HISTOGRAM_ENUMERATION("Ash.ActiveWindowShowTypeOverTime",
  189. GetActiveWindowState(),
  190. ACTIVE_WINDOW_STATE_TYPE_COUNT);
  191. }
  192. bool UserMetricsRecorder::IsUserInActiveDesktopEnvironment() const {
  193. return IsUserActive() && !IsKioskModeActive();
  194. }
  195. void UserMetricsRecorder::StartTimer() {
  196. timer_.Start(FROM_HERE, kRecordPeriodicMetricsInterval, this,
  197. &UserMetricsRecorder::RecordPeriodicMetrics);
  198. }
  199. } // namespace ash