1 // Copyright 2016 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
5 #include "ui/android/view_android.h"
6
7 #include <algorithm>
8 #include <cmath>
9 #include <utility>
10
11 #include "base/android/jni_android.h"
12 #include "base/android/jni_string.h"
13 #include "base/containers/adapters.h"
14 #include "base/stl_util.h"
15 #include "cc/layers/layer.h"
16 #include "components/viz/common/frame_sinks/copy_output_request.h"
17 #include "ui/android/event_forwarder.h"
18 #include "ui/android/ui_android_jni_headers/ViewAndroidDelegate_jni.h"
19 #include "ui/android/window_android.h"
20 #include "ui/base/layout.h"
21 #include "ui/base/mojom/cursor_type.mojom-shared.h"
22 #include "ui/events/android/drag_event_android.h"
23 #include "ui/events/android/event_handler_android.h"
24 #include "ui/events/android/gesture_event_android.h"
25 #include "ui/events/android/key_event_android.h"
26 #include "ui/events/android/motion_event_android.h"
27 #include "ui/gfx/android/java_bitmap.h"
28 #include "url/gurl.h"
29
30 namespace ui {
31
32 using base::android::ConvertUTF8ToJavaString;
33 using base::android::JavaRef;
34 using base::android::ScopedJavaLocalRef;
35
ScopedAnchorView(JNIEnv * env,const JavaRef<jobject> & jview,const JavaRef<jobject> & jdelegate)36 ViewAndroid::ScopedAnchorView::ScopedAnchorView(
37 JNIEnv* env,
38 const JavaRef<jobject>& jview,
39 const JavaRef<jobject>& jdelegate)
40 : view_(env, jview.obj()), delegate_(env, jdelegate.obj()) {
41 // If there's a view, then we need a delegate to remove it.
42 DCHECK(!jdelegate.is_null() || jview.is_null());
43 }
44
ScopedAnchorView()45 ViewAndroid::ScopedAnchorView::ScopedAnchorView() { }
46
ScopedAnchorView(ScopedAnchorView && other)47 ViewAndroid::ScopedAnchorView::ScopedAnchorView(ScopedAnchorView&& other) {
48 view_ = other.view_;
49 other.view_.reset();
50 delegate_ = other.delegate_;
51 other.delegate_.reset();
52 }
53
54 ViewAndroid::ScopedAnchorView&
operator =(ScopedAnchorView && other)55 ViewAndroid::ScopedAnchorView::operator=(ScopedAnchorView&& other) {
56 if (this != &other) {
57 view_ = other.view_;
58 other.view_.reset();
59 delegate_ = other.delegate_;
60 other.delegate_.reset();
61 }
62 return *this;
63 }
64
~ScopedAnchorView()65 ViewAndroid::ScopedAnchorView::~ScopedAnchorView() {
66 Reset();
67 }
68
Reset()69 void ViewAndroid::ScopedAnchorView::Reset() {
70 JNIEnv* env = base::android::AttachCurrentThread();
71 const ScopedJavaLocalRef<jobject> view = view_.get(env);
72 const ScopedJavaLocalRef<jobject> delegate = delegate_.get(env);
73 if (!view.is_null() && !delegate.is_null()) {
74 Java_ViewAndroidDelegate_removeView(env, delegate, view);
75 }
76 view_.reset();
77 delegate_.reset();
78 }
79
80 const base::android::ScopedJavaLocalRef<jobject>
view() const81 ViewAndroid::ScopedAnchorView::view() const {
82 JNIEnv* env = base::android::AttachCurrentThread();
83 return view_.get(env);
84 }
85
ViewAndroid(LayoutType layout_type)86 ViewAndroid::ViewAndroid(LayoutType layout_type)
87 : parent_(nullptr), layout_type_(layout_type) {}
88
ViewAndroid()89 ViewAndroid::ViewAndroid() : ViewAndroid(LayoutType::NORMAL) {}
90
~ViewAndroid()91 ViewAndroid::~ViewAndroid() {
92 RemoveAllChildren(GetWindowAndroid() != nullptr);
93 for (auto& observer : observer_list_)
94 observer.OnViewAndroidDestroyed();
95 observer_list_.Clear();
96 RemoveFromParent();
97 }
98
SetDelegate(const JavaRef<jobject> & delegate)99 void ViewAndroid::SetDelegate(const JavaRef<jobject>& delegate) {
100 // A ViewAndroid may have its own delegate or otherwise will use the next
101 // available parent's delegate.
102 JNIEnv* env = base::android::AttachCurrentThread();
103 delegate_ = JavaObjectWeakGlobalRef(env, delegate);
104 }
105
UpdateFrameInfo(const FrameInfo & frame_info)106 void ViewAndroid::UpdateFrameInfo(const FrameInfo& frame_info) {
107 frame_info_ = frame_info;
108 }
109
GetDipScale()110 float ViewAndroid::GetDipScale() {
111 return ui::GetScaleFactorForNativeView(this);
112 }
113
GetEventForwarder()114 ScopedJavaLocalRef<jobject> ViewAndroid::GetEventForwarder() {
115 if (!event_forwarder_) {
116 DCHECK(!RootPathHasEventForwarder(parent_))
117 << "The view tree path already has an event forwarder.";
118 DCHECK(!SubtreeHasEventForwarder(this))
119 << "The view tree path already has an event forwarder.";
120 event_forwarder_.reset(new EventForwarder(this));
121 }
122 return event_forwarder_->GetJavaObject();
123 }
124
AddChild(ViewAndroid * child)125 void ViewAndroid::AddChild(ViewAndroid* child) {
126 DCHECK(child);
127 DCHECK(!base::Contains(children_, child));
128 DCHECK(!RootPathHasEventForwarder(this) || !SubtreeHasEventForwarder(child))
129 << "Some view tree path will have more than one event forwarder "
130 "if the child is added.";
131
132 // The new child goes to the top, which is the end of the list.
133 children_.push_back(child);
134 if (child->parent_)
135 child->RemoveFromParent();
136 child->parent_ = this;
137
138 // Empty physical backing size need not propagating down since it can
139 // accidentally overwrite the valid ones in the children.
140 if (!physical_size_.IsEmpty())
141 child->OnPhysicalBackingSizeChanged(physical_size_);
142
143 // Empty view size also need not propagating down in order to prevent
144 // spurious events with empty size from being sent down.
145 if (child->match_parent() && !bounds_.IsEmpty() &&
146 child->GetSize() != bounds_.size()) {
147 child->OnSizeChangedInternal(bounds_.size());
148 child->DispatchOnSizeChanged();
149 }
150
151 if (GetWindowAndroid())
152 child->OnAttachedToWindow();
153 }
154
155 // static
RootPathHasEventForwarder(ViewAndroid * view)156 bool ViewAndroid::RootPathHasEventForwarder(ViewAndroid* view) {
157 while (view) {
158 if (view->has_event_forwarder())
159 return true;
160 view = view->parent_;
161 }
162
163 return false;
164 }
165
166 // static
SubtreeHasEventForwarder(ViewAndroid * view)167 bool ViewAndroid::SubtreeHasEventForwarder(ViewAndroid* view) {
168 if (view->has_event_forwarder())
169 return true;
170
171 for (auto* child : view->children_) {
172 if (SubtreeHasEventForwarder(child))
173 return true;
174 }
175 return false;
176 }
177
MoveToFront(ViewAndroid * child)178 void ViewAndroid::MoveToFront(ViewAndroid* child) {
179 DCHECK(child);
180 auto it = std::find(children_.begin(), children_.end(), child);
181 DCHECK(it != children_.end());
182
183 // Top element is placed at the end of the list.
184 if (*it != children_.back())
185 children_.splice(children_.end(), children_, it);
186 }
187
MoveToBack(ViewAndroid * child)188 void ViewAndroid::MoveToBack(ViewAndroid* child) {
189 DCHECK(child);
190 auto it = std::find(children_.begin(), children_.end(), child);
191 DCHECK(it != children_.end());
192
193 // Bottom element is placed at the beginning of the list.
194 if (*it != children_.front())
195 children_.splice(children_.begin(), children_, it);
196 }
197
RemoveFromParent()198 void ViewAndroid::RemoveFromParent() {
199 if (parent_)
200 parent_->RemoveChild(this);
201 }
202
AcquireAnchorView()203 ViewAndroid::ScopedAnchorView ViewAndroid::AcquireAnchorView() {
204 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
205 if (delegate.is_null())
206 return ViewAndroid::ScopedAnchorView();
207
208 JNIEnv* env = base::android::AttachCurrentThread();
209 return ViewAndroid::ScopedAnchorView(
210 env, Java_ViewAndroidDelegate_acquireView(env, delegate), delegate);
211 }
212
SetAnchorRect(const JavaRef<jobject> & anchor,const gfx::RectF & bounds_dip)213 void ViewAndroid::SetAnchorRect(const JavaRef<jobject>& anchor,
214 const gfx::RectF& bounds_dip) {
215 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
216 if (delegate.is_null())
217 return;
218
219 float dip_scale = GetDipScale();
220 int left_margin = std::round(bounds_dip.x() * dip_scale);
221 // Note that content_offset() is in CSS scale and bounds_dip is in DIP scale
222 // (i.e., CSS pixels * page scale factor), but the height of browser control
223 // is not affected by page scale factor. Thus, content_offset() in CSS scale
224 // is also in DIP scale.
225 int top_margin = std::round((content_offset() + bounds_dip.y()) * dip_scale);
226 const gfx::RectF bounds_px = gfx::ScaleRect(bounds_dip, dip_scale);
227 JNIEnv* env = base::android::AttachCurrentThread();
228 Java_ViewAndroidDelegate_setViewPosition(
229 env, delegate, anchor, bounds_px.x(), bounds_px.y(), bounds_px.width(),
230 bounds_px.height(), left_margin, top_margin);
231 }
232
GetContainerView()233 ScopedJavaLocalRef<jobject> ViewAndroid::GetContainerView() {
234 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
235 if (delegate.is_null())
236 return nullptr;
237
238 JNIEnv* env = base::android::AttachCurrentThread();
239 return Java_ViewAndroidDelegate_getContainerView(env, delegate);
240 }
241
GetLocationOfContainerViewInWindow()242 gfx::Point ViewAndroid::GetLocationOfContainerViewInWindow() {
243 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
244 if (delegate.is_null())
245 return gfx::Point();
246
247 JNIEnv* env = base::android::AttachCurrentThread();
248 gfx::Point result(
249 Java_ViewAndroidDelegate_getXLocationOfContainerViewInWindow(env,
250 delegate),
251 Java_ViewAndroidDelegate_getYLocationOfContainerViewInWindow(env,
252 delegate));
253
254 return result;
255 }
256
GetLocationOnScreen(float x,float y)257 gfx::PointF ViewAndroid::GetLocationOnScreen(float x, float y) {
258 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
259 if (delegate.is_null())
260 return gfx::PointF();
261
262 JNIEnv* env = base::android::AttachCurrentThread();
263 float loc_x = Java_ViewAndroidDelegate_getXLocationOnScreen(env, delegate);
264 float loc_y = Java_ViewAndroidDelegate_getYLocationOnScreen(env, delegate);
265 return gfx::PointF(x + loc_x, y + loc_y);
266 }
267
RemoveAllChildren(bool attached_to_window)268 void ViewAndroid::RemoveAllChildren(bool attached_to_window) {
269 auto it = children_.begin();
270 while (it != children_.end()) {
271 if (attached_to_window)
272 (*it)->OnDetachedFromWindow();
273 (*it)->parent_ = nullptr;
274 // erase returns a new iterator for the element following the ereased one.
275 it = children_.erase(it);
276 }
277 }
278
RemoveChild(ViewAndroid * child)279 void ViewAndroid::RemoveChild(ViewAndroid* child) {
280 DCHECK(child);
281 DCHECK_EQ(child->parent_, this);
282
283 if (GetWindowAndroid())
284 child->OnDetachedFromWindow();
285 std::list<ViewAndroid*>::iterator it =
286 std::find(children_.begin(), children_.end(), child);
287 DCHECK(it != children_.end());
288 children_.erase(it);
289 child->parent_ = nullptr;
290 }
291
AddObserver(ViewAndroidObserver * observer)292 void ViewAndroid::AddObserver(ViewAndroidObserver* observer) {
293 observer_list_.AddObserver(observer);
294 }
295
RemoveObserver(ViewAndroidObserver * observer)296 void ViewAndroid::RemoveObserver(ViewAndroidObserver* observer) {
297 observer_list_.RemoveObserver(observer);
298 }
299
RequestDisallowInterceptTouchEvent()300 void ViewAndroid::RequestDisallowInterceptTouchEvent() {
301 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
302 if (delegate.is_null())
303 return;
304 JNIEnv* env = base::android::AttachCurrentThread();
305 Java_ViewAndroidDelegate_requestDisallowInterceptTouchEvent(env, delegate);
306 }
307
RequestUnbufferedDispatch(const MotionEventAndroid & event)308 void ViewAndroid::RequestUnbufferedDispatch(const MotionEventAndroid& event) {
309 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
310 if (delegate.is_null())
311 return;
312 JNIEnv* env = base::android::AttachCurrentThread();
313 Java_ViewAndroidDelegate_requestUnbufferedDispatch(env, delegate,
314 event.GetJavaObject());
315 }
316
SetCopyOutputCallback(CopyViewCallback callback)317 void ViewAndroid::SetCopyOutputCallback(CopyViewCallback callback) {
318 copy_view_callback_ = std::move(callback);
319 }
320
321 // If view does not support copy request, return back the request.
MaybeRequestCopyOfView(std::unique_ptr<viz::CopyOutputRequest> request)322 std::unique_ptr<viz::CopyOutputRequest> ViewAndroid::MaybeRequestCopyOfView(
323 std::unique_ptr<viz::CopyOutputRequest> request) {
324 if (copy_view_callback_.is_null())
325 return request;
326 copy_view_callback_.Run(std::move(request));
327 return nullptr;
328 }
329
OnAttachedToWindow()330 void ViewAndroid::OnAttachedToWindow() {
331 for (auto& observer : observer_list_)
332 observer.OnAttachedToWindow();
333 for (auto* child : children_)
334 child->OnAttachedToWindow();
335 }
336
OnDetachedFromWindow()337 void ViewAndroid::OnDetachedFromWindow() {
338 for (auto& observer : observer_list_)
339 observer.OnDetachedFromWindow();
340 for (auto* child : children_)
341 child->OnDetachedFromWindow();
342 }
343
GetWindowAndroid() const344 WindowAndroid* ViewAndroid::GetWindowAndroid() const {
345 return parent_ ? parent_->GetWindowAndroid() : nullptr;
346 }
347
GetViewAndroidDelegate() const348 const ScopedJavaLocalRef<jobject> ViewAndroid::GetViewAndroidDelegate()
349 const {
350 JNIEnv* env = base::android::AttachCurrentThread();
351 const ScopedJavaLocalRef<jobject> delegate = delegate_.get(env);
352 if (!delegate.is_null())
353 return delegate;
354
355 return parent_ ? parent_->GetViewAndroidDelegate() : delegate;
356 }
357
GetLayer() const358 cc::Layer* ViewAndroid::GetLayer() const {
359 return layer_.get();
360 }
361
HasFocus()362 bool ViewAndroid::HasFocus() {
363 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
364 if (delegate.is_null())
365 return false;
366 JNIEnv* env = base::android::AttachCurrentThread();
367 return Java_ViewAndroidDelegate_hasFocus(env, delegate);
368 }
369
RequestFocus()370 void ViewAndroid::RequestFocus() {
371 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
372 if (delegate.is_null())
373 return;
374 JNIEnv* env = base::android::AttachCurrentThread();
375 Java_ViewAndroidDelegate_requestFocus(env, delegate);
376 }
377
SetLayer(scoped_refptr<cc::Layer> layer)378 void ViewAndroid::SetLayer(scoped_refptr<cc::Layer> layer) {
379 layer_ = layer;
380 }
381
StartDragAndDrop(const JavaRef<jstring> & jtext,const JavaRef<jobject> & jimage)382 bool ViewAndroid::StartDragAndDrop(const JavaRef<jstring>& jtext,
383 const JavaRef<jobject>& jimage) {
384 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
385 if (delegate.is_null())
386 return false;
387 JNIEnv* env = base::android::AttachCurrentThread();
388 return Java_ViewAndroidDelegate_startDragAndDrop(env, delegate, jtext,
389 jimage);
390 }
391
OnCursorChanged(int type,const SkBitmap & custom_image,const gfx::Point & hotspot)392 void ViewAndroid::OnCursorChanged(int type,
393 const SkBitmap& custom_image,
394 const gfx::Point& hotspot) {
395 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
396 if (delegate.is_null())
397 return;
398 JNIEnv* env = base::android::AttachCurrentThread();
399 if (type == static_cast<int>(ui::mojom::CursorType::kCustom)) {
400 if (custom_image.drawsNothing()) {
401 Java_ViewAndroidDelegate_onCursorChanged(
402 env, delegate, static_cast<int>(ui::mojom::CursorType::kPointer));
403 return;
404 }
405 ScopedJavaLocalRef<jobject> java_bitmap =
406 gfx::ConvertToJavaBitmap(&custom_image);
407 Java_ViewAndroidDelegate_onCursorChangedToCustom(env, delegate, java_bitmap,
408 hotspot.x(), hotspot.y());
409 } else {
410 Java_ViewAndroidDelegate_onCursorChanged(env, delegate, type);
411 }
412 }
413
OnBackgroundColorChanged(unsigned int color)414 void ViewAndroid::OnBackgroundColorChanged(unsigned int color) {
415 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
416 if (delegate.is_null())
417 return;
418 JNIEnv* env = base::android::AttachCurrentThread();
419 Java_ViewAndroidDelegate_onBackgroundColorChanged(env, delegate, color);
420 }
421
OnTopControlsChanged(float top_controls_offset,float top_content_offset,float top_controls_min_height_offset)422 void ViewAndroid::OnTopControlsChanged(float top_controls_offset,
423 float top_content_offset,
424 float top_controls_min_height_offset) {
425 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
426 if (delegate.is_null())
427 return;
428 JNIEnv* env = base::android::AttachCurrentThread();
429 Java_ViewAndroidDelegate_onTopControlsChanged(
430 env, delegate, std::round(top_controls_offset),
431 std::round(top_content_offset),
432 std::round(top_controls_min_height_offset));
433 }
434
OnBottomControlsChanged(float bottom_controls_offset,float bottom_content_offset,float bottom_controls_min_height_offset)435 void ViewAndroid::OnBottomControlsChanged(
436 float bottom_controls_offset,
437 float bottom_content_offset,
438 float bottom_controls_min_height_offset) {
439 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
440 if (delegate.is_null())
441 return;
442 JNIEnv* env = base::android::AttachCurrentThread();
443 Java_ViewAndroidDelegate_onBottomControlsChanged(
444 env, delegate, std::round(bottom_controls_offset),
445 std::round(bottom_content_offset),
446 std::round(bottom_controls_min_height_offset));
447 }
448
GetViewportInsetBottom()449 int ViewAndroid::GetViewportInsetBottom() {
450 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
451 if (delegate.is_null())
452 return 0;
453 JNIEnv* env = base::android::AttachCurrentThread();
454 return Java_ViewAndroidDelegate_getViewportInsetBottom(env, delegate);
455 }
456
OnBrowserControlsHeightChanged()457 void ViewAndroid::OnBrowserControlsHeightChanged() {
458 if (event_handler_)
459 event_handler_->OnBrowserControlsHeightChanged();
460 for (auto* child : children_) {
461 if (child->match_parent())
462 child->OnBrowserControlsHeightChanged();
463 }
464 }
465
OnSizeChanged(int width,int height)466 void ViewAndroid::OnSizeChanged(int width, int height) {
467 // Match-parent view must not receive size events.
468 DCHECK(!match_parent());
469
470 float scale = GetDipScale();
471 gfx::Size size(std::ceil(width / scale), std::ceil(height / scale));
472 if (bounds_.size() == size)
473 return;
474
475 OnSizeChangedInternal(size);
476
477 // Signal resize event after all the views in the tree get the updated size.
478 DispatchOnSizeChanged();
479 }
480
OnSizeChangedInternal(const gfx::Size & size)481 void ViewAndroid::OnSizeChangedInternal(const gfx::Size& size) {
482 if (bounds_.size() == size)
483 return;
484
485 bounds_.set_size(size);
486 for (auto* child : children_) {
487 if (child->match_parent())
488 child->OnSizeChangedInternal(size);
489 }
490 }
491
DispatchOnSizeChanged()492 void ViewAndroid::DispatchOnSizeChanged() {
493 if (event_handler_)
494 event_handler_->OnSizeChanged();
495 for (auto* child : children_) {
496 if (child->match_parent())
497 child->DispatchOnSizeChanged();
498 }
499 }
500
OnPhysicalBackingSizeChanged(const gfx::Size & size)501 void ViewAndroid::OnPhysicalBackingSizeChanged(const gfx::Size& size) {
502 if (physical_size_ == size)
503 return;
504 physical_size_ = size;
505 if (event_handler_)
506 event_handler_->OnPhysicalBackingSizeChanged();
507
508 for (auto* child : children_)
509 child->OnPhysicalBackingSizeChanged(size);
510 }
511
GetPhysicalBackingSize() const512 gfx::Size ViewAndroid::GetPhysicalBackingSize() const {
513 return physical_size_;
514 }
515
GetSize() const516 gfx::Size ViewAndroid::GetSize() const {
517 return bounds_.size();
518 }
519
OnDragEvent(const DragEventAndroid & event)520 bool ViewAndroid::OnDragEvent(const DragEventAndroid& event) {
521 return HitTest(base::BindRepeating(&ViewAndroid::SendDragEventToHandler),
522 event, event.location_f());
523 }
524
525 // static
SendDragEventToHandler(EventHandlerAndroid * handler,const DragEventAndroid & event)526 bool ViewAndroid::SendDragEventToHandler(EventHandlerAndroid* handler,
527 const DragEventAndroid& event) {
528 return handler->OnDragEvent(event);
529 }
530
OnTouchEvent(const MotionEventAndroid & event)531 bool ViewAndroid::OnTouchEvent(const MotionEventAndroid& event) {
532 return HitTest(base::BindRepeating(&ViewAndroid::SendTouchEventToHandler),
533 event, event.GetPoint());
534 }
535
536 // static
SendTouchEventToHandler(EventHandlerAndroid * handler,const MotionEventAndroid & event)537 bool ViewAndroid::SendTouchEventToHandler(EventHandlerAndroid* handler,
538 const MotionEventAndroid& event) {
539 return handler->OnTouchEvent(event);
540 }
541
OnMouseEvent(const MotionEventAndroid & event)542 bool ViewAndroid::OnMouseEvent(const MotionEventAndroid& event) {
543 return HitTest(base::BindRepeating(&ViewAndroid::SendMouseEventToHandler),
544 event, event.GetPoint());
545 }
546
547 // static
SendMouseEventToHandler(EventHandlerAndroid * handler,const MotionEventAndroid & event)548 bool ViewAndroid::SendMouseEventToHandler(EventHandlerAndroid* handler,
549 const MotionEventAndroid& event) {
550 return handler->OnMouseEvent(event);
551 }
552
OnMouseWheelEvent(const MotionEventAndroid & event)553 bool ViewAndroid::OnMouseWheelEvent(const MotionEventAndroid& event) {
554 return HitTest(
555 base::BindRepeating(&ViewAndroid::SendMouseWheelEventToHandler), event,
556 event.GetPoint());
557 }
558
559 // static
SendMouseWheelEventToHandler(EventHandlerAndroid * handler,const MotionEventAndroid & event)560 bool ViewAndroid::SendMouseWheelEventToHandler(
561 EventHandlerAndroid* handler,
562 const MotionEventAndroid& event) {
563 return handler->OnMouseWheelEvent(event);
564 }
565
OnGestureEvent(const GestureEventAndroid & event)566 bool ViewAndroid::OnGestureEvent(const GestureEventAndroid& event) {
567 return HitTest(base::BindRepeating(&ViewAndroid::SendGestureEventToHandler),
568 event, event.location());
569 }
570
571 // static
SendGestureEventToHandler(EventHandlerAndroid * handler,const GestureEventAndroid & event)572 bool ViewAndroid::SendGestureEventToHandler(EventHandlerAndroid* handler,
573 const GestureEventAndroid& event) {
574 return handler->OnGestureEvent(event);
575 }
576
OnGenericMotionEvent(const MotionEventAndroid & event)577 bool ViewAndroid::OnGenericMotionEvent(const MotionEventAndroid& event) {
578 if (event_handler_ && event_handler_->OnGenericMotionEvent(event))
579 return true;
580
581 for (auto* child : children_) {
582 if (child->OnGenericMotionEvent(event))
583 return true;
584 }
585 return false;
586 }
587
OnKeyUp(const KeyEventAndroid & event)588 bool ViewAndroid::OnKeyUp(const KeyEventAndroid& event) {
589 if (event_handler_ && event_handler_->OnKeyUp(event))
590 return true;
591
592 for (auto* child : children_) {
593 if (child->OnKeyUp(event))
594 return true;
595 }
596 return false;
597 }
598
DispatchKeyEvent(const KeyEventAndroid & event)599 bool ViewAndroid::DispatchKeyEvent(const KeyEventAndroid& event) {
600 if (event_handler_ && event_handler_->DispatchKeyEvent(event))
601 return true;
602
603 for (auto* child : children_) {
604 if (child->DispatchKeyEvent(event))
605 return true;
606 }
607 return false;
608 }
609
ScrollBy(float delta_x,float delta_y)610 bool ViewAndroid::ScrollBy(float delta_x, float delta_y) {
611 if (event_handler_ && event_handler_->ScrollBy(delta_x, delta_y))
612 return true;
613
614 for (auto* child : children_) {
615 if (child->ScrollBy(delta_x, delta_y))
616 return true;
617 }
618 return false;
619 }
620
ScrollTo(float x,float y)621 bool ViewAndroid::ScrollTo(float x, float y) {
622 if (event_handler_ && event_handler_->ScrollTo(x, y))
623 return true;
624
625 for (auto* child : children_) {
626 if (child->ScrollTo(x, y))
627 return true;
628 }
629 return false;
630 }
631
632 template <typename E>
HitTest(EventHandlerCallback<E> handler_callback,const E & event,const gfx::PointF & point)633 bool ViewAndroid::HitTest(EventHandlerCallback<E> handler_callback,
634 const E& event,
635 const gfx::PointF& point) {
636 if (event_handler_) {
637 if (bounds_.origin().IsOrigin()) { // (x, y) == (0, 0)
638 if (handler_callback.Run(event_handler_, event))
639 return true;
640 } else {
641 std::unique_ptr<E> e(event.CreateFor(point));
642 if (handler_callback.Run(event_handler_, *e))
643 return true;
644 }
645 }
646
647 if (!children_.empty()) {
648 gfx::PointF offset_point(point);
649 offset_point.Offset(-bounds_.x(), -bounds_.y());
650 gfx::Point int_point = gfx::ToFlooredPoint(offset_point);
651
652 // Match from back to front for hit testing.
653 for (auto* child : base::Reversed(children_)) {
654 bool matched = child->match_parent();
655 if (!matched)
656 matched = child->bounds_.Contains(int_point);
657 if (matched && child->HitTest(handler_callback, event, offset_point))
658 return true;
659 }
660 }
661 return false;
662 }
663
SetLayoutForTesting(int x,int y,int width,int height)664 void ViewAndroid::SetLayoutForTesting(int x, int y, int width, int height) {
665 bounds_.SetRect(x, y, width, height);
666 }
667
HasTouchlessEventHandler()668 bool ViewAndroid::HasTouchlessEventHandler() {
669 JNIEnv* env = base::android::AttachCurrentThread();
670 static bool s_has_touchless_event_handler =
671 Java_ViewAndroidDelegate_hasTouchlessEventHandler(env);
672
673 return s_has_touchless_event_handler;
674 }
675
OnUnconsumedKeyboardEventAck(int native_code)676 bool ViewAndroid::OnUnconsumedKeyboardEventAck(int native_code) {
677 if (!HasTouchlessEventHandler())
678 return false;
679
680 JNIEnv* env = base::android::AttachCurrentThread();
681
682 return Java_ViewAndroidDelegate_onUnconsumedKeyboardEventAck(env,
683 native_code);
684 }
685
FallbackCursorModeLockCursor(bool left,bool right,bool up,bool down)686 void ViewAndroid::FallbackCursorModeLockCursor(bool left,
687 bool right,
688 bool up,
689 bool down) {
690 if (!HasTouchlessEventHandler())
691 return;
692
693 JNIEnv* env = base::android::AttachCurrentThread();
694
695 Java_ViewAndroidDelegate_fallbackCursorModeLockCursor(env, left, right, up,
696 down);
697 }
698
FallbackCursorModeSetCursorVisibility(bool visible)699 void ViewAndroid::FallbackCursorModeSetCursorVisibility(bool visible) {
700 if (!HasTouchlessEventHandler())
701 return;
702
703 JNIEnv* env = base::android::AttachCurrentThread();
704
705 Java_ViewAndroidDelegate_fallbackCursorModeSetCursorVisibility(env, visible);
706 }
707
708 } // namespace ui
709