Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(378)

Unified Diff: ui/android/view_android.cc

Issue 2708613002: Add EventForwarder for routing touch events (Closed)
Patch Set: base::Bind (doesn't compile yet) Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/android/view_android.cc
diff --git a/ui/android/view_android.cc b/ui/android/view_android.cc
index 1d5b146653458a83b93c58810f743f6df78e5c46..d36e3d08af98cc8332fed5c5f3d5f9480d98d8be 100644
--- a/ui/android/view_android.cc
+++ b/ui/android/view_android.cc
@@ -8,11 +8,14 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
+#include "base/containers/adapters.h"
#include "cc/layers/layer.h"
#include "jni/ViewAndroidDelegate_jni.h"
+#include "ui/android/event_handler.h"
+#include "ui/android/view_client.h"
#include "ui/android/window_android.h"
-#include "ui/display/display.h"
-#include "ui/display/screen.h"
+#include "ui/base/layout.h"
+#include "ui/events/android/motion_event_android.h"
#include "url/gurl.h"
namespace ui {
@@ -21,6 +24,40 @@ using base::android::ConvertUTF8ToJavaString;
using base::android::JavaRef;
using base::android::ScopedJavaLocalRef;
+namespace {
+
+struct TouchEventSender : ViewAndroid::EventSender {
+ TouchEventSender(bool for_touch_handle)
+ : for_touch_handle_(for_touch_handle) {}
+ bool SendToView(ViewAndroid* view,
+ const MotionEventAndroid& e) const override {
+ return view->OnTouchEvent(e, for_touch_handle_);
+ }
+
+ bool SendToClient(ViewClient* client,
+ const MotionEventAndroid& e) const override {
+ return client->OnTouchEvent(e, for_touch_handle_);
+ }
+
+ private:
+ bool for_touch_handle_;
+};
+
+struct MouseEventSender : ViewAndroid::EventSender {
+ MouseEventSender() {}
+ bool SendToView(ViewAndroid* view,
+ const MotionEventAndroid& e) const override {
+ return view->OnMouseEvent(e);
+ }
+
+ bool SendToClient(ViewClient* client,
+ const MotionEventAndroid& e) const override {
+ return client->OnMouseEvent(e);
+ }
+};
+
+} // namespace
+
ViewAndroid::ScopedAnchorView::ScopedAnchorView(
JNIEnv* env,
const JavaRef<jobject>& jview,
@@ -71,11 +108,10 @@ ViewAndroid::ScopedAnchorView::view() const {
return view_.get(env);
}
-ViewAndroid::ViewAndroid(const JavaRef<jobject>& delegate)
- : parent_(nullptr),
- delegate_(base::android::AttachCurrentThread(), delegate.obj()) {}
+ViewAndroid::ViewAndroid(ViewClient* view_client)
+ : parent_(nullptr), client_(view_client) {}
-ViewAndroid::ViewAndroid() : parent_(nullptr) {}
+ViewAndroid::ViewAndroid() : ViewAndroid(nullptr) {}
ViewAndroid::~ViewAndroid() {
RemoveFromParent();
@@ -88,21 +124,71 @@ ViewAndroid::~ViewAndroid() {
}
void ViewAndroid::SetDelegate(const JavaRef<jobject>& delegate) {
+ // A ViewAndroid may have its own delegate or otherwise will use the next
+ // available parent's delegate.
JNIEnv* env = base::android::AttachCurrentThread();
delegate_ = JavaObjectWeakGlobalRef(env, delegate);
}
+float ViewAndroid::GetDipScale() {
+ return ui::GetScaleFactorForNativeView(this);
+}
+
+ScopedJavaLocalRef<jobject> ViewAndroid::GetEventHandler() {
+ if (!event_handler_) {
+ DCHECK(!ViewTreeHasEventHandler(this))
+ << "Root of the ViewAndroid can have at most one handler.";
+ event_handler_.reset(new EventHandler(this));
+ }
+ return event_handler_->GetJavaObject();
+}
+
void ViewAndroid::AddChild(ViewAndroid* child) {
DCHECK(child);
DCHECK(std::find(children_.begin(), children_.end(), child) ==
children_.end());
+ DCHECK(!SubtreeHasEventHandler(child) || !ViewTreeHasEventHandler(this))
+ << "Only one event handler is allowed.";
+ // The new child goes to the top, which is the end of the list.
children_.push_back(child);
if (child->parent_)
child->RemoveFromParent();
child->parent_ = this;
}
+// static
+bool ViewAndroid::ViewTreeHasEventHandler(ViewAndroid* view) {
+ ViewAndroid* v = view;
+ do {
+ if (v->has_event_handler())
+ return true;
+ v = v->parent_;
+ } while (v);
+ return SubtreeHasEventHandler(view);
+}
+
+// static
+bool ViewAndroid::SubtreeHasEventHandler(ViewAndroid* view) {
+ if (view->has_event_handler())
+ return true;
+ for (auto* child : view->children_) {
+ if (SubtreeHasEventHandler(child))
+ return true;
+ }
+ return false;
+}
+
+void ViewAndroid::MoveToFront(ViewAndroid* child) {
+ DCHECK(child);
+ auto it = std::find(children_.begin(), children_.end(), child);
+ DCHECK(it != children_.end());
+
+ // Top element is placed at the end of the list.
+ if (*it != children_.back())
+ children_.splice(children_.end(), children_, it);
+}
+
void ViewAndroid::RemoveFromParent() {
if (parent_)
parent_->RemoveChild(this);
@@ -124,15 +210,13 @@ void ViewAndroid::SetAnchorRect(const JavaRef<jobject>& anchor,
if (delegate.is_null())
return;
- float scale = display::Screen::GetScreen()
- ->GetDisplayNearestWindow(this)
- .device_scale_factor();
- int left_margin = std::round(bounds.x() * scale);
- int top_margin = std::round((content_offset().y() + bounds.y()) * scale);
+ float dip_scale = GetDipScale();
+ int left_margin = std::round(bounds.x() * dip_scale);
+ int top_margin = std::round((content_offset().y() + bounds.y()) * dip_scale);
JNIEnv* env = base::android::AttachCurrentThread();
Java_ViewAndroidDelegate_setViewPosition(
env, delegate, anchor, bounds.x(), bounds.y(), bounds.width(),
- bounds.height(), scale, left_margin, top_margin);
+ bounds.height(), dip_scale, left_margin, top_margin);
}
ScopedJavaLocalRef<jobject> ViewAndroid::GetContainerView() {
@@ -177,6 +261,14 @@ void ViewAndroid::SetLayer(scoped_refptr<cc::Layer> layer) {
layer_ = layer;
}
+void ViewAndroid::SetLayout(ViewAndroid::LayoutParams params) {
+ match_parent_ = params.match_parent;
+ if (!params.match_parent) {
+ origin_.SetPoint(params.x, params.y);
+ size_.SetSize(params.width, params.height);
+ }
+}
+
bool ViewAndroid::StartDragAndDrop(const JavaRef<jstring>& jtext,
const JavaRef<jobject>& jimage) {
ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
@@ -227,4 +319,59 @@ void ViewAndroid::StartContentIntent(const GURL& content_url,
is_main_frame);
}
+bool ViewAndroid::OnTouchEvent(const MotionEventAndroid& event,
+ bool for_touch_handle) {
+ return HitTest(
+ base::Bind([for_touch_handle](ViewClient* client,
+ const MotionEventAndroid& event) -> bool {
+ return client->OnTouchEvent(event, for_touch_handle);
+ }),
+ base::Bind([for_touch_handle](ViewAndroid* view,
+ const MotionEventAndroid& event) -> bool {
+ return view->OnTouchEvent(event, for_touch_handle);
+ }),
+ event);
+}
+
+bool ViewAndroid::OnMouseEvent(const MotionEventAndroid& event) {
+ return HitTest(base::Bind(&ViewAndroid::SendToClient),
+ base::Bind(&ViewAndroid::SendToView), event);
+}
+
+bool ViewAndroid::SendToClient(ViewClient* client,
+ const MotionEventAndroid& event) {
+ return client->OnMouseEvent(event);
+}
+
+bool ViewAndroid::SendToView(ViewAndroid* view,
+ const MotionEventAndroid& event) {
+ return view->OnMouseEvent(event);
+}
+
+bool ViewAndroid::HitTest(
+ const base::Callback<bool(ViewClient*, const MotionEventAndroid&)>
+ send_to_client,
+ const base::Callback<bool(ViewAndroid*, const MotionEventAndroid&)>
+ send_to_view,
boliu 2017/03/06 22:19:59 you don't need send_to_view, HitTest can just recu
Jinsuk Kim 2017/03/07 05:02:23 Sorry missed your comment... now made HitTest recu
boliu 2017/03/07 05:08:49 I meant no lambda, but yes callbacks
Jinsuk Kim 2017/03/08 02:16:16 Yes already done. PTAL
+ const MotionEventAndroid& event) {
+ if (client_ && send_to_client.Run(client_, event))
+ return true;
+
+ if (!children_.empty()) {
+ MotionEventAndroid e(event, -origin_.x(), -origin_.y());
+
+ // Match from back to front for hit testing.
+ for (auto* child : base::Reversed(children_)) {
+ bool matched = child->match_parent_;
+ if (!matched) {
+ gfx::Rect bound(child->origin_, child->size_);
+ matched = bound.Contains(e.GetX(0), e.GetY(0));
+ }
+ if (matched && send_to_view.Run(child, e))
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace ui

Powered by Google App Engine
This is Rietveld 408576698