Rename isSystemLocationEnabled to isLocationEnabled, as per internal review (185995).
[chromium-blink-merge.git] / content / browser / android / overscroll_controller_android.cc
blob0f161d8fdd9d4395df71efb64c03ae00cb29a032
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/edge_effect.h"
12 #include "content/browser/android/edge_effect_l.h"
13 #include "content/browser/web_contents/web_contents_impl.h"
14 #include "content/common/input/did_overscroll_params.h"
15 #include "content/public/browser/navigation_controller.h"
16 #include "content/public/common/content_switches.h"
17 #include "third_party/WebKit/public/web/WebInputEvent.h"
18 #include "ui/android/resources/resource_manager.h"
19 #include "ui/base/android/window_android_compositor.h"
21 namespace content {
22 namespace {
24 // Used for conditional creation of EdgeEffect types for the overscroll glow.
25 const int kAndroidLSDKVersion = 21;
27 // Default offset in dips from the top of the view beyond which the refresh
28 // action will be activated.
29 const int kDefaultRefreshDragTargetDips = 64;
31 scoped_ptr<EdgeEffectBase> CreateGlowEdgeEffect(
32 ui::ResourceManager* resource_manager,
33 float dpi_scale) {
34 DCHECK(resource_manager);
35 static bool use_l_flavoured_effect =
36 base::android::BuildInfo::GetInstance()->sdk_int() >= kAndroidLSDKVersion;
37 if (use_l_flavoured_effect)
38 return scoped_ptr<EdgeEffectBase>(new EdgeEffectL(resource_manager));
40 return scoped_ptr<EdgeEffectBase>(
41 new EdgeEffect(resource_manager, dpi_scale));
44 scoped_ptr<OverscrollGlow> CreateGlowEffect(OverscrollGlowClient* client,
45 float dpi_scale) {
46 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
47 switches::kDisableOverscrollEdgeEffect)) {
48 return nullptr;
51 return make_scoped_ptr(new OverscrollGlow(client));
54 scoped_ptr<OverscrollRefresh> CreateRefreshEffect(
55 ui::WindowAndroidCompositor* compositor,
56 OverscrollRefreshClient* client,
57 float dpi_scale) {
58 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
59 switches::kDisablePullToRefreshEffect)) {
60 return nullptr;
63 return make_scoped_ptr(
64 new OverscrollRefresh(&compositor->GetResourceManager(), client,
65 kDefaultRefreshDragTargetDips * dpi_scale));
68 } // namespace
70 OverscrollControllerAndroid::OverscrollControllerAndroid(
71 WebContents* web_contents,
72 ui::WindowAndroidCompositor* compositor,
73 float dpi_scale)
74 : compositor_(compositor),
75 dpi_scale_(dpi_scale),
76 enabled_(true),
77 glow_effect_(CreateGlowEffect(this, dpi_scale)),
78 refresh_effect_(CreateRefreshEffect(compositor, this, dpi_scale)),
79 triggered_refresh_active_(false),
80 is_fullscreen_(static_cast<WebContentsImpl*>(web_contents)
81 ->IsFullscreenForCurrentTab()) {
82 DCHECK(web_contents);
83 DCHECK(compositor);
84 if (refresh_effect_)
85 Observe(web_contents);
88 OverscrollControllerAndroid::~OverscrollControllerAndroid() {
91 bool OverscrollControllerAndroid::WillHandleGestureEvent(
92 const blink::WebGestureEvent& event) {
93 if (!enabled_)
94 return false;
96 // Suppress refresh detection for fullscreen web apps.
97 if (!refresh_effect_ || is_fullscreen_)
98 return false;
100 bool handled = false;
101 bool maybe_needs_animate = false;
102 switch (event.type) {
103 case blink::WebInputEvent::GestureScrollBegin:
104 refresh_effect_->OnScrollBegin();
105 break;
107 case blink::WebInputEvent::GestureScrollUpdate: {
108 gfx::Vector2dF scroll_delta(event.data.scrollUpdate.deltaX,
109 event.data.scrollUpdate.deltaY);
110 scroll_delta.Scale(dpi_scale_);
111 maybe_needs_animate = true;
112 handled = refresh_effect_->WillHandleScrollUpdate(scroll_delta);
113 } break;
115 case blink::WebInputEvent::GestureScrollEnd:
116 refresh_effect_->OnScrollEnd(gfx::Vector2dF());
117 maybe_needs_animate = true;
118 break;
120 case blink::WebInputEvent::GestureFlingStart: {
121 gfx::Vector2dF scroll_velocity(event.data.flingStart.velocityX,
122 event.data.flingStart.velocityY);
123 scroll_velocity.Scale(dpi_scale_);
124 refresh_effect_->OnScrollEnd(scroll_velocity);
125 if (refresh_effect_->IsActive()) {
126 // TODO(jdduke): Figure out a cleaner way of suppressing a fling.
127 // It's important that the any downstream code sees a scroll-ending
128 // event (in this case GestureFlingStart) if it has seen a scroll begin.
129 // Thus, we cannot simply consume the fling. Changing the event type to
130 // a GestureScrollEnd might work in practice, but could lead to
131 // unexpected results. For now, simply truncate the fling velocity, but
132 // not to zero as downstream code may not expect a zero-velocity fling.
133 blink::WebGestureEvent& modified_event =
134 const_cast<blink::WebGestureEvent&>(event);
135 modified_event.data.flingStart.velocityX = .01f;
136 modified_event.data.flingStart.velocityY = .01f;
138 maybe_needs_animate = true;
139 } break;
141 case blink::WebInputEvent::GesturePinchBegin:
142 refresh_effect_->ReleaseWithoutActivation();
143 break;
145 default:
146 break;
149 if (maybe_needs_animate && refresh_effect_->IsActive())
150 SetNeedsAnimate();
152 return handled;
155 void OverscrollControllerAndroid::OnGestureEventAck(
156 const blink::WebGestureEvent& event,
157 InputEventAckState ack_result) {
158 if (!enabled_)
159 return;
161 // The overscroll effect requires an explicit release signal that may not be
162 // sent from the renderer compositor.
163 if (event.type == blink::WebInputEvent::GestureScrollEnd ||
164 event.type == blink::WebInputEvent::GestureFlingStart) {
165 OnOverscrolled(DidOverscrollParams());
168 if (event.type == blink::WebInputEvent::GestureScrollUpdate &&
169 refresh_effect_) {
170 // The effect should only be allowed if both the causal touch events go
171 // unconsumed and the generated scroll events go unconsumed.
172 bool consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED ||
173 event.data.scrollUpdate.previousUpdateInSequencePrevented;
174 refresh_effect_->OnScrollUpdateAck(consumed);
178 void OverscrollControllerAndroid::OnOverscrolled(
179 const DidOverscrollParams& params) {
180 if (!enabled_)
181 return;
183 if (refresh_effect_ && (refresh_effect_->IsActive() ||
184 refresh_effect_->IsAwaitingScrollUpdateAck())) {
185 // An active (or potentially active) refresh effect should always pre-empt
186 // the passive glow effect.
187 return;
190 if (glow_effect_ &&
191 glow_effect_->OnOverscrolled(
192 base::TimeTicks::Now(),
193 gfx::ScaleVector2d(params.accumulated_overscroll, dpi_scale_),
194 gfx::ScaleVector2d(params.latest_overscroll_delta, dpi_scale_),
195 gfx::ScaleVector2d(params.current_fling_velocity, dpi_scale_),
196 gfx::ScaleVector2d(
197 params.causal_event_viewport_point.OffsetFromOrigin(),
198 dpi_scale_))) {
199 SetNeedsAnimate();
203 bool OverscrollControllerAndroid::Animate(base::TimeTicks current_time,
204 cc::Layer* parent_layer) {
205 DCHECK(parent_layer);
206 if (!enabled_)
207 return false;
209 bool needs_animate = false;
210 if (refresh_effect_)
211 needs_animate |= refresh_effect_->Animate(current_time, parent_layer);
212 if (glow_effect_)
213 needs_animate |= glow_effect_->Animate(current_time, parent_layer);
214 return needs_animate;
217 void OverscrollControllerAndroid::OnFrameMetadataUpdated(
218 const cc::CompositorFrameMetadata& frame_metadata) {
219 if (!refresh_effect_ && !glow_effect_)
220 return;
222 const float scale_factor =
223 frame_metadata.page_scale_factor * frame_metadata.device_scale_factor;
224 gfx::SizeF viewport_size =
225 gfx::ScaleSize(frame_metadata.scrollable_viewport_size, scale_factor);
226 gfx::SizeF content_size =
227 gfx::ScaleSize(frame_metadata.root_layer_size, scale_factor);
228 gfx::Vector2dF content_scroll_offset =
229 gfx::ScaleVector2d(frame_metadata.root_scroll_offset, scale_factor);
231 if (refresh_effect_)
232 refresh_effect_->UpdateDisplay(viewport_size, content_scroll_offset);
234 if (glow_effect_) {
235 glow_effect_->UpdateDisplay(viewport_size, content_size,
236 content_scroll_offset);
240 void OverscrollControllerAndroid::Enable() {
241 enabled_ = true;
244 void OverscrollControllerAndroid::Disable() {
245 if (!enabled_)
246 return;
247 enabled_ = false;
248 if (!enabled_) {
249 if (refresh_effect_)
250 refresh_effect_->Reset();
251 if (glow_effect_)
252 glow_effect_->Reset();
256 void OverscrollControllerAndroid::DidNavigateMainFrame(
257 const LoadCommittedDetails& details,
258 const FrameNavigateParams& params) {
259 // Once the main frame has navigated, there's little need to further animate
260 // the reload effect. Note that the effect will naturally time out should the
261 // reload be interruped for any reason.
262 triggered_refresh_active_ = false;
265 void OverscrollControllerAndroid::DidToggleFullscreenModeForTab(
266 bool entered_fullscreen) {
267 if (is_fullscreen_ == entered_fullscreen)
268 return;
269 is_fullscreen_ = entered_fullscreen;
270 if (is_fullscreen_)
271 refresh_effect_->ReleaseWithoutActivation();
274 void OverscrollControllerAndroid::TriggerRefresh() {
275 triggered_refresh_active_ = false;
276 if (!web_contents())
277 return;
279 triggered_refresh_active_ = true;
280 web_contents()->GetController().Reload(true);
283 bool OverscrollControllerAndroid::IsStillRefreshing() const {
284 return triggered_refresh_active_;
287 scoped_ptr<EdgeEffectBase> OverscrollControllerAndroid::CreateEdgeEffect() {
288 return CreateGlowEdgeEffect(&compositor_->GetResourceManager(), dpi_scale_);
291 void OverscrollControllerAndroid::SetNeedsAnimate() {
292 compositor_->SetNeedsAnimate();
295 } // namespace content