#ifndef UI_ANDROID_VIEW_ANDROID_H_
#define UI_ANDROID_VIEW_ANDROID_H_
#include <list>
#include <memory>
#include <optional>
#include "base/android/jni_array.h"
#include "base/android/jni_weak_ref.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "ui/android/ui_android_export.h"
#include "ui/android/view_android_observer.h"
#include "ui/gfx/geometry/rect_f.h"
namespace cc::slim {
class Layer;
}
namespace gfx {
class Point;
class Size;
}
namespace viz {
class CopyOutputRequest;
}
namespace ui {
class Cursor;
class DragEventAndroid;
class EventForwarder;
class EventHandlerAndroid;
class GestureEventAndroid;
class KeyEventAndroid;
class MotionEventAndroid;
class WindowAndroid;
class ViewAndroidObserver;
struct FrameInfo {
gfx::SizeF viewport_size;
float content_offset;
};
class UI_ANDROID_EXPORT ViewAndroid {
public:
using CopyViewCallback =
base::RepeatingCallback<void(std::unique_ptr<viz::CopyOutputRequest>)>;
using HitTestCallback = base::RepeatingCallback<bool()>;
class ScopedAnchorView {
public:
ScopedAnchorView(JNIEnv* env,
const base::android::JavaRef<jobject>& jview,
const base::android::JavaRef<jobject>& jdelegate);
ScopedAnchorView();
ScopedAnchorView(ScopedAnchorView&& other);
ScopedAnchorView& operator=(ScopedAnchorView&& other);
~ScopedAnchorView();
void Reset();
const base::android::ScopedJavaLocalRef<jobject> view() const;
private:
JavaObjectWeakGlobalRef view_;
JavaObjectWeakGlobalRef delegate_;
};
enum class LayoutType {
kNormal,
kMatchParent
};
explicit ViewAndroid(LayoutType layout_type);
ViewAndroid();
ViewAndroid(const ViewAndroid&) = delete;
ViewAndroid& operator=(const ViewAndroid&) = delete;
virtual ~ViewAndroid();
void UpdateFrameInfo(const FrameInfo& frame_info);
float content_offset() const { return frame_info_.content_offset; }
gfx::SizeF viewport_size() const { return frame_info_.viewport_size; }
virtual WindowAndroid* GetWindowAndroid() const;
virtual float GetDipScale();
cc::slim::Layer* GetLayer() const;
void SetLayer(scoped_refptr<cc::slim::Layer> layer);
void SetDelegate(const base::android::JavaRef<jobject>& delegate);
base::android::ScopedJavaLocalRef<jobject> GetEventForwarder();
void AddChild(ViewAndroid* child);
void MoveToFront(ViewAndroid* child);
void MoveToBack(ViewAndroid* child);
void RemoveFromParent();
bool HasFocus();
void RequestFocus();
bool StartDragAndDrop(const base::android::JavaRef<jobject>& jshadow_image,
const base::android::JavaRef<jobject>& jdrop_data,
jint cursor_offset_x,
jint cursor_offset_y,
jint drag_obj_rect_width,
jint drag_obj_rect_height);
gfx::Size GetPhysicalBackingSize() const;
gfx::Size GetSizeDIPs() const;
gfx::Size GetSizeDevicePx() const;
void OnSizeChanged(int width, int height);
void OnPhysicalBackingSizeChanged(
const gfx::Size& size,
std::optional<base::TimeDelta> deadline_override = std::nullopt);
void OnCursorChanged(const Cursor& cursor);
void NotifyHoverActionStylusWritable(bool stylus_writable);
void OnBackgroundColorChanged(unsigned int color);
void OnControlsChanged(float top_controls_offset,
float top_content_offset,
float top_controls_min_height_offset,
float bottom_controls_offset,
float bottom_controls_min_height_offset);
void OnBrowserControlsHeightChanged();
void OnVerticalScrollDirectionChanged(bool direction_up,
float current_scroll_ratio);
void OnControlsResizeViewChanged(bool controls_resize_view);
void DispatchWindowPositionChange();
int GetViewportInsetBottom();
ScopedAnchorView AcquireAnchorView();
void SetAnchorRect(const base::android::JavaRef<jobject>& anchor,
const gfx::RectF& bounds);
base::android::ScopedJavaLocalRef<jobject> GetContainerView();
gfx::Point GetLocationOfContainerViewInWindow();
gfx::PointF GetLocationOnScreen(float x, float y);
void AddObserver(ViewAndroidObserver* observer);
void RemoveObserver(ViewAndroidObserver* observer);
void RequestDisallowInterceptTouchEvent();
void RequestUnbufferedDispatch(const MotionEventAndroid& event);
void SetTooltip(const std::u16string& text);
void SetCopyOutputCallback(CopyViewCallback callback);
std::unique_ptr<viz::CopyOutputRequest> MaybeRequestCopyOfView(
std::unique_ptr<viz::CopyOutputRequest> request);
void SetHitTestCallback(HitTestCallback callback);
void set_event_handler(EventHandlerAndroid* handler) {
event_handler_ = handler;
}
ViewAndroid* parent() const { return parent_; }
bool OnTouchEventForTesting(const MotionEventAndroid& event) {
return OnTouchEvent(event);
}
void NotifyVirtualKeyboardOverlayRect(const gfx::Rect& keyboard_rect);
void ShowInterestInElement(int);
void SetLayoutForTesting(int x, int y, int width, int height);
EventForwarder* event_forwarder() { return event_forwarder_.get(); }
size_t GetChildrenCountForTesting() const;
const ViewAndroid* GetTopMostChildForTesting() const;
void SetIsHitTestEligible(bool is_hit_test_eligible) {
is_hit_test_eligible_ = is_hit_test_eligible;
}
bool IsCheckHitEligible() const;
protected:
void RemoveAllChildren(bool attached_to_window);
void OnPointerLockRelease();
raw_ptr<ViewAndroid> parent_;
private:
FRIEND_TEST_ALL_PREFIXES(ViewAndroidBoundsTest, MatchesViewInFront);
FRIEND_TEST_ALL_PREFIXES(ViewAndroidBoundsTest, MatchesViewArea);
FRIEND_TEST_ALL_PREFIXES(ViewAndroidBoundsTest, MatchesViewAfterMove);
FRIEND_TEST_ALL_PREFIXES(ViewAndroidBoundsTest,
MatchesViewSizeOfkMatchParent);
FRIEND_TEST_ALL_PREFIXES(ViewAndroidBoundsTest, MatchesViewsWithOffset);
FRIEND_TEST_ALL_PREFIXES(ViewAndroidBoundsTest, OnSizeChanged);
friend class EventForwarder;
friend class ViewAndroidBoundsTest;
friend class WindowAndroid;
bool OnDragEvent(const DragEventAndroid& event);
bool OnTouchEvent(const MotionEventAndroid& event);
bool OnMouseEvent(const MotionEventAndroid& event);
bool OnMouseWheelEvent(const MotionEventAndroid& event);
bool OnGestureEvent(const GestureEventAndroid& event);
bool OnGenericMotionEvent(const MotionEventAndroid& event);
bool OnKeyUp(const KeyEventAndroid& event);
bool DispatchKeyEvent(const KeyEventAndroid& event);
bool ScrollBy(float delta_x, float delta_y);
bool ScrollTo(float x, float y);
void RemoveChild(ViewAndroid* child);
void OnAttachedToWindow();
void OnDetachedFromWindow();
template <typename E>
using EventHandlerCallback =
const base::RepeatingCallback<bool(EventHandlerAndroid*, const E&)>;
template <typename E>
bool HitTest(EventHandlerCallback<E> handler_callback,
const E& event,
const gfx::PointF& point);
static bool SendDragEventToHandler(EventHandlerAndroid* handler,
const DragEventAndroid& event);
static bool SendTouchEventToHandler(EventHandlerAndroid* handler,
const MotionEventAndroid& event);
static bool SendMouseEventToHandler(EventHandlerAndroid* handler,
const MotionEventAndroid& event);
static bool SendMouseWheelEventToHandler(EventHandlerAndroid* handler,
const MotionEventAndroid& event);
static bool SendGestureEventToHandler(EventHandlerAndroid* handler,
const GestureEventAndroid& event);
bool has_event_forwarder() const { return !!event_forwarder_; }
bool match_parent() const { return layout_type_ == LayoutType::kMatchParent; }
static bool RootPathHasEventForwarder(ViewAndroid* view);
static bool SubtreeHasEventForwarder(ViewAndroid* view);
void OnSizeChangedInternal(const gfx::Size& size_device_px);
void DispatchOnSizeChanged();
const base::android::ScopedJavaLocalRef<jobject> GetViewAndroidDelegate()
const;
std::list<raw_ptr<ViewAndroid, CtnExperimental>> children_;
base::ObserverList<ViewAndroidObserver>::Unchecked observer_list_;
scoped_refptr<cc::slim::Layer> layer_;
JavaObjectWeakGlobalRef delegate_;
raw_ptr<EventHandlerAndroid> event_handler_ = nullptr;
gfx::Rect bounds_dips_;
gfx::Rect bounds_device_px_;
const LayoutType layout_type_;
gfx::Size physical_size_;
FrameInfo frame_info_;
std::unique_ptr<EventForwarder> event_forwarder_;
CopyViewCallback copy_view_callback_;
HitTestCallback hit_test_callback_;
bool controls_resize_view_ = false;
bool is_hit_test_eligible_ = false;
};
}
#endif