Commit aa9394e0 authored by riajiang's avatar riajiang Committed by Commit bot

mus: Add watcher for all touch events.

This is part of the touch hud app for mustash (https://codereview.chromium.org/2092343002/).

BUG=588311
TEST=views_mus_unittests

Review-Url: https://codereview.chromium.org/2125663002
Cr-Commit-Position: refs/heads/master@{#405297}
parent 98caac0f
......@@ -1165,25 +1165,35 @@ void WindowTree::SetEventObserver(mojom::EventMatcherPtr matcher,
// Do not allow key events to be observed, as a compromised app could register
// itself as an event observer and spy on keystrokes to another app.
if (!matcher->type_matcher) {
if (!matcher->type_matcher && !matcher->pointer_kind_matcher) {
DVLOG(1) << "SetEventObserver must specify an event type.";
return;
}
const ui::mojom::EventType event_type_whitelist[] = {
ui::mojom::EventType::POINTER_CANCEL, ui::mojom::EventType::POINTER_DOWN,
ui::mojom::EventType::POINTER_MOVE, ui::mojom::EventType::POINTER_UP,
ui::mojom::EventType::MOUSE_EXIT, ui::mojom::EventType::WHEEL,
};
bool allowed = false;
for (ui::mojom::EventType event_type : event_type_whitelist) {
if (matcher->type_matcher->type == event_type) {
allowed = true;
break;
if (matcher->type_matcher) {
auto iter =
std::find(std::begin(event_type_whitelist),
std::end(event_type_whitelist), matcher->type_matcher->type);
if (iter == std::end(event_type_whitelist)) {
DVLOG(1) << "SetEventObserver event type not allowed";
return;
}
}
if (!allowed) {
DVLOG(1) << "SetEventObserver event type not allowed";
return;
if (matcher->pointer_kind_matcher) {
ui::mojom::PointerKind pointer_kind =
matcher->pointer_kind_matcher->pointer_kind;
if (pointer_kind != ui::mojom::PointerKind::MOUSE &&
pointer_kind != ui::mojom::PointerKind::TOUCH &&
pointer_kind != ui::mojom::PointerKind::PEN) {
DVLOG(1) << "SetEventObserver pointer kind not allowed";
return;
}
}
event_observer_matcher_.reset(new EventMatcher(*matcher));
......
......@@ -21,6 +21,7 @@
#include "ui/views/mus/native_widget_mus.h"
#include "ui/views/mus/screen_mus.h"
#include "ui/views/pointer_watcher.h"
#include "ui/views/touch_event_watcher.h"
#include "ui/views/views_delegate.h"
namespace views {
......@@ -81,6 +82,8 @@ NativeWidget* WindowManagerConnection::CreateNativeWidgetMus(
}
void WindowManagerConnection::AddPointerWatcher(PointerWatcher* watcher) {
// TODO(riajiang): Support multiple event matchers (crbug.com/627146).
DCHECK(!HasTouchEventWatcher());
bool had_watcher = HasPointerWatcher();
pointer_watchers_.AddObserver(watcher);
if (!had_watcher) {
......@@ -101,6 +104,28 @@ void WindowManagerConnection::RemovePointerWatcher(PointerWatcher* watcher) {
}
}
void WindowManagerConnection::AddTouchEventWatcher(TouchEventWatcher* watcher) {
// TODO(riajiang): Support multiple event matchers (crbug.com/627146).
DCHECK(!HasPointerWatcher());
bool had_watcher = HasTouchEventWatcher();
touch_event_watchers_.AddObserver(watcher);
if (!had_watcher) {
ui::mojom::EventMatcherPtr matcher = ui::mojom::EventMatcher::New();
matcher->pointer_kind_matcher = ui::mojom::PointerKindMatcher::New();
matcher->pointer_kind_matcher->pointer_kind = ui::mojom::PointerKind::TOUCH;
client_->SetEventObserver(std::move(matcher));
}
}
void WindowManagerConnection::RemoveTouchEventWatcher(
TouchEventWatcher* watcher) {
touch_event_watchers_.RemoveObserver(watcher);
if (!HasTouchEventWatcher()) {
// Last TouchEventWatcher removed, stop the event observer.
client_->SetEventObserver(nullptr);
}
}
const std::set<ui::Window*>& WindowManagerConnection::GetRoots() const {
return client_->GetRoots();
}
......@@ -151,6 +176,15 @@ bool WindowManagerConnection::HasPointerWatcher() {
return !!iterator.GetNext();
}
bool WindowManagerConnection::HasTouchEventWatcher() {
// Check to see if we really have any observers left. This doesn't use
// base::ObserverList<>::might_have_observers() because that returns true
// during iteration over the list even when the last observer is removed.
base::ObserverList<TouchEventWatcher>::Iterator iterator(
&touch_event_watchers_);
return !!iterator.GetNext();
}
void WindowManagerConnection::OnEmbed(ui::Window* root) {}
void WindowManagerConnection::OnDidDestroyClient(ui::WindowTreeClient* client) {
......@@ -175,14 +209,22 @@ void WindowManagerConnection::OnEventObserved(const ui::Event& event,
// to store screen coordinates. Screen coordinates really should be returned
// separately. See http://crbug.com/608547
gfx::Point location_in_screen = event.AsLocatedEvent()->root_location();
if (event.type() == ui::ET_MOUSE_PRESSED) {
FOR_EACH_OBSERVER(PointerWatcher, pointer_watchers_,
OnMousePressed(*event.AsMouseEvent(), location_in_screen,
target_widget));
} else if (event.type() == ui::ET_TOUCH_PRESSED) {
FOR_EACH_OBSERVER(PointerWatcher, pointer_watchers_,
OnTouchPressed(*event.AsTouchEvent(), location_in_screen,
target_widget));
if (HasPointerWatcher()) {
if (event.type() == ui::ET_MOUSE_PRESSED) {
FOR_EACH_OBSERVER(PointerWatcher, pointer_watchers_,
OnMousePressed(*event.AsMouseEvent(),
location_in_screen, target_widget));
} else if (event.type() == ui::ET_TOUCH_PRESSED) {
FOR_EACH_OBSERVER(PointerWatcher, pointer_watchers_,
OnTouchPressed(*event.AsTouchEvent(),
location_in_screen, target_widget));
}
} else if (HasTouchEventWatcher()) {
if (event.IsTouchEvent() || event.IsTouchPointerEvent()) {
FOR_EACH_OBSERVER(
TouchEventWatcher, touch_event_watchers_,
OnTouchEventObserved(*event.AsLocatedEvent(), target_widget));
}
}
}
......
......@@ -28,6 +28,7 @@ namespace views {
class ClipboardMus;
class NativeWidget;
class PointerWatcher;
class TouchEventWatcher;
class ScreenMus;
namespace internal {
class NativeWidgetDelegate;
......@@ -67,6 +68,9 @@ class VIEWS_MUS_EXPORT WindowManagerConnection
void AddPointerWatcher(PointerWatcher* watcher);
void RemovePointerWatcher(PointerWatcher* watcher);
void AddTouchEventWatcher(TouchEventWatcher* watcher);
void RemoveTouchEventWatcher(TouchEventWatcher* watcher);
const std::set<ui::Window*>& GetRoots() const;
private:
......@@ -75,8 +79,9 @@ class VIEWS_MUS_EXPORT WindowManagerConnection
WindowManagerConnection(shell::Connector* connector,
const shell::Identity& identity);
// Returns true if there is one or more pointer watchers for this client.
// Returns true if there is one or more watchers for this client.
bool HasPointerWatcher();
bool HasTouchEventWatcher();
// ui::WindowTreeClientDelegate:
void OnEmbed(ui::Window* root) override;
......@@ -93,6 +98,7 @@ class VIEWS_MUS_EXPORT WindowManagerConnection
std::unique_ptr<ui::WindowTreeClient> client_;
// Must be empty on destruction.
base::ObserverList<PointerWatcher, true> pointer_watchers_;
base::ObserverList<TouchEventWatcher, true> touch_event_watchers_;
DISALLOW_COPY_AND_ASSIGN(WindowManagerConnection);
};
......
......@@ -11,6 +11,7 @@
#include "ui/events/event.h"
#include "ui/views/pointer_watcher.h"
#include "ui/views/test/scoped_views_test_helper.h"
#include "ui/views/touch_event_watcher.h"
namespace views {
namespace {
......@@ -49,6 +50,31 @@ class TestPointerWatcher : public PointerWatcher {
} // namespace
namespace {
class TestTouchEventWatcher : public TouchEventWatcher {
public:
TestTouchEventWatcher() {}
~TestTouchEventWatcher() override {}
bool touch_observed() const { return touch_observed_; }
void Reset() { touch_observed_ = false; }
// TouchEventWatcher:
void OnTouchEventObserved(const ui::LocatedEvent& event,
Widget* target) override {
touch_observed_ = true;
}
private:
bool touch_observed_ = false;
DISALLOW_COPY_AND_ASSIGN(TestTouchEventWatcher);
};
} // namespace
class WindowManagerConnectionTest : public testing::Test {
public:
WindowManagerConnectionTest() {}
......@@ -115,4 +141,74 @@ TEST_F(WindowManagerConnectionTest, PointerWatcher) {
EXPECT_FALSE(watcher1.touch_pressed());
}
TEST_F(WindowManagerConnectionTest, TouchEventWatcher) {
base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
ScopedViewsTestHelper helper;
WindowManagerConnection* connection = WindowManagerConnection::Get();
ASSERT_TRUE(connection);
const ui::EventType kMouseType[] = {
ui::ET_MOUSE_PRESSED, ui::ET_MOUSE_DRAGGED, ui::ET_MOUSE_MOVED,
ui::ET_MOUSE_ENTERED, ui::ET_MOUSE_EXITED, ui::ET_MOUSE_RELEASED};
const ui::EventType kTouchType[] = {ui::ET_TOUCH_PRESSED, ui::ET_TOUCH_MOVED,
ui::ET_TOUCH_RELEASED,
ui::ET_TOUCH_CANCELLED};
TestTouchEventWatcher watcher1;
connection->AddTouchEventWatcher(&watcher1);
// TouchEventWatchers do not trigger for mouse events.
for (size_t i = 0; i < arraysize(kMouseType); i++) {
ui::MouseEvent mouse_event(kMouseType[i], gfx::Point(), gfx::Point(),
base::TimeTicks(), 0, 0);
ui::PointerEvent mouse_pointer_event(mouse_event);
EXPECT_TRUE(mouse_pointer_event.IsMousePointerEvent());
OnEventObserved(mouse_pointer_event);
EXPECT_FALSE(watcher1.touch_observed());
watcher1.Reset();
}
// TouchEventWatchers receive both TouchEvent and TouchPointerEvent.
for (size_t i = 0; i < arraysize(kTouchType); i++) {
ui::TouchEvent touch_event(kTouchType[i], gfx::Point(), 0,
base::TimeTicks());
EXPECT_TRUE(touch_event.IsTouchEvent());
OnEventObserved(touch_event);
EXPECT_TRUE(watcher1.touch_observed());
watcher1.Reset();
ui::PointerEvent touch_pointer_event(touch_event);
EXPECT_TRUE(touch_pointer_event.IsTouchPointerEvent());
OnEventObserved(touch_pointer_event);
EXPECT_TRUE(watcher1.touch_observed());
watcher1.Reset();
}
// Two TouchEventWatchers can both receive a single observed event.
TestTouchEventWatcher watcher2;
connection->AddTouchEventWatcher(&watcher2);
ui::TouchEvent touch_event(ui::ET_TOUCH_PRESSED, gfx::Point(), 0,
base::TimeTicks());
ui::PointerEvent touch_pointer_event(touch_event);
OnEventObserved(touch_pointer_event);
EXPECT_TRUE(watcher1.touch_observed());
EXPECT_TRUE(watcher2.touch_observed());
watcher1.Reset();
watcher2.Reset();
// Removing the first TouchEventWatcher stops sending events to it.
connection->RemoveTouchEventWatcher(&watcher1);
OnEventObserved(touch_pointer_event);
EXPECT_FALSE(watcher1.touch_observed());
EXPECT_TRUE(watcher2.touch_observed());
watcher1.Reset();
watcher2.Reset();
// Removing the last TouchEventWatcher stops sending events to it.
connection->RemoveTouchEventWatcher(&watcher2);
OnEventObserved(touch_pointer_event);
EXPECT_FALSE(watcher1.touch_observed());
EXPECT_FALSE(watcher2.touch_observed());
}
} // namespace views
......@@ -5,6 +5,7 @@
#ifndef UI_VIEWS_POINTER_WATCHER_H_
#define UI_VIEWS_POINTER_WATCHER_H_
#include "base/macros.h"
#include "ui/views/views_export.h"
namespace gfx {
......@@ -27,14 +28,19 @@ class Widget;
// event.target() is always null.
class VIEWS_EXPORT PointerWatcher {
public:
virtual ~PointerWatcher() {}
PointerWatcher() {}
virtual void OnMousePressed(const ui::MouseEvent& event,
const gfx::Point& location_in_screen,
Widget* target) = 0;
virtual void OnTouchPressed(const ui::TouchEvent& event,
const gfx::Point& location_in_screen,
Widget* target) = 0;
protected:
virtual ~PointerWatcher() {}
private:
DISALLOW_COPY_AND_ASSIGN(PointerWatcher);
};
} // namespace views
......
// Copyright 2016 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.
#ifndef UI_VIEWS_TOUCH_EVENT_WATCHER_H_
#define UI_VIEWS_TOUCH_EVENT_WATCHER_H_
#include "base/macros.h"
#include "ui/views/views_export.h"
namespace gfx {
class Point;
}
namespace ui {
class LocatedEvent;
}
namespace views {
class Widget;
// An interface for read-only observation of touch events (in particular, the
// events cannot be marked as handled). Only touch pointer kind are supported.
// The |target| is the top-level widget that will receive the event, if any.
// NOTE: On mus this allows observation of events outside of windows owned
// by the current process, in which case the |target| will be null. On mus
// event.target() is always null.
class VIEWS_EXPORT TouchEventWatcher {
public:
TouchEventWatcher() {}
virtual void OnTouchEventObserved(const ui::LocatedEvent& event,
Widget* target) = 0;
protected:
virtual ~TouchEventWatcher() {}
private:
DISALLOW_COPY_AND_ASSIGN(TouchEventWatcher);
};
} // namespace views
#endif // UI_VIEWS_TOUCH_EVENT_WATCHER_H_
......@@ -299,6 +299,7 @@
'style/platform_style.cc',
'style/platform_style.h',
'style/platform_style_mac.mm',
'touch_event_watcher.h',
'view.cc',
'view.h',
'view_constants.cc',
......
......@@ -8,3 +8,4 @@
// the resulting dynamic library.
#include "ui/views/pointer_watcher.h"
#include "ui/views/touch_event_watcher.h"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment