1 // Copyright 2019 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 "weblayer/browser/browser_controls_container_view.h"
6
7 #include "base/android/jni_string.h"
8 #include "base/bind.h"
9 #include "base/feature_list.h"
10 #include "cc/layers/ui_resource_layer.h"
11 #include "content/public/browser/android/compositor.h"
12 #include "content/public/browser/render_view_host.h"
13 #include "content/public/browser/render_widget_host.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/common/browser_controls_state.h"
16 #include "ui/android/resources/resource.h"
17 #include "ui/android/resources/resource_manager.h"
18 #include "ui/android/view_android.h"
19 #include "weblayer/browser/content_view_render_view.h"
20 #include "weblayer/browser/java/jni/BrowserControlsContainerView_jni.h"
21 #include "weblayer/browser/weblayer_features.h"
22
23 using base::android::AttachCurrentThread;
24 using base::android::JavaParamRef;
25
26 namespace weblayer {
27
BrowserControlsContainerView(const JavaParamRef<jobject> & java_browser_controls_container_view,ContentViewRenderView * content_view_render_view,bool is_top)28 BrowserControlsContainerView::BrowserControlsContainerView(
29 const JavaParamRef<jobject>& java_browser_controls_container_view,
30 ContentViewRenderView* content_view_render_view,
31 bool is_top)
32 : java_browser_controls_container_view_(
33 java_browser_controls_container_view),
34 content_view_render_view_(content_view_render_view),
35 is_top_(is_top) {
36 DCHECK(content_view_render_view_);
37 if (!is_top_) {
38 content_view_render_view_->SetHeightChangedListener(
39 base::BindRepeating(&BrowserControlsContainerView::ContentHeightChanged,
40 base::Unretained(this)));
41 }
42 }
43
~BrowserControlsContainerView()44 BrowserControlsContainerView::~BrowserControlsContainerView() {
45 if (!is_top_) {
46 content_view_render_view_->SetHeightChangedListener(
47 base::RepeatingClosure());
48 }
49 }
50
GetControlsHeight()51 int BrowserControlsContainerView::GetControlsHeight() {
52 return controls_layer_ ? controls_layer_->bounds().height() : 0;
53 }
54
GetMinHeight()55 int BrowserControlsContainerView::GetMinHeight() {
56 return Java_BrowserControlsContainerView_getMinHeight(
57 AttachCurrentThread(), java_browser_controls_container_view_);
58 }
59
OnlyExpandControlsAtPageTop()60 bool BrowserControlsContainerView::OnlyExpandControlsAtPageTop() {
61 return Java_BrowserControlsContainerView_onlyExpandControlsAtPageTop(
62 AttachCurrentThread(), java_browser_controls_container_view_);
63 }
64
ShouldAnimateBrowserControlsHeightChanges()65 bool BrowserControlsContainerView::ShouldAnimateBrowserControlsHeightChanges() {
66 return Java_BrowserControlsContainerView_shouldAnimateBrowserControlsHeightChanges(
67 AttachCurrentThread(), java_browser_controls_container_view_);
68 }
69
GetContentHeightDelta()70 int BrowserControlsContainerView::GetContentHeightDelta() {
71 if (!controls_layer_ || !web_contents())
72 return 0;
73
74 if (is_top_)
75 return web_contents()->GetNativeView()->GetLayer()->position().y();
76
77 return content_view_render_view_->height() - controls_layer_->position().y();
78 }
79
IsFullyVisible() const80 bool BrowserControlsContainerView::IsFullyVisible() const {
81 // At this time this is only needed for top-controls.
82 DCHECK(is_top_);
83 return controls_layer_ && controls_layer_->position().y() == 0;
84 }
85
CreateControlsLayer(JNIEnv * env,int id)86 void BrowserControlsContainerView::CreateControlsLayer(
87 JNIEnv* env,
88 int id) {
89 controls_resource_id_ = id;
90 controls_layer_ = cc::UIResourceLayer::Create();
91 // Real size is sent in SetControlsSize().
92 controls_layer_->SetBounds(gfx::Size(1, 1));
93 controls_layer_->SetPosition(gfx::PointF(0, 0));
94 controls_layer_->SetElementId(cc::ElementId(controls_layer_->id()));
95 controls_layer_->SetHitTestable(false);
96 controls_layer_->SetIsDrawable(true);
97 content_view_render_view_->root_container_layer()->AddChild(controls_layer_);
98 UpdateControlsResource(env);
99 }
100
DeleteBrowserControlsContainerView(JNIEnv * env)101 void BrowserControlsContainerView::DeleteBrowserControlsContainerView(
102 JNIEnv* env) {
103 delete this;
104 }
105
DeleteControlsLayer(JNIEnv * env)106 void BrowserControlsContainerView::DeleteControlsLayer(JNIEnv* env) {
107 controls_layer_.reset();
108 }
109
SetTopControlsOffset(JNIEnv * env,int content_offset_y)110 void BrowserControlsContainerView::SetTopControlsOffset(JNIEnv* env,
111 int content_offset_y) {
112 DCHECK(is_top_);
113 // |controls_layer_| may not be created if the controls view has 0 height.
114 if (controls_layer_)
115 controls_layer_->SetPosition(gfx::PointF(0, GetControlsOffset()));
116 if (web_contents()) {
117 web_contents()->GetNativeView()->GetLayer()->SetPosition(
118 gfx::PointF(0, content_offset_y));
119 }
120 }
121
SetBottomControlsOffset(JNIEnv * env)122 void BrowserControlsContainerView::SetBottomControlsOffset(JNIEnv* env) {
123 DCHECK(!is_top_);
124 DoSetBottomControlsOffset();
125 }
126
SetControlsSize(JNIEnv * env,int width,int height)127 void BrowserControlsContainerView::SetControlsSize(
128 JNIEnv* env,
129 int width,
130 int height) {
131 DCHECK(controls_layer_);
132 controls_layer_->SetBounds(gfx::Size(width, height));
133 // It's assumed the caller handles triggering SynchronizeVisualProperties()
134 // being called (this is done in java code).
135 }
136
UpdateControlsResource(JNIEnv * env)137 void BrowserControlsContainerView::UpdateControlsResource(JNIEnv* env) {
138 DCHECK(controls_layer_);
139 ui::ResourceManager& resource_manager =
140 content_view_render_view_->compositor()->GetResourceManager();
141 ui::Resource* controls_resource = resource_manager.GetResource(
142 ui::ANDROID_RESOURCE_TYPE_DYNAMIC, controls_resource_id_);
143 DCHECK(controls_resource);
144 controls_layer_->SetUIResourceId(controls_resource->ui_resource()->id());
145 }
146
SetWebContents(JNIEnv * env,const JavaParamRef<jobject> & web_contents)147 void BrowserControlsContainerView::SetWebContents(
148 JNIEnv* env,
149 const JavaParamRef<jobject>& web_contents) {
150 Observe(content::WebContents::FromJavaWebContents(web_contents));
151 }
152
DidToggleFullscreenModeForTab(bool entered_fullscreen,bool will_cause_resize)153 void BrowserControlsContainerView::DidToggleFullscreenModeForTab(
154 bool entered_fullscreen,
155 bool will_cause_resize) {
156 TRACE_EVENT0(
157 "weblayer",
158 "Java_BrowserControlsContainerView_didToggleFullscreenModeForTab");
159 Java_BrowserControlsContainerView_didToggleFullscreenModeForTab(
160 AttachCurrentThread(), java_browser_controls_container_view_,
161 entered_fullscreen);
162 }
163
ContentHeightChanged()164 void BrowserControlsContainerView::ContentHeightChanged() {
165 DCHECK(!is_top_);
166 DoSetBottomControlsOffset();
167 }
168
GetControlsOffset()169 int BrowserControlsContainerView::GetControlsOffset() {
170 return Java_BrowserControlsContainerView_getControlsOffset(
171 AttachCurrentThread(), java_browser_controls_container_view_);
172 }
173
DoSetBottomControlsOffset()174 void BrowserControlsContainerView::DoSetBottomControlsOffset() {
175 DCHECK(!is_top_);
176 // |controls_layer_| may not be created if the controls view has 0 height.
177 if (!controls_layer_)
178 return;
179 controls_layer_->SetPosition(
180 gfx::PointF(0, content_view_render_view_->height() - GetControlsHeight() +
181 GetControlsOffset()));
182 }
183
184 static jlong
JNI_BrowserControlsContainerView_CreateBrowserControlsContainerView(JNIEnv * env,const JavaParamRef<jobject> & java_browser_controls_container_view,jlong native_content_view_render_view,jboolean is_top)185 JNI_BrowserControlsContainerView_CreateBrowserControlsContainerView(
186 JNIEnv* env,
187 const JavaParamRef<jobject>& java_browser_controls_container_view,
188 jlong native_content_view_render_view,
189 jboolean is_top) {
190 return reinterpret_cast<jlong>(new BrowserControlsContainerView(
191 java_browser_controls_container_view,
192 reinterpret_cast<ContentViewRenderView*>(native_content_view_render_view),
193 is_top));
194 }
195
JNI_BrowserControlsContainerView_ShouldDelayVisibilityChange(JNIEnv * env)196 static jboolean JNI_BrowserControlsContainerView_ShouldDelayVisibilityChange(
197 JNIEnv* env) {
198 return !base::FeatureList::IsEnabled(kImmediatelyHideBrowserControlsForTest);
199 }
200
201 } // namespace weblayer
202