Handle transfer state received from Browser and process input events.
In this change we are introducing logic to handle input events received on Viz. - Input events received on Viz before state transfer are queued. - Upon receiving state transfer input events in queue for the given sequence are flushed and forwarded to "correct" RenderInputRouterSupportAndroid. - Any out of order state transfer received are being ignored. This can happen since the states can come over different pipes from different web contents. Bug: 370506271 Change-Id: I4c7aa7da0ccc17c4a9c52882e54686d491a743ed Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6073287 Reviewed-by: Peter Kasting <pkasting@chromium.org> Reviewed-by: Aman Verma <amanvr@google.com> Reviewed-by: Jinsuk Kim <jinsukkim@chromium.org> Reviewed-by: Stephen Nusko <nuskos@chromium.org> Reviewed-by: Jonathan Ross <jonross@chromium.org> Commit-Queue: Kartar Singh <kartarsingh@google.com> Cr-Commit-Position: refs/heads/main@{#1402336}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
bc3b061b6b
commit
a4f9be41fd
base/time
components/viz/service
BUILD.gn
input
content/browser/renderer_host/input
tools/metrics/histograms/metadata/android
@ -414,6 +414,8 @@ class TimeBase {
|
||||
kMicrosecondsPerHour * kHoursPerDay;
|
||||
static constexpr int64_t kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
|
||||
static constexpr int64_t kNanosecondsPerMicrosecond = 1000;
|
||||
static constexpr int64_t kNanosecondsPerMillisecond =
|
||||
kNanosecondsPerMicrosecond * kMicrosecondsPerMillisecond;
|
||||
static constexpr int64_t kNanosecondsPerSecond =
|
||||
kNanosecondsPerMicrosecond * kMicrosecondsPerSecond;
|
||||
|
||||
|
@ -421,6 +421,8 @@ viz_component("service") {
|
||||
"frame_sinks/external_begin_frame_source_android.h",
|
||||
"gl/throw_uncaught_exception.cc",
|
||||
"gl/throw_uncaught_exception.h",
|
||||
"input/android_state_transfer_handler.cc",
|
||||
"input/android_state_transfer_handler.h",
|
||||
"input/fling_scheduler_android.cc",
|
||||
"input/fling_scheduler_android.h",
|
||||
"input/render_input_router_support_android.cc",
|
||||
@ -689,7 +691,9 @@ viz_source_set("unit_tests") {
|
||||
"display/overlay_unittest.cc",
|
||||
"frame_sinks/external_begin_frame_source_android_unittest.cc",
|
||||
"frame_sinks/fling_scheduler_android_unittest.cc",
|
||||
"input/android_state_transfer_handler_unittest.cc",
|
||||
]
|
||||
deps += [ "//ui/events:motionevent_jni_headers" ]
|
||||
}
|
||||
|
||||
if (enable_vulkan) {
|
||||
|
233
components/viz/service/input/android_state_transfer_handler.cc
Normal file
233
components/viz/service/input/android_state_transfer_handler.cc
Normal file
@ -0,0 +1,233 @@
|
||||
// Copyright 2025 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/viz/service/input/android_state_transfer_handler.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/check_deref.h"
|
||||
#include "base/notreached.h"
|
||||
#include "ui/events/android/motion_event_android_native.h"
|
||||
|
||||
namespace viz {
|
||||
|
||||
namespace {
|
||||
|
||||
base::TimeTicks GetEventDowntime(const base::android::ScopedInputEvent& event) {
|
||||
return base::TimeTicks::FromUptimeMillis(
|
||||
AMotionEvent_getDownTime(event.a_input_event()) /
|
||||
base::Time::kNanosecondsPerMillisecond);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AndroidStateTransferHandler::TransferState::TransferState(
|
||||
base::WeakPtr<RenderInputRouterSupportAndroidInterface> support,
|
||||
input::mojom::TouchTransferStatePtr state)
|
||||
: rir_support(support), transfer_state(std::move(state)) {
|
||||
CHECK(transfer_state);
|
||||
}
|
||||
|
||||
AndroidStateTransferHandler::TransferState::~TransferState() = default;
|
||||
|
||||
AndroidStateTransferHandler::TransferState::TransferState(
|
||||
TransferState&& other) {
|
||||
rir_support = other.rir_support;
|
||||
other.rir_support = nullptr;
|
||||
transfer_state = std::move(other.transfer_state);
|
||||
}
|
||||
|
||||
AndroidStateTransferHandler::AndroidStateTransferHandler() = default;
|
||||
|
||||
AndroidStateTransferHandler::~AndroidStateTransferHandler() = default;
|
||||
|
||||
void AndroidStateTransferHandler::StateOnTouchTransfer(
|
||||
input::mojom::TouchTransferStatePtr state,
|
||||
base::WeakPtr<RenderInputRouterSupportAndroidInterface> rir_support) {
|
||||
TRACE_EVENT("viz", "AndroidStateTransferHandler::StateOnTouchTransfer");
|
||||
|
||||
EmitPendingTransfersHistogram();
|
||||
|
||||
// TODO(crbug.com/383323530): Convert it to CHECK once we are using
|
||||
// AssociatedRemotes for passing state from Browser to Viz.
|
||||
const bool state_received_out_of_order =
|
||||
(!pending_transferred_states_.empty() &&
|
||||
(state->down_time_ms <
|
||||
pending_transferred_states_.back().transfer_state->down_time_ms));
|
||||
if (state_received_out_of_order) {
|
||||
TRACE_EVENT_INSTANT("viz", "OutOfOrderTransferStateDropped");
|
||||
// Drop out of order state received.
|
||||
// It is possible since the state transfers coming from different web
|
||||
// contents come over different mojo pipes.
|
||||
return;
|
||||
}
|
||||
|
||||
MaybeDropEventsFromEarlierSequences(state);
|
||||
|
||||
pending_transferred_states_.emplace(rir_support, std::move(state));
|
||||
if (pending_transferred_states_.size() > kMaxPendingTransferredStates) {
|
||||
pending_transferred_states_.pop();
|
||||
}
|
||||
|
||||
if (events_buffer_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (CanStartProcessingVizEvents(events_buffer_.front())) {
|
||||
while (!events_buffer_.empty()) {
|
||||
if (!state_for_curr_sequence_.has_value()) {
|
||||
// This can happen if the whole sequence was received on Viz before the
|
||||
// state could be transferred from Browser. Early out since we wouldn't
|
||||
// want to process the events from next sequence if they made it to
|
||||
// queue as well. `state_for_curr_sequence_` is reset at the end of
|
||||
// touch sequence when touch up or cancel is seen in `HandleTouchEvent`
|
||||
// method.
|
||||
return;
|
||||
}
|
||||
HandleTouchEvent(std::move(events_buffer_.front()));
|
||||
events_buffer_.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AndroidStateTransferHandler::OnMotionEvent(
|
||||
base::android::ScopedInputEvent input_event,
|
||||
const FrameSinkId& root_frame_sink_id) {
|
||||
TRACE_EVENT("input", "AndroidStateTransferHandler::OnMotionEvent");
|
||||
|
||||
const int action = AMotionEvent_getAction(input_event.a_input_event()) &
|
||||
AMOTION_EVENT_ACTION_MASK;
|
||||
if (ignore_remaining_touch_sequence_) {
|
||||
if (action == AMOTION_EVENT_ACTION_CANCEL ||
|
||||
action == AMOTION_EVENT_ACTION_UP) {
|
||||
ignore_remaining_touch_sequence_ = false;
|
||||
state_for_curr_sequence_.reset();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ValidateRootFrameSinkId(root_frame_sink_id);
|
||||
|
||||
if (state_for_curr_sequence_.has_value() ||
|
||||
CanStartProcessingVizEvents(input_event)) {
|
||||
HandleTouchEvent(std::move(input_event));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool events_from_dropped_sequence =
|
||||
!pending_transferred_states_.empty() &&
|
||||
(GetEventDowntime(input_event) <
|
||||
pending_transferred_states_.front().transfer_state->down_time_ms);
|
||||
if (events_from_dropped_sequence) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Queue events until we can start processing events received directly on
|
||||
// Viz.
|
||||
// TODO(crbug.com/384424270): Coalesce touch moves instead of pushing
|
||||
// individual events to queue.
|
||||
events_buffer_.push(std::move(input_event));
|
||||
|
||||
// Always return true since we are receiving input on Viz after hit testing on
|
||||
// Browser already determined that web contents are being hit.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AndroidStateTransferHandler::CanStartProcessingVizEvents(
|
||||
const base::android::ScopedInputEvent& event) {
|
||||
CHECK(!state_for_curr_sequence_.has_value());
|
||||
|
||||
if (pending_transferred_states_.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const jlong j_event_down_time =
|
||||
base::TimeTicks::FromJavaNanoTime(
|
||||
AMotionEvent_getDownTime(event.a_input_event()))
|
||||
.ToUptimeMillis();
|
||||
base::TimeTicks event_down_time =
|
||||
base::TimeTicks::FromUptimeMillis(j_event_down_time);
|
||||
|
||||
auto& state = pending_transferred_states_.front();
|
||||
// Touch event corresponding to previous state transfer should be
|
||||
// processed before next sequence starts.
|
||||
if (event_down_time == state.transfer_state->down_time_ms) {
|
||||
state_for_curr_sequence_.emplace(std::move(state));
|
||||
pending_transferred_states_.pop();
|
||||
return true;
|
||||
}
|
||||
CHECK_LT(event_down_time, state.transfer_state->down_time_ms);
|
||||
return false;
|
||||
}
|
||||
|
||||
void AndroidStateTransferHandler::MaybeDropEventsFromEarlierSequences(
|
||||
const input::mojom::TouchTransferStatePtr& state) {
|
||||
if (events_buffer_.empty()) {
|
||||
return;
|
||||
}
|
||||
while (!events_buffer_.empty() &&
|
||||
GetEventDowntime(events_buffer_.front()) < state->down_time_ms) {
|
||||
events_buffer_.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidStateTransferHandler::EmitPendingTransfersHistogram() {
|
||||
const char* histogram_name;
|
||||
if (state_for_curr_sequence_.has_value()) {
|
||||
histogram_name = kPendingTransfersHistogramNonNull;
|
||||
} else {
|
||||
histogram_name = kPendingTransfersHistogramNull;
|
||||
}
|
||||
// We don't expect histogram value i.e. `pending_transferred_states_.size()`
|
||||
// to be more than 3(`kMaxPendingTransferredStates`, but leaving histogram max
|
||||
// to 10 to have some space to increase `kMaxPendingTransferredStates`.
|
||||
base::UmaHistogramCustomCounts(histogram_name,
|
||||
pending_transferred_states_.size(), /*min=*/1,
|
||||
/*exclusive_max=*/10, /*buckets=*/10u);
|
||||
}
|
||||
|
||||
void AndroidStateTransferHandler::HandleTouchEvent(
|
||||
base::android::ScopedInputEvent input_event) {
|
||||
CHECK(state_for_curr_sequence_.has_value() &&
|
||||
GetEventDowntime(input_event) ==
|
||||
state_for_curr_sequence_->transfer_state->down_time_ms);
|
||||
|
||||
if (!state_for_curr_sequence_->rir_support) {
|
||||
const int action = AMotionEvent_getAction(input_event.a_input_event()) &
|
||||
AMOTION_EVENT_ACTION_MASK;
|
||||
if (action == AMOTION_EVENT_ACTION_CANCEL ||
|
||||
action == AMOTION_EVENT_ACTION_UP) {
|
||||
state_for_curr_sequence_.reset();
|
||||
ignore_remaining_touch_sequence_ = false;
|
||||
} else {
|
||||
ignore_remaining_touch_sequence_ = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// TOOD(crbug.com/370506271): Use correct pix_to_dip for creating events.
|
||||
auto event = ui::MotionEventAndroidNative::Create(
|
||||
std::move(input_event),
|
||||
/* pix_to_dip= */ 1,
|
||||
state_for_curr_sequence_->transfer_state->raw_y_offset);
|
||||
|
||||
state_for_curr_sequence_->rir_support->OnTouchEvent(
|
||||
*event.get(), /* emit_histograms= */ true);
|
||||
|
||||
if (event->GetAction() == ui::MotionEvent::Action::UP ||
|
||||
event->GetAction() == ui::MotionEvent::Action::CANCEL) {
|
||||
state_for_curr_sequence_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidStateTransferHandler::ValidateRootFrameSinkId(
|
||||
const FrameSinkId& root_frame_sink_id) {
|
||||
CHECK(root_frame_sink_id.is_valid());
|
||||
if (active_root_frame_sink_id_ != root_frame_sink_id) {
|
||||
CHECK(!active_root_frame_sink_id_.is_valid());
|
||||
active_root_frame_sink_id_ = root_frame_sink_id;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace viz
|
@ -0,0 +1,91 @@
|
||||
// Copyright 2025 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef COMPONENTS_VIZ_SERVICE_INPUT_ANDROID_STATE_TRANSFER_HANDLER_H_
|
||||
#define COMPONENTS_VIZ_SERVICE_INPUT_ANDROID_STATE_TRANSFER_HANDLER_H_
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "base/containers/queue.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/metrics/histogram_functions.h"
|
||||
#include "components/input/android/android_input_callback.h"
|
||||
#include "components/input/render_input_router.mojom.h"
|
||||
#include "components/viz/common/surfaces/frame_sink_id.h"
|
||||
#include "components/viz/service/input/render_input_router_support_android.h"
|
||||
#include "components/viz/service/viz_service_export.h"
|
||||
|
||||
namespace viz {
|
||||
|
||||
// AndroidStateTransferHandler listens to input events coming from Android
|
||||
// platform and receives |TouchTransferState| coming from Browser. Input events
|
||||
// are queued until state for corresponding touch sequence is received from
|
||||
// Browser, similarly state is queued until we started receiving input events
|
||||
// from Android platform.
|
||||
class VIZ_SERVICE_EXPORT AndroidStateTransferHandler
|
||||
: public input::AndroidInputCallbackClient {
|
||||
public:
|
||||
AndroidStateTransferHandler();
|
||||
~AndroidStateTransferHandler();
|
||||
|
||||
// AndroidInputCallbackClient implementation.
|
||||
bool OnMotionEvent(base::android::ScopedInputEvent input_event,
|
||||
const FrameSinkId& root_frame_sink_id) override;
|
||||
|
||||
// `rir_support`: RenderInputRouterSupport corresponding to root widget's
|
||||
// FrameSinkId in TouchTransferState. `rir_support` can be null at the start
|
||||
// or in the middle of sequence in case CompositorFrameSink got destroyed.
|
||||
void StateOnTouchTransfer(
|
||||
input::mojom::TouchTransferStatePtr state,
|
||||
base::WeakPtr<RenderInputRouterSupportAndroidInterface> rir_support);
|
||||
|
||||
size_t GetEventsBufferSizeForTesting() const { return events_buffer_.size(); }
|
||||
|
||||
static constexpr const char* kPendingTransfersHistogramNonNull =
|
||||
"Android.InputOnViz.Viz.PendingStateTransfers.NonNullCurrentState";
|
||||
static constexpr const char* kPendingTransfersHistogramNull =
|
||||
"Android.InputOnViz.Viz.PendingStateTransfers.NullCurrentState";
|
||||
|
||||
private:
|
||||
bool CanStartProcessingVizEvents(
|
||||
const base::android::ScopedInputEvent& event);
|
||||
|
||||
void HandleTouchEvent(base::android::ScopedInputEvent input_event);
|
||||
void MaybeDropEventsFromEarlierSequences(
|
||||
const input::mojom::TouchTransferStatePtr& state);
|
||||
void EmitPendingTransfersHistogram();
|
||||
void ValidateRootFrameSinkId(const FrameSinkId& root_frame_sink_id);
|
||||
|
||||
// We currently only support a single active root frame sink.
|
||||
FrameSinkId active_root_frame_sink_id_;
|
||||
|
||||
bool ignore_remaining_touch_sequence_ = false;
|
||||
|
||||
struct TransferState {
|
||||
TransferState(
|
||||
base::WeakPtr<RenderInputRouterSupportAndroidInterface> support,
|
||||
input::mojom::TouchTransferStatePtr transfer_state);
|
||||
TransferState(TransferState&& other);
|
||||
~TransferState();
|
||||
|
||||
base::WeakPtr<RenderInputRouterSupportAndroidInterface> rir_support;
|
||||
input::mojom::TouchTransferStatePtr transfer_state;
|
||||
};
|
||||
|
||||
// State corresponding to active touch sequence.
|
||||
std::optional<TransferState> state_for_curr_sequence_ = std::nullopt;
|
||||
|
||||
// The list maintains sorted order by key `TouchTransferState.down_time_ms`.
|
||||
// Any state transfer received out of order is dropped.
|
||||
base::queue<TransferState> pending_transferred_states_;
|
||||
static constexpr int kMaxPendingTransferredStates = 3;
|
||||
|
||||
// Stores input events until we have received state from Browser for the
|
||||
// currently transferred touch sequence.
|
||||
base::queue<base::android::ScopedInputEvent> events_buffer_;
|
||||
};
|
||||
|
||||
} // namespace viz
|
||||
|
||||
#endif // COMPONENTS_VIZ_SERVICE_INPUT_ANDROID_STATE_TRANSFER_HANDLER_H_
|
@ -0,0 +1,421 @@
|
||||
// Copyright 2025 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/viz/service/input/android_state_transfer_handler.h"
|
||||
|
||||
#include <android/input.h>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/android/build_info.h"
|
||||
#include "base/android/jni_android.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
// Must come after all headers that specialize FromJniType() / ToJniType().
|
||||
#include "ui/events/motionevent_jni_headers/MotionEvent_jni.h"
|
||||
|
||||
namespace viz {
|
||||
|
||||
using ::testing::_;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kAndroidActionDown = AMOTION_EVENT_ACTION_DOWN;
|
||||
constexpr int kAndroidActionMove = AMOTION_EVENT_ACTION_MOVE;
|
||||
constexpr int kAndroidActionUp = AMOTION_EVENT_ACTION_UP;
|
||||
constexpr FrameSinkId kRootCompositorFrameSinkId = FrameSinkId(1, 1);
|
||||
constexpr FrameSinkId kRootWidgetFrameSinkId = FrameSinkId(2, 3);
|
||||
|
||||
base::android::ScopedInputEvent GetInputEvent(jlong down_time_ms,
|
||||
jlong event_time_ms,
|
||||
int action,
|
||||
float x,
|
||||
float y) {
|
||||
// Java_MotionEvent_obtain expects timestamps(down time, event time) obtained
|
||||
// from |SystemClock#uptimeMillis()|.
|
||||
JNIEnv* env = base::android::AttachCurrentThread();
|
||||
base::android::ScopedJavaLocalRef<jobject> java_motion_event =
|
||||
JNI_MotionEvent::Java_MotionEvent_obtain(env, down_time_ms, event_time_ms,
|
||||
action, x, y,
|
||||
/*metaState=*/0);
|
||||
const AInputEvent* native_event = nullptr;
|
||||
if (__builtin_available(android 31, *)) {
|
||||
native_event = AMotionEvent_fromJava(env, java_motion_event.obj());
|
||||
}
|
||||
CHECK(native_event);
|
||||
|
||||
return base::android::ScopedInputEvent(native_event);
|
||||
}
|
||||
|
||||
struct TestInputStream {
|
||||
base::TimeTicks down_time_ms;
|
||||
std::vector<base::android::ScopedInputEvent> events;
|
||||
};
|
||||
|
||||
TestInputStream GenerateEventsForSequence(int num_moves,
|
||||
bool include_touch_up) {
|
||||
static base::TimeTicks event_time =
|
||||
base::TimeTicks::Now() - base::Milliseconds(100);
|
||||
static float x = 100;
|
||||
static float y = 200;
|
||||
|
||||
TestInputStream event_stream;
|
||||
|
||||
event_time += base::Milliseconds(8);
|
||||
x += 5;
|
||||
y += 5;
|
||||
|
||||
jlong down_time = event_time.ToUptimeMillis();
|
||||
event_stream.down_time_ms = base::TimeTicks::FromUptimeMillis(down_time);
|
||||
event_stream.events.push_back(GetInputEvent(
|
||||
down_time, event_time.ToUptimeMillis(), kAndroidActionDown, x, y));
|
||||
|
||||
for (int i = 1; i <= num_moves; i++) {
|
||||
event_time += base::Milliseconds(8);
|
||||
x += 5;
|
||||
y += 5;
|
||||
event_stream.events.push_back(GetInputEvent(
|
||||
down_time, event_time.ToUptimeMillis(), kAndroidActionMove, x, y));
|
||||
}
|
||||
if (include_touch_up) {
|
||||
event_time += base::Milliseconds(8);
|
||||
event_stream.events.push_back(GetInputEvent(
|
||||
down_time, event_time.ToUptimeMillis(), kAndroidActionUp, x, y));
|
||||
}
|
||||
return event_stream;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class MockRenderInputRouterSupportAndroid
|
||||
: public RenderInputRouterSupportAndroidInterface {
|
||||
public:
|
||||
virtual ~MockRenderInputRouterSupportAndroid() = default;
|
||||
|
||||
MOCK_METHOD((bool),
|
||||
OnTouchEvent,
|
||||
(const ui::MotionEventAndroid&, bool),
|
||||
(override));
|
||||
|
||||
base::WeakPtr<RenderInputRouterSupportAndroidInterface> GetWeakPtr() {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
void Destroy() { weak_factory_.InvalidateWeakPtrs(); }
|
||||
|
||||
private:
|
||||
base::WeakPtrFactory<RenderInputRouterSupportAndroidInterface> weak_factory_{
|
||||
this};
|
||||
};
|
||||
|
||||
class AndroidStateTransferHandlerTest : public testing::Test {
|
||||
public:
|
||||
void SetUp() override {
|
||||
if (base::android::BuildInfo::GetInstance()->sdk_int() <
|
||||
base::android::SDK_VERSION_V) {
|
||||
GTEST_SKIP()
|
||||
<< "AndroidStateTransferHandlerTest is used only when InputOnViz "
|
||||
"is enabled i.e. on Android V+";
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
MockRenderInputRouterSupportAndroid mock_rir_support_;
|
||||
AndroidStateTransferHandler handler_;
|
||||
};
|
||||
|
||||
// The order of events received:
|
||||
// Down1 -> Move1 -> StateTransfer(for Down1)
|
||||
TEST_F(AndroidStateTransferHandlerTest, EventsProcessedOnStateTransfer) {
|
||||
TestInputStream event_stream = GenerateEventsForSequence(
|
||||
/*num_moves*/ 1,
|
||||
/*include_touch_up*/ false);
|
||||
|
||||
for (auto& event : event_stream.events) {
|
||||
handler_.OnMotionEvent(std::move(event), kRootCompositorFrameSinkId);
|
||||
}
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 2u);
|
||||
|
||||
auto state = input::mojom::TouchTransferState::New();
|
||||
state->down_time_ms = event_stream.down_time_ms;
|
||||
state->root_widget_frame_sink_id = kRootWidgetFrameSinkId;
|
||||
|
||||
// Both the events should be dequeued and processed.
|
||||
EXPECT_CALL(mock_rir_support_, OnTouchEvent(_, _)).Times(2);
|
||||
handler_.StateOnTouchTransfer(std::move(state),
|
||||
mock_rir_support_.GetWeakPtr());
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 0u);
|
||||
}
|
||||
|
||||
// The order of events received:
|
||||
// Down1 -> Move1 -> StateTransfer(for Down1)
|
||||
// The rir_support for widget referred in state is already destroyed.
|
||||
TEST_F(AndroidStateTransferHandlerTest, RIRSupportNullOnStateTransfer) {
|
||||
TestInputStream event_stream = GenerateEventsForSequence(
|
||||
/*num_moves*/ 1,
|
||||
/*include_touch_up*/ false);
|
||||
|
||||
for (auto& event : event_stream.events) {
|
||||
handler_.OnMotionEvent(std::move(event), kRootCompositorFrameSinkId);
|
||||
}
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 2u);
|
||||
|
||||
auto state = input::mojom::TouchTransferState::New();
|
||||
state->down_time_ms = event_stream.down_time_ms;
|
||||
state->root_widget_frame_sink_id = kRootWidgetFrameSinkId;
|
||||
|
||||
EXPECT_CALL(mock_rir_support_, OnTouchEvent(_, _)).Times(0);
|
||||
handler_.StateOnTouchTransfer(std::move(state),
|
||||
/* rir_support= */ nullptr);
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 0u);
|
||||
}
|
||||
|
||||
// The order of events received:
|
||||
// StateTransfer(for Down1) -> Down1 -> Move1 -> OnDestroyedCompositorFrameSink
|
||||
// -> Move3.
|
||||
// Move3 ends up getting dropped.
|
||||
TEST_F(AndroidStateTransferHandlerTest,
|
||||
InputReceivingCompositorFrameSinkDestroyedMidSequence) {
|
||||
TestInputStream event_stream = GenerateEventsForSequence(
|
||||
/*num_moves*/ 2,
|
||||
/*include_touch_up*/ false);
|
||||
|
||||
auto state = input::mojom::TouchTransferState::New();
|
||||
state->down_time_ms = event_stream.down_time_ms;
|
||||
state->root_widget_frame_sink_id = kRootWidgetFrameSinkId;
|
||||
|
||||
handler_.StateOnTouchTransfer(std::move(state),
|
||||
mock_rir_support_.GetWeakPtr());
|
||||
handler_.OnMotionEvent(std::move(event_stream.events[0]),
|
||||
kRootCompositorFrameSinkId);
|
||||
handler_.OnMotionEvent(std::move(event_stream.events[1]),
|
||||
kRootCompositorFrameSinkId);
|
||||
|
||||
EXPECT_CALL(mock_rir_support_, OnTouchEvent(_, _)).Times(0);
|
||||
mock_rir_support_.Destroy();
|
||||
|
||||
// The events are dropped after the render input router support is
|
||||
// destroyed.
|
||||
handler_.OnMotionEvent(std::move(event_stream.events[2]),
|
||||
kRootCompositorFrameSinkId);
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 0u);
|
||||
}
|
||||
|
||||
// The order of events received:
|
||||
// StateTransfer(for Down1) -> Down1 -> Move1
|
||||
// Down1 and Move1 can be immediately processed.
|
||||
TEST_F(AndroidStateTransferHandlerTest, StateReceivedBeforeTouchDownOnViz) {
|
||||
TestInputStream event_stream = GenerateEventsForSequence(
|
||||
/*num_moves*/ 2,
|
||||
/*include_touch_up*/ false);
|
||||
|
||||
auto state = input::mojom::TouchTransferState::New();
|
||||
state->down_time_ms = event_stream.down_time_ms;
|
||||
state->root_widget_frame_sink_id = kRootWidgetFrameSinkId;
|
||||
handler_.StateOnTouchTransfer(std::move(state),
|
||||
mock_rir_support_.GetWeakPtr());
|
||||
|
||||
EXPECT_CALL(mock_rir_support_, OnTouchEvent(_, _)).Times(1);
|
||||
handler_.OnMotionEvent(std::move(event_stream.events[0]),
|
||||
kRootCompositorFrameSinkId);
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 0u);
|
||||
|
||||
EXPECT_CALL(mock_rir_support_, OnTouchEvent(_, _)).Times(1);
|
||||
handler_.OnMotionEvent(std::move(event_stream.events[1]),
|
||||
kRootCompositorFrameSinkId);
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 0u);
|
||||
}
|
||||
|
||||
// The order of events received:
|
||||
// StateTransfer(for Down1) -> Down1 -> Move1 -> StateTransfer(for Down2) -> Up1
|
||||
// -> Down2 Down1 and move1 can be immediately processed.
|
||||
TEST_F(AndroidStateTransferHandlerTest, NewStateReceivedMidSequence) {
|
||||
TestInputStream event_stream_1 =
|
||||
GenerateEventsForSequence(/*num_moves*/ 1,
|
||||
/*include_touch_up*/ true);
|
||||
|
||||
TestInputStream event_stream_2 =
|
||||
GenerateEventsForSequence(/*num_moves*/ 0,
|
||||
/*include_touch_up*/ false);
|
||||
|
||||
// State is received before receiving any touch events directly on Viz
|
||||
auto state1 = input::mojom::TouchTransferState::New();
|
||||
state1->down_time_ms = event_stream_1.down_time_ms;
|
||||
|
||||
handler_.StateOnTouchTransfer(std::move(state1),
|
||||
mock_rir_support_.GetWeakPtr());
|
||||
|
||||
EXPECT_CALL(mock_rir_support_, OnTouchEvent(_, _)).Times(3);
|
||||
// Down1 is received.
|
||||
handler_.OnMotionEvent(std::move(event_stream_1.events[0]),
|
||||
kRootCompositorFrameSinkId);
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 0u);
|
||||
|
||||
// Move1 is received.
|
||||
handler_.OnMotionEvent(std::move(event_stream_1.events[1]),
|
||||
kRootCompositorFrameSinkId);
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 0u);
|
||||
|
||||
// State for second sequence is received.
|
||||
MockRenderInputRouterSupportAndroid mock_rir_support2;
|
||||
auto state2 = input::mojom::TouchTransferState::New();
|
||||
state2->down_time_ms = event_stream_2.down_time_ms;
|
||||
handler_.StateOnTouchTransfer(std::move(state2),
|
||||
mock_rir_support2.GetWeakPtr());
|
||||
|
||||
// Up1 is received.
|
||||
handler_.OnMotionEvent(std::move(event_stream_1.events[2]),
|
||||
kRootCompositorFrameSinkId);
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 0u);
|
||||
|
||||
// Down1 is received from second sequence, on different
|
||||
// RenderInputRouterSupport.
|
||||
EXPECT_CALL(mock_rir_support2, OnTouchEvent(_, _)).Times(1);
|
||||
handler_.OnMotionEvent(std::move(event_stream_2.events[0]),
|
||||
kRootCompositorFrameSinkId);
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 0u);
|
||||
}
|
||||
|
||||
// The order of events received:
|
||||
// Down1 -> Move1 -> Up1 -> Down2 -> StateTransfer(for Down1)
|
||||
// Down1 and move1 can be immediately processed.
|
||||
TEST_F(AndroidStateTransferHandlerTest,
|
||||
FullSequenceReceivedBeforeStateTransfer) {
|
||||
TestInputStream event_stream_1 =
|
||||
GenerateEventsForSequence(/*num_moves*/ 1,
|
||||
/*include_touch_up*/ true);
|
||||
|
||||
TestInputStream event_stream_2 =
|
||||
GenerateEventsForSequence(/*num_moves*/ 0,
|
||||
/*include_touch_up*/ false);
|
||||
|
||||
for (auto& event : event_stream_1.events) {
|
||||
handler_.OnMotionEvent(std::move(event), kRootCompositorFrameSinkId);
|
||||
}
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 3u);
|
||||
|
||||
for (auto& event : event_stream_2.events) {
|
||||
handler_.OnMotionEvent(std::move(event), kRootCompositorFrameSinkId);
|
||||
}
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 4u);
|
||||
|
||||
// State is received before receiving any touch events directly on Viz
|
||||
EXPECT_CALL(mock_rir_support_, OnTouchEvent(_, _)).Times(3);
|
||||
auto state1 = input::mojom::TouchTransferState::New();
|
||||
state1->down_time_ms = event_stream_1.down_time_ms;
|
||||
handler_.StateOnTouchTransfer(std::move(state1),
|
||||
mock_rir_support_.GetWeakPtr());
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 1u);
|
||||
}
|
||||
|
||||
// The order of events received:
|
||||
// StateTransfer(Down2) -> Down1 -> Up1 -> Down2
|
||||
TEST_F(AndroidStateTransferHandlerTest,
|
||||
InputEventsAreNotQueuedForDroppedStateTransfer) {
|
||||
TestInputStream event_stream_1 =
|
||||
GenerateEventsForSequence(/*num_moves*/ 0,
|
||||
/*include_touch_up*/ true);
|
||||
|
||||
TestInputStream event_stream_2 =
|
||||
GenerateEventsForSequence(/*num_moves*/ 0,
|
||||
/*include_touch_up*/ false);
|
||||
|
||||
auto state2 = input::mojom::TouchTransferState::New();
|
||||
state2->down_time_ms = event_stream_2.down_time_ms;
|
||||
handler_.StateOnTouchTransfer(std::move(state2),
|
||||
mock_rir_support_.GetWeakPtr());
|
||||
|
||||
for (auto& event : event_stream_1.events) {
|
||||
handler_.OnMotionEvent(std::move(event), kRootCompositorFrameSinkId);
|
||||
}
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 0u);
|
||||
|
||||
EXPECT_CALL(mock_rir_support_, OnTouchEvent(_, _)).Times(1);
|
||||
for (auto& event : event_stream_2.events) {
|
||||
handler_.OnMotionEvent(std::move(event), kRootCompositorFrameSinkId);
|
||||
}
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 0u);
|
||||
}
|
||||
|
||||
// The order of events received:
|
||||
// Down1 -> Up1 -> Down2 -> Up2 -> Down3 -> StateTransfer(Down3)
|
||||
TEST_F(AndroidStateTransferHandlerTest,
|
||||
QueuedInputEventsDroppedUponLaterStateTransfer) {
|
||||
TestInputStream event_stream_1 =
|
||||
GenerateEventsForSequence(/*num_moves*/ 0,
|
||||
/*include_touch_up*/ true);
|
||||
|
||||
TestInputStream event_stream_2 =
|
||||
GenerateEventsForSequence(/*num_moves*/ 0,
|
||||
/*include_touch_up*/ true);
|
||||
|
||||
TestInputStream event_stream_3 =
|
||||
GenerateEventsForSequence(/*num_moves*/ 0,
|
||||
/*include_touch_up*/ false);
|
||||
|
||||
for (auto& event : event_stream_1.events) {
|
||||
handler_.OnMotionEvent(std::move(event), kRootCompositorFrameSinkId);
|
||||
}
|
||||
for (auto& event : event_stream_2.events) {
|
||||
handler_.OnMotionEvent(std::move(event), kRootCompositorFrameSinkId);
|
||||
}
|
||||
for (auto& event : event_stream_3.events) {
|
||||
handler_.OnMotionEvent(std::move(event), kRootCompositorFrameSinkId);
|
||||
}
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(),
|
||||
event_stream_1.events.size() + event_stream_2.events.size() +
|
||||
event_stream_3.events.size());
|
||||
|
||||
EXPECT_CALL(mock_rir_support_, OnTouchEvent(_, _)).Times(1);
|
||||
auto state3 = input::mojom::TouchTransferState::New();
|
||||
state3->down_time_ms = event_stream_3.down_time_ms;
|
||||
handler_.StateOnTouchTransfer(std::move(state3),
|
||||
mock_rir_support_.GetWeakPtr());
|
||||
}
|
||||
|
||||
// The order of events received:
|
||||
// StateTransfer(Down1) -> Down1 -> Move1 -> OnDestroyedCompositorFrameSink ->
|
||||
// Up1 -> Down2 -> StateTransfer(Down2)
|
||||
TEST_F(AndroidStateTransferHandlerTest, RirNullOnLastInputInSequence) {
|
||||
TestInputStream event_stream_1 =
|
||||
GenerateEventsForSequence(/*num_moves*/ 1,
|
||||
/*include_touch_up*/ true);
|
||||
|
||||
TestInputStream event_stream_2 =
|
||||
GenerateEventsForSequence(/*num_moves*/ 0,
|
||||
/*include_touch_up*/ false);
|
||||
|
||||
auto state1 = input::mojom::TouchTransferState::New();
|
||||
state1->down_time_ms = event_stream_1.down_time_ms;
|
||||
handler_.StateOnTouchTransfer(std::move(state1),
|
||||
mock_rir_support_.GetWeakPtr());
|
||||
|
||||
EXPECT_CALL(mock_rir_support_, OnTouchEvent(_, _)).Times(2);
|
||||
handler_.OnMotionEvent(std::move(event_stream_1.events[0]),
|
||||
kRootCompositorFrameSinkId);
|
||||
handler_.OnMotionEvent(std::move(event_stream_1.events[1]),
|
||||
kRootCompositorFrameSinkId);
|
||||
|
||||
mock_rir_support_.Destroy();
|
||||
|
||||
EXPECT_CALL(mock_rir_support_, OnTouchEvent(_, _)).Times(0);
|
||||
handler_.OnMotionEvent(std::move(event_stream_1.events[2]),
|
||||
kRootCompositorFrameSinkId);
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 0u);
|
||||
|
||||
for (auto& event : event_stream_2.events) {
|
||||
handler_.OnMotionEvent(std::move(event), kRootCompositorFrameSinkId);
|
||||
}
|
||||
EXPECT_EQ(handler_.GetEventsBufferSizeForTesting(), 1u);
|
||||
|
||||
EXPECT_CALL(mock_rir_support_, OnTouchEvent(_, _)).Times(1);
|
||||
auto state2 = input::mojom::TouchTransferState::New();
|
||||
state2->down_time_ms = event_stream_2.down_time_ms;
|
||||
handler_.StateOnTouchTransfer(std::move(state2),
|
||||
mock_rir_support_.GetWeakPtr());
|
||||
}
|
||||
|
||||
} // namespace viz
|
@ -381,7 +381,18 @@ std::optional<bool> InputManager::IsDelegatedInkHovering(
|
||||
}
|
||||
void InputManager::StateOnTouchTransfer(
|
||||
input::mojom::TouchTransferStatePtr state) {
|
||||
// TODO(crbug.com/370506271): Handle state to start processing input events.
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
auto iter = frame_sink_metadata_map_.find(state->root_widget_frame_sink_id);
|
||||
base::WeakPtr<RenderInputRouterSupportAndroidInterface>
|
||||
support_android_interface = nullptr;
|
||||
if (iter != frame_sink_metadata_map_.end()) {
|
||||
auto* support_android = static_cast<RenderInputRouterSupportAndroid*>(
|
||||
iter->second.rir_support.get());
|
||||
support_android_interface = support_android->GetWeakPtr();
|
||||
}
|
||||
android_state_transfer_handler_.StateOnTouchTransfer(
|
||||
std::move(state), support_android_interface);
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputManager::NotifySiteIsMobileOptimized(
|
||||
@ -512,7 +523,8 @@ void InputManager::CreateOrReuseAndroidInputReceiver(
|
||||
}
|
||||
|
||||
std::unique_ptr<input::AndroidInputCallback> android_input_callback =
|
||||
std::make_unique<input::AndroidInputCallback>(frame_sink_id, this);
|
||||
std::make_unique<input::AndroidInputCallback>(
|
||||
frame_sink_id, &android_state_transfer_handler_);
|
||||
// Destructor of |ScopedInputReceiverCallbacks| will call
|
||||
// |AInputReceiverCallbacks_release|, so we don't have to explicitly unset the
|
||||
// motion event callback we set below using
|
||||
@ -560,16 +572,6 @@ void InputManager::CreateOrReuseAndroidInputReceiver(
|
||||
std::move(receiver), std::move(viz_input_token));
|
||||
}
|
||||
|
||||
bool InputManager::OnMotionEvent(base::android::ScopedInputEvent input_event,
|
||||
const FrameSinkId& root_frame_sink_id) {
|
||||
// TODO(370506271): Implement once we do the state transfer from Browser on
|
||||
// touch down.
|
||||
|
||||
// Always return true since we are receiving input on Viz after hit testing on
|
||||
// Browser already determined that web contents are being hit.
|
||||
return true;
|
||||
}
|
||||
|
||||
BeginFrameSource* InputManager::GetBeginFrameSourceForFrameSink(
|
||||
const FrameSinkId& id) {
|
||||
return frame_sink_manager_->GetFrameSinkForId(id)->begin_frame_source();
|
||||
|
@ -21,9 +21,10 @@
|
||||
#include "gpu/ipc/common/surface_handle.h"
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
#include "components/input/android/android_input_callback.h"
|
||||
#include "components/input/android/input_receiver_data.h"
|
||||
#include "components/viz/service/input/android_state_transfer_handler.h"
|
||||
#include "components/viz/service/input/fling_scheduler_android.h"
|
||||
#include "components/viz/service/input/render_input_router_support_android.h"
|
||||
#endif
|
||||
|
||||
namespace input {
|
||||
@ -55,7 +56,6 @@ class VIZ_SERVICE_EXPORT InputManager
|
||||
: public FrameSinkObserver,
|
||||
public input::RenderWidgetHostInputEventRouter::Delegate,
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
public input::AndroidInputCallbackClient,
|
||||
public FlingSchedulerAndroid::Delegate,
|
||||
#endif
|
||||
public RenderInputRouterSupportBase::Delegate,
|
||||
@ -98,10 +98,6 @@ class VIZ_SERVICE_EXPORT InputManager
|
||||
const FrameSinkId& frame_sink_id) override;
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
// AndroidInputCallbackClient implementation.
|
||||
bool OnMotionEvent(base::android::ScopedInputEvent input_event,
|
||||
const FrameSinkId& root_frame_sink_id) override;
|
||||
|
||||
// FlingSchedulerAndroid::Delegate implementation.
|
||||
BeginFrameSource* GetBeginFrameSourceForFrameSink(
|
||||
const FrameSinkId& id) override;
|
||||
@ -167,6 +163,8 @@ class VIZ_SERVICE_EXPORT InputManager
|
||||
const FrameSinkId& frame_sink_id,
|
||||
const gpu::SurfaceHandle& surface_handle);
|
||||
|
||||
AndroidStateTransferHandler android_state_transfer_handler_;
|
||||
|
||||
std::unique_ptr<input::InputReceiverData> receiver_data_;
|
||||
#endif // BUILDFLAG(IS_ANDROID)
|
||||
|
||||
|
@ -143,4 +143,9 @@ void RenderInputRouterSupportAndroid::GestureEventAck(
|
||||
StopFlingingIfNecessary(event, ack_result);
|
||||
}
|
||||
|
||||
base::WeakPtr<RenderInputRouterSupportAndroid>
|
||||
RenderInputRouterSupportAndroid::GetWeakPtr() {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
} // namespace viz
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "components/input/android_input_helper.h"
|
||||
#include "components/input/events_helper.h"
|
||||
#include "components/viz/service/input/render_input_router_support_base.h"
|
||||
@ -15,10 +16,19 @@
|
||||
|
||||
namespace viz {
|
||||
|
||||
// Allow easy testing of code calling into RenderInputRouterSupport's
|
||||
// OnTouchEvent.
|
||||
class RenderInputRouterSupportAndroidInterface {
|
||||
public:
|
||||
virtual bool OnTouchEvent(const ui::MotionEventAndroid& event,
|
||||
bool emit_histograms) = 0;
|
||||
};
|
||||
|
||||
class VIZ_SERVICE_EXPORT RenderInputRouterSupportAndroid
|
||||
: public RenderInputRouterSupportBase,
|
||||
public ui::GestureProviderClient,
|
||||
public input::AndroidInputHelper::Delegate {
|
||||
public input::AndroidInputHelper::Delegate,
|
||||
public RenderInputRouterSupportAndroidInterface {
|
||||
public:
|
||||
explicit RenderInputRouterSupportAndroid(
|
||||
input::RenderInputRouter* rir,
|
||||
@ -35,7 +45,8 @@ class VIZ_SERVICE_EXPORT RenderInputRouterSupportAndroid
|
||||
// |emit_histograms|: Whether to emit tool type and OS touch latency
|
||||
// histograms, for the events forwarded from Browser we wouldn't want to emit
|
||||
// histograms for them since Browser code would have already emitted them.
|
||||
bool OnTouchEvent(const ui::MotionEventAndroid& event, bool emit_histograms);
|
||||
bool OnTouchEvent(const ui::MotionEventAndroid& event,
|
||||
bool emit_histograms) override;
|
||||
bool ShouldRouteEvents() const;
|
||||
|
||||
// ui::GestureProviderClient implementation.
|
||||
@ -64,12 +75,16 @@ class VIZ_SERVICE_EXPORT RenderInputRouterSupportAndroid
|
||||
void SendGestureEvent(const blink::WebGestureEvent& event) override;
|
||||
ui::FilteredGestureProvider& GetGestureProvider() override;
|
||||
|
||||
base::WeakPtr<RenderInputRouterSupportAndroid> GetWeakPtr();
|
||||
|
||||
private:
|
||||
std::unique_ptr<input::AndroidInputHelper> input_helper_;
|
||||
|
||||
// Provides gesture synthesis given a stream of touch events (derived from
|
||||
// Android MotionEvent's) and touch event acks.
|
||||
ui::FilteredGestureProvider gesture_provider_;
|
||||
|
||||
base::WeakPtrFactory<RenderInputRouterSupportAndroid> weak_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace viz
|
||||
|
@ -44,6 +44,8 @@ InputTransferHandlerAndroid::InputTransferHandlerAndroid(
|
||||
InputTransferHandlerAndroid::~InputTransferHandlerAndroid() = default;
|
||||
|
||||
bool InputTransferHandlerAndroid::OnTouchEvent(const ui::MotionEvent& event) {
|
||||
// TODO(crbug.com/383307455): Forward events seen on Browser post transfer
|
||||
// over to Viz.
|
||||
if (touch_transferred_) {
|
||||
// TODO(crbug.com/370506271): Add support for getDownTime in MotionEvent and
|
||||
// check if this cancel has same downtime as the original down used for
|
||||
|
@ -2213,6 +2213,24 @@ chromium-metrics-reviews@google.com.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Android.InputOnViz.Viz.PendingStateTransfers.{CurrentState}"
|
||||
units="counts" expires_after="2025-06-30">
|
||||
<owner>kartarsingh@google.com</owner>
|
||||
<owner>woa-performance-team@google.com</owner>
|
||||
<summary>
|
||||
When `InputOnViz` is enabled Browser process sends state on TouchDown to Viz
|
||||
in case touch transfer was successful. In theory, due to hiccups in system
|
||||
we can have multiple pending states on Viz.
|
||||
|
||||
This metric records the number of pending states on Viz when {CurrentState}.
|
||||
This would help us verify if we have pending states in practice as well.
|
||||
</summary>
|
||||
<token key="CurrentState">
|
||||
<variant name="NonNullCurrentState" summary="current state is non-null"/>
|
||||
<variant name="NullCurrentState" summary="current state is null"/>
|
||||
</token>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Android.Intent.HasNonSpoofablePackageName" enum="Boolean"
|
||||
expires_after="2024-12-01">
|
||||
<owner>katzz@google.com</owner>
|
||||
|
Reference in New Issue
Block a user