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