Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(60)

Side by Side Diff: content/browser/android/overscroll_controller_android.cc

Issue 679493002: [Android] Add a native pull-to-refresh overscroll effect (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix findbugs... Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "content/browser/android/overscroll_controller_android.h"
6
7 #include "base/android/build_info.h"
8 #include "base/bind.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/common/input/did_overscroll_params.h"
14 #include "content/public/browser/web_contents.h"
15 #include "third_party/WebKit/public/web/WebInputEvent.h"
16 #include "ui/base/android/window_android_compositor.h"
17
18 namespace content {
19 namespace {
20
21 // Used for conditional creation of EdgeEffect types for the overscroll glow.
22 const int kAndroidLSDKVersion = 21;
23
24 scoped_ptr<EdgeEffectBase> CreateGlowEdgeEffect(
25 ui::SystemUIResourceManager* resource_manager,
26 float dpi_scale) {
27 DCHECK(resource_manager);
28 static bool use_l_flavoured_effect =
29 base::android::BuildInfo::GetInstance()->sdk_int() >= kAndroidLSDKVersion;
30 if (use_l_flavoured_effect)
31 return scoped_ptr<EdgeEffectBase>(new EdgeEffectL(resource_manager));
32
33 return scoped_ptr<EdgeEffectBase>(
34 new EdgeEffect(resource_manager, dpi_scale));
35 }
36
37 } // namespace
38
39 OverscrollControllerAndroid::OverscrollControllerAndroid(
40 WebContents* web_contents,
41 ui::WindowAndroidCompositor* compositor,
42 float dpi_scale)
43 : WebContentsObserver(web_contents),
44 compositor_(compositor),
45 dpi_scale_(dpi_scale),
46 enabled_(true),
47 glow_effect_(base::Bind(&CreateGlowEdgeEffect,
48 &compositor->GetSystemUIResourceManager(),
49 dpi_scale_)),
50 refresh_effect_(&compositor->GetSystemUIResourceManager(), this),
51 triggered_refresh_active_(false) {
52 DCHECK(web_contents);
53 }
54
55 OverscrollControllerAndroid::~OverscrollControllerAndroid() {
56 }
57
58 bool OverscrollControllerAndroid::WillHandleGestureEvent(
59 const blink::WebGestureEvent& event) {
60 if (!enabled_)
61 return false;
62
63 bool handled = false;
64 bool maybe_needs_animate = false;
65 switch (event.type) {
66 case blink::WebInputEvent::GestureScrollBegin:
67 refresh_effect_.OnScrollBegin();
68 break;
69
70 case blink::WebInputEvent::GestureScrollUpdate: {
71 gfx::Vector2dF scroll_delta(event.data.scrollUpdate.deltaX,
72 event.data.scrollUpdate.deltaY);
73 scroll_delta.Scale(dpi_scale_);
74 maybe_needs_animate = true;
75 handled = refresh_effect_.WillHandleScrollUpdate(scroll_delta);
76 } break;
77
78 case blink::WebInputEvent::GestureScrollEnd:
79 refresh_effect_.OnScrollEnd(gfx::Vector2dF());
80 maybe_needs_animate = true;
81 break;
82
83 case blink::WebInputEvent::GestureFlingStart: {
84 gfx::Vector2dF scroll_velocity(event.data.flingStart.velocityX,
85 event.data.flingStart.velocityY);
86 scroll_velocity.Scale(dpi_scale_);
87 refresh_effect_.OnScrollEnd(scroll_velocity);
88 if (refresh_effect_.IsActive()) {
89 // TODO(jdduke): Figure out a cleaner way of suppressing a fling.
90 // It's important that the any downstream code sees a scroll-ending
91 // event (in this case GestureFlingStart) if it has seen a scroll begin.
92 // Thus, we cannot simply consume the fling. Changing the event type to
93 // a GestureScrollEnd might work in practice, but could lead to
94 // unexpected results. For now, simply truncate the fling velocity, but
95 // not to zero as downstream code may not expect a zero-velocity fling.
96 blink::WebGestureEvent& modified_event =
97 const_cast<blink::WebGestureEvent&>(event);
98 modified_event.data.flingStart.velocityX = .01f;
99 modified_event.data.flingStart.velocityY = .01f;
100 }
101 maybe_needs_animate = true;
102 } break;
103
104 default:
105 break;
106 }
107
108 if (maybe_needs_animate && refresh_effect_.IsActive())
109 SetNeedsAnimate();
110
111 return handled;
112 }
113
114 void OverscrollControllerAndroid::OnGestureEventAck(
115 const blink::WebGestureEvent& event,
116 InputEventAckState ack_result) {
117 if (!enabled_)
118 return;
119
120 // The overscroll effect requires an explicit release signal that may not be
121 // sent from the renderer compositor.
122 if (event.type == blink::WebInputEvent::GestureScrollEnd ||
123 event.type == blink::WebInputEvent::GestureFlingStart) {
124 OnOverscrolled(DidOverscrollParams());
125 }
126
127 if (event.type == blink::WebInputEvent::GestureScrollUpdate) {
128 // The effect should only be allowed if both the causal touch events go
129 // unconsumed and the generated scroll events go unconsumed.
130 // TODO(jdduke): Prevent activation if the first touchmove was consumed,
131 // i.e., the first GSU was prevented.
132 bool consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
133 refresh_effect_.OnScrollUpdateAck(consumed);
134 }
135 }
136
137 void OverscrollControllerAndroid::OnOverscrolled(
138 const DidOverscrollParams& params) {
139 if (!enabled_)
140 return;
141
142 if (refresh_effect_.IsActive() ||
143 refresh_effect_.IsAwaitingScrollUpdateAck()) {
144 // An active (or potentially active) refresh effect should always pre-empt
145 // the passive glow effect.
146 return;
147 }
148
149 if (glow_effect_.OnOverscrolled(
150 base::TimeTicks::Now(),
151 gfx::ScaleVector2d(params.accumulated_overscroll, dpi_scale_),
152 gfx::ScaleVector2d(params.latest_overscroll_delta, dpi_scale_),
153 gfx::ScaleVector2d(params.current_fling_velocity, dpi_scale_),
154 gfx::ScaleVector2d(params.causal_event_viewport_point.OffsetFromOrigin(),
155 dpi_scale_))) {
156 SetNeedsAnimate();
157 }
158 }
159
160 bool OverscrollControllerAndroid::Animate(base::TimeTicks current_time,
161 cc::Layer* parent_layer) {
162 DCHECK(parent_layer);
163 if (!enabled_)
164 return false;
165
166 bool needs_animate = refresh_effect_.Animate(current_time, parent_layer);
167 needs_animate |= glow_effect_.Animate(current_time, parent_layer);
168 return needs_animate;
169 }
170
171 void OverscrollControllerAndroid::OnFrameMetadataUpdated(
172 const cc::CompositorFrameMetadata& frame_metadata) {
173 const float scale_factor =
174 frame_metadata.page_scale_factor * frame_metadata.device_scale_factor;
175 gfx::SizeF viewport_size =
176 gfx::ScaleSize(frame_metadata.scrollable_viewport_size, scale_factor);
177 gfx::SizeF content_size =
178 gfx::ScaleSize(frame_metadata.root_layer_size, scale_factor);
179 gfx::Vector2dF content_scroll_offset =
180 gfx::ScaleVector2d(frame_metadata.root_scroll_offset, scale_factor);
181
182 refresh_effect_.UpdateDisplay(viewport_size, content_scroll_offset);
183 glow_effect_.UpdateDisplay(viewport_size, content_size,
184 content_scroll_offset);
185 }
186
187 void OverscrollControllerAndroid::Enable() {
188 enabled_ = true;
189 }
190
191 void OverscrollControllerAndroid::Disable() {
192 if (!enabled_)
193 return;
194 enabled_ = false;
195 if (!enabled_) {
196 refresh_effect_.Reset();
197 glow_effect_.Reset();
198 }
199 }
200
201 void OverscrollControllerAndroid::DidNavigateMainFrame(
202 const LoadCommittedDetails& details,
203 const FrameNavigateParams& params) {
204 // Once the main frame has navigated, there's little need to further animate
205 // the reload effect. Note that the effect will naturally time out should the
206 // reload be interruped for any reason.
207 triggered_refresh_active_ = false;
208 }
209
210 void OverscrollControllerAndroid::TriggerRefresh() {
211 triggered_refresh_active_ = false;
212 if (!web_contents())
213 return;
214
215 triggered_refresh_active_ = true;
216 web_contents()->ReloadFocusedFrame(false);
217 }
218
219 bool OverscrollControllerAndroid::IsStillRefreshing() const {
220 return triggered_refresh_active_;
221 }
222
223 void OverscrollControllerAndroid::SetNeedsAnimate() {
224 compositor_->SetNeedsAnimate();
225 }
226
227 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/android/overscroll_controller_android.h ('k') | content/browser/android/overscroll_glow.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698