Add long running gmail memory benchmark for background tab.
[chromium-blink-merge.git] / content / browser / android / overscroll_controller_android.cc
blob8608f52a6703a8e74abecf9cb6aceb9349801407
1 // Copyright 2014 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.
5 #include "content/browser/android/overscroll_controller_android.h"
7 #include "base/android/build_info.h"
8 #include "base/command_line.h"
9 #include "cc/layers/layer.h"
10 #include "cc/output/compositor_frame_metadata.h"
11 #include "content/browser/android/content_view_core_impl.h"
12 #include "content/browser/android/edge_effect.h"
13 #include "content/browser/android/edge_effect_l.h"
14 #include "content/browser/web_contents/web_contents_impl.h"
15 #include "content/common/input/did_overscroll_params.h"
16 #include "content/public/browser/navigation_controller.h"
17 #include "content/public/browser/user_metrics.h"
18 #include "content/public/common/content_switches.h"
19 #include "third_party/WebKit/public/web/WebInputEvent.h"
20 #include "ui/android/resources/resource_manager.h"
21 #include "ui/android/window_android.h"
22 #include "ui/android/window_android_compositor.h"
23 #include "ui/base/l10n/l10n_util_android.h"
25 namespace content {
26 namespace {
28 // Used for conditional creation of EdgeEffect types for the overscroll glow.
29 const int kAndroidLSDKVersion = 21;
31 // If the glow effect alpha is greater than this value, the refresh effect will
32 // be suppressed. This value was experimentally determined to provide a
33 // reasonable balance between avoiding accidental refresh activation and
34 // minimizing the wait required to refresh after the glow has been triggered.
35 const float kMinGlowAlphaToDisableRefreshOnL = 0.085f;
37 bool IsAndroidLOrNewer() {
38 static bool android_l_or_newer =
39 base::android::BuildInfo::GetInstance()->sdk_int() >= kAndroidLSDKVersion;
40 return android_l_or_newer;
43 // Suppressing refresh detection when the glow is still animating prevents
44 // visual confusion and accidental activation after repeated scrolls.
45 float MinGlowAlphaToDisableRefresh() {
46 // Only the L effect is guaranteed to be both sufficiently brief and prominent
47 // to provide a meaningful "wait" signal. The refresh effect on previous
48 // Android releases can be quite faint, depending on the OEM-supplied
49 // overscroll resources, and lasts nearly twice as long.
50 if (IsAndroidLOrNewer())
51 return kMinGlowAlphaToDisableRefreshOnL;
53 // Any value greater than 1 effectively prevents the glow effect from ever
54 // suppressing the refresh effect.
55 return 1.01f;
58 scoped_ptr<EdgeEffectBase> CreateGlowEdgeEffect(
59 ui::ResourceManager* resource_manager,
60 float dpi_scale) {
61 DCHECK(resource_manager);
62 if (IsAndroidLOrNewer())
63 return scoped_ptr<EdgeEffectBase>(new EdgeEffectL(resource_manager));
65 return scoped_ptr<EdgeEffectBase>(
66 new EdgeEffect(resource_manager, dpi_scale));
69 scoped_ptr<OverscrollGlow> CreateGlowEffect(OverscrollGlowClient* client,
70 float dpi_scale) {
71 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
72 switches::kDisableOverscrollEdgeEffect)) {
73 return nullptr;
76 return make_scoped_ptr(new OverscrollGlow(client));
79 scoped_ptr<OverscrollRefresh> CreateRefreshEffect(
80 OverscrollRefreshHandler* handler) {
81 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
82 switches::kDisablePullToRefreshEffect)) {
83 return nullptr;
86 return make_scoped_ptr(new OverscrollRefresh(handler));
89 } // namespace
91 OverscrollControllerAndroid::OverscrollControllerAndroid(
92 ContentViewCoreImpl* content_view_core)
93 : compositor_(content_view_core->GetWindowAndroid()->GetCompositor()),
94 dpi_scale_(content_view_core->GetDpiScale()),
95 enabled_(true),
96 glow_effect_(CreateGlowEffect(this, dpi_scale_)),
97 refresh_effect_(CreateRefreshEffect(content_view_core)),
98 is_fullscreen_(false) {
99 DCHECK(compositor_);
100 // Fullscreen state is only relevant for the refresh effect.
101 if (refresh_effect_) {
102 WebContentsImpl* web_contents =
103 static_cast<WebContentsImpl*>(content_view_core->GetWebContents());
104 is_fullscreen_ = web_contents->IsFullscreenForCurrentTab();
105 Observe(web_contents);
109 OverscrollControllerAndroid::~OverscrollControllerAndroid() {
112 bool OverscrollControllerAndroid::WillHandleGestureEvent(
113 const blink::WebGestureEvent& event) {
114 if (!enabled_)
115 return false;
117 if (!refresh_effect_)
118 return false;
120 // Suppress refresh detection for fullscreen HTML5 scenarios, e.g., video.
121 if (is_fullscreen_)
122 return false;
124 // Suppress refresh detection if the glow effect is still prominent.
125 if (glow_effect_ && glow_effect_->IsActive()) {
126 if (glow_effect_->GetVisibleAlpha() > MinGlowAlphaToDisableRefresh())
127 return false;
130 bool handled = false;
131 switch (event.type) {
132 case blink::WebInputEvent::GestureScrollBegin:
133 refresh_effect_->OnScrollBegin();
134 break;
136 case blink::WebInputEvent::GestureScrollUpdate: {
137 gfx::Vector2dF scroll_delta(event.data.scrollUpdate.deltaX,
138 event.data.scrollUpdate.deltaY);
139 scroll_delta.Scale(dpi_scale_);
140 handled = refresh_effect_->WillHandleScrollUpdate(scroll_delta);
141 } break;
143 case blink::WebInputEvent::GestureScrollEnd:
144 refresh_effect_->OnScrollEnd(gfx::Vector2dF());
145 break;
147 case blink::WebInputEvent::GestureFlingStart: {
148 if (refresh_effect_->IsActive()) {
149 gfx::Vector2dF scroll_velocity(event.data.flingStart.velocityX,
150 event.data.flingStart.velocityY);
151 scroll_velocity.Scale(dpi_scale_);
152 refresh_effect_->OnScrollEnd(scroll_velocity);
153 // TODO(jdduke): Figure out a cleaner way of suppressing a fling.
154 // It's important that the any downstream code sees a scroll-ending
155 // event (in this case GestureFlingStart) if it has seen a scroll begin.
156 // Thus, we cannot simply consume the fling. Changing the event type to
157 // a GestureScrollEnd might work in practice, but could lead to
158 // unexpected results. For now, simply truncate the fling velocity, but
159 // not to zero as downstream code may not expect a zero-velocity fling.
160 blink::WebGestureEvent& modified_event =
161 const_cast<blink::WebGestureEvent&>(event);
162 modified_event.data.flingStart.velocityX = .01f;
163 modified_event.data.flingStart.velocityY = .01f;
165 } break;
167 case blink::WebInputEvent::GesturePinchBegin:
168 refresh_effect_->ReleaseWithoutActivation();
169 break;
171 default:
172 break;
175 return handled;
178 void OverscrollControllerAndroid::OnGestureEventAck(
179 const blink::WebGestureEvent& event,
180 InputEventAckState ack_result) {
181 if (!enabled_)
182 return;
184 // The overscroll effect requires an explicit release signal that may not be
185 // sent from the renderer compositor.
186 if (event.type == blink::WebInputEvent::GestureScrollEnd ||
187 event.type == blink::WebInputEvent::GestureFlingStart) {
188 OnOverscrolled(DidOverscrollParams());
191 if (event.type == blink::WebInputEvent::GestureScrollUpdate &&
192 refresh_effect_) {
193 // The effect should only be allowed if both the causal touch events go
194 // unconsumed and the generated scroll events go unconsumed.
195 bool consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED ||
196 event.data.scrollUpdate.previousUpdateInSequencePrevented;
197 refresh_effect_->OnScrollUpdateAck(consumed);
201 void OverscrollControllerAndroid::OnOverscrolled(
202 const DidOverscrollParams& params) {
203 if (!enabled_)
204 return;
206 if (refresh_effect_ && (refresh_effect_->IsActive() ||
207 refresh_effect_->IsAwaitingScrollUpdateAck())) {
208 // An active (or potentially active) refresh effect should always pre-empt
209 // the passive glow effect.
210 return;
213 if (glow_effect_ &&
214 glow_effect_->OnOverscrolled(
215 base::TimeTicks::Now(),
216 gfx::ScaleVector2d(params.accumulated_overscroll, dpi_scale_),
217 gfx::ScaleVector2d(params.latest_overscroll_delta, dpi_scale_),
218 gfx::ScaleVector2d(params.current_fling_velocity, dpi_scale_),
219 gfx::ScaleVector2d(
220 params.causal_event_viewport_point.OffsetFromOrigin(),
221 dpi_scale_))) {
222 SetNeedsAnimate();
226 bool OverscrollControllerAndroid::Animate(base::TimeTicks current_time,
227 cc::Layer* parent_layer) {
228 DCHECK(parent_layer);
229 if (!enabled_ || !glow_effect_)
230 return false;
232 return glow_effect_->Animate(current_time, parent_layer);
235 void OverscrollControllerAndroid::OnFrameMetadataUpdated(
236 const cc::CompositorFrameMetadata& frame_metadata) {
237 if (!refresh_effect_ && !glow_effect_)
238 return;
240 const float scale_factor =
241 frame_metadata.page_scale_factor * frame_metadata.device_scale_factor;
242 gfx::SizeF viewport_size =
243 gfx::ScaleSize(frame_metadata.scrollable_viewport_size, scale_factor);
244 gfx::SizeF content_size =
245 gfx::ScaleSize(frame_metadata.root_layer_size, scale_factor);
246 gfx::Vector2dF content_scroll_offset =
247 gfx::ScaleVector2d(frame_metadata.root_scroll_offset, scale_factor);
249 if (refresh_effect_) {
250 refresh_effect_->OnFrameUpdated(content_scroll_offset,
251 frame_metadata.root_overflow_y_hidden);
254 if (glow_effect_) {
255 glow_effect_->OnFrameUpdated(viewport_size, content_size,
256 content_scroll_offset);
260 void OverscrollControllerAndroid::Enable() {
261 enabled_ = true;
264 void OverscrollControllerAndroid::Disable() {
265 if (!enabled_)
266 return;
267 enabled_ = false;
268 if (!enabled_) {
269 if (refresh_effect_)
270 refresh_effect_->Reset();
271 if (glow_effect_)
272 glow_effect_->Reset();
276 void OverscrollControllerAndroid::DidToggleFullscreenModeForTab(
277 bool entered_fullscreen) {
278 DCHECK(refresh_effect_);
279 if (is_fullscreen_ == entered_fullscreen)
280 return;
281 is_fullscreen_ = entered_fullscreen;
282 if (is_fullscreen_)
283 refresh_effect_->ReleaseWithoutActivation();
286 scoped_ptr<EdgeEffectBase> OverscrollControllerAndroid::CreateEdgeEffect() {
287 return CreateGlowEdgeEffect(&compositor_->GetResourceManager(), dpi_scale_);
290 void OverscrollControllerAndroid::SetNeedsAnimate() {
291 compositor_->SetNeedsAnimate();
294 } // namespace content