Skip to content

Commit

Permalink
Add metrics for ChromeOS touch selection dragging and menu actions.
Browse files Browse the repository at this point in the history
Record types of touch selection drags that occur and menu actions that
are requested. This is for some new CrOS touch text editing features,
see design doc: go/cros-touch-text-editing#heading=h.nmwbq0ix2t8q

We would also like to log some metrics to count the actions that occur
within a touch selection "session", will try to do in a followup.

Bug: b:264824468
Change-Id: Id887c72876104b8dc17c7f89855d28d9c2fe5a32
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4775944
Reviewed-by: Darren Shen <shend@chromium.org>
Reviewed-by: Mitsuru Oshima <oshima@chromium.org>
Commit-Queue: Michelle Chen <michellegc@google.com>
Reviewed-by: Robert Flack <flackr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1184456}
  • Loading branch information
Michelle authored and Chromium LUCI CQ committed Aug 16, 2023
1 parent 954c1a9 commit 58ac847
Show file tree
Hide file tree
Showing 17 changed files with 405 additions and 11 deletions.
2 changes: 2 additions & 0 deletions chrome/browser/ui/ash/touch_selection_menu_chromeos.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "ui/display/screen.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/touch_selection/touch_selection_metrics.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button.h"

Expand Down Expand Up @@ -80,6 +81,7 @@ void TouchSelectionMenuChromeOS::OnBeforeBubbleWidgetInit(
TouchSelectionMenuChromeOS::~TouchSelectionMenuChromeOS() = default;

void TouchSelectionMenuChromeOS::ActionButtonPressed() {
ui::RecordTouchSelectionMenuSmartAction();
auto* arc_service_manager = arc::ArcServiceManager::Get();
if (!arc_service_manager)
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_timeouts.h"
#include "build/chromeos_buildflags.h"
Expand Down Expand Up @@ -45,6 +46,7 @@
#include "ui/events/test/event_generator.h"
#include "ui/events/test/motion_event_test_utils.h"
#include "ui/touch_selection/touch_selection_controller_test_api.h"
#include "ui/touch_selection/touch_selection_metrics.h"

namespace content {
namespace {
Expand Down Expand Up @@ -1334,7 +1336,50 @@ IN_PROC_BROWSER_TEST_P(TouchSelectionControllerClientAuraCAPFeatureTest,
ui::TouchSelectionController::INSERTION_ACTIVE);
EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
}
#endif
#endif // BUILDFLAG(IS_CHROMEOS)

#if BUILDFLAG(IS_CHROMEOS_ASH)
// Tests that touch selection dragging records a histogram entry.
IN_PROC_BROWSER_TEST_P(TouchSelectionControllerClientAuraCAPFeatureTest,
SelectionDraggingMetrics) {
// Set the test page up.
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/touch_selection.html"));

base::HistogramTester histogram_tester;
InitSelectionController(false);
RenderWidgetHostViewAura* rwhva = GetRenderWidgetHostViewAura();
gfx::NativeView native_view = rwhva->GetNativeView();
ui::test::EventGenerator generator(native_view->GetRootWindow());
gfx::Point point_in_textfield =
gfx::ToRoundedPoint(GetPointInsideTextfield());
generator.delegate()->ConvertPointFromTarget(native_view,
&point_in_textfield);

// Long press drag selection.
SelectWithLongPress(generator, point_in_textfield);
InitiateTouchSelectionDragging(generator);
DragAndWaitForSelectionUpdate(generator, 9 * kCharacterWidth, 0);
generator.ReleaseTouch();
histogram_tester.ExpectBucketCount(ui::kTouchSelectionDragTypeHistogramName,
ui::TouchSelectionDragType::kLongPressDrag,
1);
histogram_tester.ExpectTotalCount(ui::kTouchSelectionDragTypeHistogramName,
1);

// Double press drag selection. Close the menu if needed so that it doesn't
// get in the way of the double press.
ui::TouchSelectionMenuRunner::GetInstance()->CloseMenu();
SelectWithDoublePress(generator, point_in_textfield);
InitiateTouchSelectionDragging(generator);
DragAndWaitForSelectionUpdate(generator, 10 * kCharacterWidth, 0);
generator.ReleaseTouch();
histogram_tester.ExpectBucketCount(
ui::kTouchSelectionDragTypeHistogramName,
ui::TouchSelectionDragType::kDoublePressDrag, 1);
histogram_tester.ExpectTotalCount(ui::kTouchSelectionDragTypeHistogramName,
2);
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)

// Tests that the quick menu is hidden whenever a touch point is active.
// Flaky: https://crbug.com/803576
Expand Down
18 changes: 18 additions & 0 deletions tools/metrics/histograms/enums.xml
Original file line number Diff line number Diff line change
Expand Up @@ -104647,6 +104647,24 @@ would be helpful to identify which type is being sent.
<int value="5" label="Fastest"/>
</enum>

<enum name="TouchSelectionDragType">
<int value="0" label="Cursor handle drag"/>
<int value="1" label="Selection handle drag"/>
<int value="2" label="Cursor drag"/>
<int value="3" label="Long press drag"/>
<int value="4" label="Double press drag"/>
</enum>

<enum name="TouchSelectionMenuAction">
<int value="0" label="Cut"/>
<int value="1" label="Copy"/>
<int value="2" label="Paste"/>
<int value="3" label="Select all"/>
<int value="4" label="Select word"/>
<int value="5" label="Ellipsis"/>
<int value="6" label="Smart action"/>
</enum>

<enum name="TouchTargetAndDispatchResultType">
<int value="0"
label="Non-root-scroller, non-scrollable document, not handled"/>
Expand Down
20 changes: 20 additions & 0 deletions tools/metrics/histograms/metadata/input/histograms.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1455,6 +1455,26 @@ chromium-metrics-reviews@google.com.
<summary>How emojis were inserted.</summary>
</histogram>

<histogram name="InputMethod.TouchSelection.DragType"
enum="TouchSelectionDragType" expires_after="2024-02-02">
<owner>michellegc@google.com</owner>
<owner>essential-inputs-team@google.com</owner>
<summary>
Type of dragging gesture used to adjust the selection or cursor position on
ChromeOS. Recorded at the end of the drag.
</summary>
</histogram>

<histogram name="InputMethod.TouchSelection.MenuAction"
enum="TouchSelectionMenuAction" expires_after="2024-02-02">
<owner>michellegc@google.com</owner>
<owner>essential-inputs-team@google.com</owner>
<summary>
Action requested by a ChromeOS user from the touch selection menu. Recorded
when the menu button is pressed.
</summary>
</histogram>

<histogram name="InputMethod.VirtualKeyboard.BackspaceCount" units="units"
expires_after="2023-12-24">
<owner>shend@chromium.org</owner>
Expand Down
2 changes: 2 additions & 0 deletions ui/touch_selection/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ component("touch_selection") {
"touch_selection_draggable.h",
"touch_selection_menu_runner.cc",
"touch_selection_menu_runner.h",
"touch_selection_metrics.cc",
"touch_selection_metrics.h",
"ui_touch_selection_export.h",
]

Expand Down
33 changes: 28 additions & 5 deletions ui/touch_selection/touch_selection_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/notreached.h"
#include "ui/touch_selection/touch_selection_metrics.h"

namespace ui {
namespace {
Expand Down Expand Up @@ -198,13 +199,16 @@ void TouchSelectionController::HandleLongPressEvent(
const gfx::PointF& location) {
longpress_drag_selector_.OnLongPressEvent(event_time, location);
response_pending_input_event_ = LONG_PRESS;
drag_selector_initiating_gesture_ = DragSelectorInitiatingGesture::kLongPress;
}

void TouchSelectionController::HandleDoublePressEvent(
base::TimeTicks event_time,
const gfx::PointF& location) {
longpress_drag_selector_.OnDoublePressEvent(event_time, location);
response_pending_input_event_ = LONG_PRESS;
drag_selector_initiating_gesture_ =
DragSelectorInitiatingGesture::kDoublePress;
}

void TouchSelectionController::OnScrollBeginEvent() {
Expand Down Expand Up @@ -380,7 +384,6 @@ bool TouchSelectionController::WillHandleTouchEventImpl(

void TouchSelectionController::OnSwipeToMoveCursorBegin() {
if (config_.hide_active_handle) {
// Hide the handle when magnifier is showing since it can confuse the user.
SetTemporarilyHidden(true);

// If the user has typed something, the insertion handle might be hidden.
Expand All @@ -390,9 +393,10 @@ void TouchSelectionController::OnSwipeToMoveCursorBegin() {
}

void TouchSelectionController::OnSwipeToMoveCursorEnd() {
// Show the handle at the end if magnifier was showing.
if (config_.hide_active_handle)
if (config_.hide_active_handle) {
SetTemporarilyHidden(false);
}
RecordTouchSelectionDrag(ui::TouchSelectionDragType::kCursorDrag);
}

void TouchSelectionController::OnDragBegin(
Expand Down Expand Up @@ -477,10 +481,13 @@ void TouchSelectionController::OnDragUpdate(

void TouchSelectionController::OnDragEnd(
const TouchSelectionDraggable& draggable) {
if (&draggable == insertion_handle_.get())
if (&draggable == insertion_handle_.get()) {
client_->OnSelectionEvent(INSERTION_HANDLE_DRAG_STOPPED);
else
} else {
client_->OnSelectionEvent(SELECTION_HANDLE_DRAG_STOPPED);
}
LogDragType(draggable);
drag_selector_initiating_gesture_ = DragSelectorInitiatingGesture::kNone;
}

bool TouchSelectionController::IsWithinTapSlop(
Expand Down Expand Up @@ -710,4 +717,20 @@ void TouchSelectionController::LogSelectionEnd() {
}
}

void TouchSelectionController::LogDragType(
const TouchSelectionDraggable& draggable) {
if (&draggable == insertion_handle_.get()) {
RecordTouchSelectionDrag(ui::TouchSelectionDragType::kCursorHandleDrag);
} else if (&draggable == start_selection_handle_.get() ||
&draggable == end_selection_handle_.get()) {
RecordTouchSelectionDrag(ui::TouchSelectionDragType::kSelectionHandleDrag);
} else if (drag_selector_initiating_gesture_ ==
DragSelectorInitiatingGesture::kLongPress) {
RecordTouchSelectionDrag(ui::TouchSelectionDragType::kLongPressDrag);
} else if (drag_selector_initiating_gesture_ ==
DragSelectorInitiatingGesture::kDoublePress) {
RecordTouchSelectionDrag(ui::TouchSelectionDragType::kDoublePressDrag);
}
}

} // namespace ui
11 changes: 10 additions & 1 deletion ui/touch_selection/touch_selection_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ class UI_TOUCH_SELECTION_EXPORT TouchSelectionController

enum InputEventType { TAP, REPEATED_TAP, LONG_PRESS, INPUT_EVENT_TYPE_NONE };

enum class DragSelectorInitiatingGesture { kNone, kLongPress, kDoublePress };

bool WillHandleTouchEventImpl(const MotionEvent& event);

// TouchHandleClient implementation.
Expand Down Expand Up @@ -215,6 +217,7 @@ class UI_TOUCH_SELECTION_EXPORT TouchSelectionController
TouchHandle::AnimationStyle GetAnimationStyle(bool was_active) const;

void LogSelectionEnd();
void LogDragType(const TouchSelectionDraggable& draggable);

const raw_ptr<TouchSelectionControllerClient, DanglingUntriaged> client_;
const Config config_;
Expand Down Expand Up @@ -244,9 +247,15 @@ class UI_TOUCH_SELECTION_EXPORT TouchSelectionController
// between lines.
bool anchor_drag_to_selection_start_;

// Longpress drag allows direct manipulation of longpress-initiated selection.
// Allows the text selection to be adjusted by touch dragging after a long
// press or double press initiated selection.
LongPressDragSelector longpress_drag_selector_;

// Used to track whether a selection drag gesture was initiated by a long
// press or double press.
DragSelectorInitiatingGesture drag_selector_initiating_gesture_ =
DragSelectorInitiatingGesture::kNone;

gfx::RectF viewport_rect_;

base::TimeTicks selection_start_time_;
Expand Down
53 changes: 53 additions & 0 deletions ui/touch_selection/touch_selection_metrics.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/touch_selection/touch_selection_metrics.h"

#include "base/metrics/histogram_functions.h"
#include "ui/base/pointer/touch_editing_controller.h"

namespace ui {

namespace {

TouchSelectionMenuAction MapCommandIdToMenuAction(int command_id) {
switch (command_id) {
case ui::TouchEditable::kCut:
return TouchSelectionMenuAction::kCut;
case ui::TouchEditable::kCopy:
return TouchSelectionMenuAction::kCopy;
case ui::TouchEditable::kPaste:
return TouchSelectionMenuAction::kPaste;
case ui::TouchEditable::kSelectAll:
return TouchSelectionMenuAction::kSelectAll;
case ui::TouchEditable::kSelectWord:
return TouchSelectionMenuAction::kSelectWord;
default:
NOTREACHED_NORETURN() << "Invalid command id: " << command_id;
}
}

} // namespace

void RecordTouchSelectionDrag(TouchSelectionDragType drag_type) {
base::UmaHistogramEnumeration(kTouchSelectionDragTypeHistogramName,
drag_type);
}

void RecordTouchSelectionMenuCommandAction(int command_id) {
base::UmaHistogramEnumeration(kTouchSelectionMenuActionHistogramName,
MapCommandIdToMenuAction(command_id));
}

void RecordTouchSelectionMenuEllipsisAction() {
base::UmaHistogramEnumeration(kTouchSelectionMenuActionHistogramName,
TouchSelectionMenuAction::kEllipsis);
}

void RecordTouchSelectionMenuSmartAction() {
base::UmaHistogramEnumeration(kTouchSelectionMenuActionHistogramName,
TouchSelectionMenuAction::kSmartAction);
}

} // namespace ui
52 changes: 52 additions & 0 deletions ui/touch_selection/touch_selection_metrics.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_TOUCH_SELECTION_TOUCH_SELECTION_METRICS_H_
#define UI_TOUCH_SELECTION_TOUCH_SELECTION_METRICS_H_

#include "ui/touch_selection/ui_touch_selection_export.h"

namespace ui {

inline constexpr char kTouchSelectionDragTypeHistogramName[] =
"InputMethod.TouchSelection.DragType";

inline constexpr char kTouchSelectionMenuActionHistogramName[] =
"InputMethod.TouchSelection.MenuAction";

// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class TouchSelectionDragType {
kCursorHandleDrag = 0,
kSelectionHandleDrag = 1,
kCursorDrag = 2,
kLongPressDrag = 3,
kDoublePressDrag = 4,
kMaxValue = kDoublePressDrag
};

// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class TouchSelectionMenuAction {
kCut = 0,
kCopy = 1,
kPaste = 2,
kSelectAll = 3,
kSelectWord = 4,
kEllipsis = 5,
kSmartAction = 6,
kMaxValue = kSmartAction
};

UI_TOUCH_SELECTION_EXPORT void RecordTouchSelectionDrag(
TouchSelectionDragType drag_type);

UI_TOUCH_SELECTION_EXPORT void RecordTouchSelectionMenuCommandAction(
int command_id);
UI_TOUCH_SELECTION_EXPORT void RecordTouchSelectionMenuEllipsisAction();
UI_TOUCH_SELECTION_EXPORT void RecordTouchSelectionMenuSmartAction();

} // namespace ui

#endif // UI_TOUCH_SELECTION_TOUCH_SELECTION_METRICS_H_

0 comments on commit 58ac847

Please sign in to comment.