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

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: Tests! 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 "cc/layers/layer.h"
9 #include "cc/output/compositor_frame_metadata.h"
10 #include "content/browser/android/content_view_core_impl.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 "ui/base/android/window_android.h"
15 #include "ui/base/android/window_android_compositor.h"
16
17 namespace content {
18 namespace {
19
20 // Used for conditional creation of EdgeEffect types for the overscroll glow.
21 const int kAndroidLSDKVersion = 21;
22
23 ui::SystemUIResourceManager* GetSystemUIResourceManager(
24 ContentViewCore* content_view_core) {
25 ui::WindowAndroid* window = content_view_core->GetWindowAndroid();
26 DCHECK(window);
27 ui::WindowAndroidCompositor* compositor = window->GetCompositor();
28 DCHECK(compositor);
29 return &compositor->GetSystemUIResourceManager();
30 }
31
32 scoped_ptr<EdgeEffectBase> CreateGlowEdgeEffect(
33 ui::SystemUIResourceManager* resource_manager,
34 float dpi_scale) {
35 DCHECK(resource_manager);
36 static bool use_l_flavoured_effect =
37 base::android::BuildInfo::GetInstance()->sdk_int() >= kAndroidLSDKVersion;
38 if (use_l_flavoured_effect)
39 return scoped_ptr<EdgeEffectBase>(new EdgeEffectL(resource_manager));
40
41 return scoped_ptr<EdgeEffectBase>(
42 new EdgeEffect(resource_manager, dpi_scale));
43 }
44
45 } // namespace
46
47 OverscrollControllerAndroid::OverscrollControllerAndroid(
48 ContentViewCoreImpl* content_view_core)
49 : WebContentsObserver(content_view_core->GetWebContents()),
50 content_view_core_(content_view_core),
51 enabled_(true),
52 glow_effect_(base::Bind(&CreateGlowEdgeEffect,
53 GetSystemUIResourceManager(content_view_core),
54 content_view_core->GetDpiScale())),
55 refresh_effect_(GetSystemUIResourceManager(content_view_core), this),
56 triggered_refresh_active_(false) {
57 }
58
59 OverscrollControllerAndroid::~OverscrollControllerAndroid() {
60 }
61
62 bool OverscrollControllerAndroid::WillHandleGestureEvent(
63 const blink::WebGestureEvent& event) {
64 if (!enabled_)
65 return false;
66
67 bool handled = false;
68 bool maybe_needs_animate = false;
69 switch (event.type) {
70 case blink::WebInputEvent::GestureScrollBegin:
71 refresh_effect_.OnScrollBegin();
72 break;
73
74 case blink::WebInputEvent::GestureScrollUpdate: {
75 gfx::Vector2dF scroll_delta(event.data.scrollUpdate.deltaX,
76 event.data.scrollUpdate.deltaY);
77 scroll_delta.Scale(GetDpiScale());
78 maybe_needs_animate = true;
79 handled = refresh_effect_.WillHandleScrollUpdate(scroll_delta);
80 } break;
81
82 case blink::WebInputEvent::GestureScrollEnd:
83 refresh_effect_.OnScrollEnd(gfx::Vector2dF());
84 maybe_needs_animate = true;
85 break;
86
87 case blink::WebInputEvent::GestureFlingStart: {
88 gfx::Vector2dF scroll_velocity(event.data.flingStart.velocityX,
89 event.data.flingStart.velocityY);
90 scroll_velocity.Scale(GetDpiScale());
91 refresh_effect_.OnScrollEnd(scroll_velocity);
92 if (refresh_effect_.IsActive()) {
93 // TODO(jdduke): Figure out a cleaner way of suppressing a fling.
aelias_OOO_until_Jul13 2014/10/30 03:53:21 What would happen if we just let flings always go
jdduke (slow) 2014/10/30 15:19:02 That's the behavior I had originally, and it's cer
94 // It's important that the any downstream code sees a scroll-ending
95 // event (in this case GestureFlingStart) if it has seen a scroll begin.
96 // Thus, we cannot simply consume the fling. Changing the event type to
97 // a GestureScrollEnd might work in practice, but could lead to
98 // unexpected results. For now, simply truncate the fling velocity, but
99 // not to zero as downstream code may not expect a zero-velocity fling.
100 blink::WebGestureEvent& modified_event =
101 const_cast<blink::WebGestureEvent&>(event);
102 modified_event.data.flingStart.velocityX = .01f;
103 modified_event.data.flingStart.velocityY = .01f;
104 }
105 maybe_needs_animate = true;
106 } break;
107
108 default:
109 break;
110 }
111
112 if (maybe_needs_animate && refresh_effect_.IsActive())
113 content_view_core_->SetNeedsAnimate();
Ted C 2014/10/31 23:52:05 I wonder if we should just make GetRenderWidgetHos
jdduke (slow) 2014/11/06 00:10:37 Your call, don't have a strong opinion here. It's
Ted C 2014/11/06 19:25:40 I have a slight preference for exposing RWHVA. Ma
jdduke (slow) 2014/11/07 18:33:44 I did us all a favor and removed all of the Conten
114
115 return handled;
116 }
117
118 void OverscrollControllerAndroid::OnGestureEventAck(
119 const blink::WebGestureEvent& event,
120 InputEventAckState ack_result) {
121 if (!enabled_)
122 return;
123
124 if (event.type == blink::WebInputEvent::GestureScrollUpdate) {
125 bool consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
126 refresh_effect_.OnScrollUpdateAck(consumed);
127 }
128 }
129
130 void OverscrollControllerAndroid::OnOverscrolled(
131 const DidOverscrollParams& params) {
132 if (!enabled_)
133 return;
134
135 if (refresh_effect_.IsActive() ||
136 refresh_effect_.IsPendingScrollUpdateAck()) {
137 // An active (or potentially active) refresh effect should always pre-empt
138 // the passive glow effect.
139 return;
140 }
141
142 const float dpi_scale = GetDpiScale();
143 if (glow_effect_.OnOverscrolled(
144 base::TimeTicks::Now(),
145 gfx::ScaleVector2d(params.accumulated_overscroll, dpi_scale),
146 gfx::ScaleVector2d(params.latest_overscroll_delta, dpi_scale),
147 gfx::ScaleVector2d(params.current_fling_velocity, dpi_scale),
148 gfx::ScaleVector2d(
149 params.causal_event_viewport_point.OffsetFromOrigin(),
150 dpi_scale))) {
151 content_view_core_->SetNeedsAnimate();
152 }
153 }
154
155 bool OverscrollControllerAndroid::Animate(base::TimeTicks current_time) {
156 if (!enabled_)
157 return false;
158
159 scoped_refptr<cc::Layer> parent = content_view_core_->GetLayer();
160 bool needs_animate = refresh_effect_.Animate(current_time, parent.get());
161 needs_animate |= glow_effect_.Animate(current_time, parent.get());
162 return needs_animate;
163 }
164
165 void OverscrollControllerAndroid::OnFrameMetadataUpdated(
166 const cc::CompositorFrameMetadata& frame_metadata) {
167 const float scale_factor =
168 frame_metadata.page_scale_factor * frame_metadata.device_scale_factor;
169 gfx::SizeF viewport_size =
170 gfx::ScaleSize(frame_metadata.scrollable_viewport_size, scale_factor);
171 gfx::SizeF content_size =
172 gfx::ScaleSize(frame_metadata.root_layer_size, scale_factor);
173 gfx::Vector2dF content_scroll_offset =
174 gfx::ScaleVector2d(frame_metadata.root_scroll_offset, scale_factor);
175
176 refresh_effect_.UpdateDisplay(viewport_size, content_scroll_offset);
177 glow_effect_.UpdateDisplay(
178 viewport_size, content_size, content_scroll_offset);
179 }
180
181 void OverscrollControllerAndroid::Enable() {
182 enabled_ = true;
183 }
184
185 void OverscrollControllerAndroid::Disable() {
186 if (!enabled_)
187 return;
188 enabled_ = false;
189 if (!enabled_) {
190 refresh_effect_.Reset();
191 glow_effect_.Reset();
192 }
193 }
194
195 void OverscrollControllerAndroid::DidNavigateMainFrame(
196 const LoadCommittedDetails& details,
197 const FrameNavigateParams& params) {
198 // Once the main frame has navigated, there's little need to further animate
199 // the reload effect. Note that the effect will naturally time out should the
200 // reload be interruped for any reason.
201 triggered_refresh_active_ = false;
202 }
203
204 void OverscrollControllerAndroid::TriggerRefresh() {
205 triggered_refresh_active_ = false;
206 WebContents* web_contents = content_view_core_->GetWebContents();
207 if (web_contents) {
208 triggered_refresh_active_ = true;
209 web_contents->ReloadFocusedFrame(false);
210 }
211 }
212
213 bool OverscrollControllerAndroid::IsTriggeredRefreshActive() const {
214 return triggered_refresh_active_;
215 }
216
217 float OverscrollControllerAndroid::GetDpiScale() const {
218 return content_view_core_->GetDpiScale();
219 }
220
221 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698