OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/android/overscroll_controller_android.h" | 5 #include "content/browser/android/overscroll_controller_android.h" |
6 | 6 |
7 #include "base/android/build_info.h" | 7 #include "base/android/build_info.h" |
8 #include "base/bind.h" | 8 #include "base/command_line.h" |
9 #include "cc/layers/layer.h" | 9 #include "cc/layers/layer.h" |
10 #include "cc/output/compositor_frame_metadata.h" | 10 #include "cc/output/compositor_frame_metadata.h" |
11 #include "content/browser/android/edge_effect.h" | 11 #include "content/browser/android/edge_effect.h" |
12 #include "content/browser/android/edge_effect_l.h" | 12 #include "content/browser/android/edge_effect_l.h" |
13 #include "content/common/input/did_overscroll_params.h" | 13 #include "content/common/input/did_overscroll_params.h" |
14 #include "content/public/browser/web_contents.h" | 14 #include "content/public/browser/web_contents.h" |
| 15 #include "content/public/common/content_switches.h" |
15 #include "third_party/WebKit/public/web/WebInputEvent.h" | 16 #include "third_party/WebKit/public/web/WebInputEvent.h" |
16 #include "ui/base/android/window_android_compositor.h" | 17 #include "ui/base/android/window_android_compositor.h" |
17 | 18 |
18 namespace content { | 19 namespace content { |
19 namespace { | 20 namespace { |
20 | 21 |
21 // Used for conditional creation of EdgeEffect types for the overscroll glow. | 22 // Used for conditional creation of EdgeEffect types for the overscroll glow. |
22 const int kAndroidLSDKVersion = 21; | 23 const int kAndroidLSDKVersion = 21; |
23 | 24 |
24 // Default offset in dips from the top of the view beyond which the refresh | 25 // Default offset in dips from the top of the view beyond which the refresh |
25 // action will be activated. | 26 // action will be activated. |
26 const int kDefaultRefreshDragTargetDips = 64; | 27 const int kDefaultRefreshDragTargetDips = 64; |
27 | 28 |
28 scoped_ptr<EdgeEffectBase> CreateGlowEdgeEffect( | 29 scoped_ptr<EdgeEffectBase> CreateGlowEdgeEffect( |
29 ui::SystemUIResourceManager* resource_manager, | 30 ui::SystemUIResourceManager* resource_manager, |
30 float dpi_scale) { | 31 float dpi_scale) { |
31 DCHECK(resource_manager); | 32 DCHECK(resource_manager); |
32 static bool use_l_flavoured_effect = | 33 static bool use_l_flavoured_effect = |
33 base::android::BuildInfo::GetInstance()->sdk_int() >= kAndroidLSDKVersion; | 34 base::android::BuildInfo::GetInstance()->sdk_int() >= kAndroidLSDKVersion; |
34 if (use_l_flavoured_effect) | 35 if (use_l_flavoured_effect) |
35 return scoped_ptr<EdgeEffectBase>(new EdgeEffectL(resource_manager)); | 36 return scoped_ptr<EdgeEffectBase>(new EdgeEffectL(resource_manager)); |
36 | 37 |
37 return scoped_ptr<EdgeEffectBase>( | 38 return scoped_ptr<EdgeEffectBase>( |
38 new EdgeEffect(resource_manager, dpi_scale)); | 39 new EdgeEffect(resource_manager, dpi_scale)); |
39 } | 40 } |
40 | 41 |
| 42 scoped_ptr<OverscrollGlow> CreateGlowEffect(OverscrollGlowClient* client, |
| 43 float dpi_scale) { |
| 44 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 45 switches::kDisableOverscrollEdgeEffect)) { |
| 46 return nullptr; |
| 47 } |
| 48 |
| 49 return make_scoped_ptr(new OverscrollGlow(client)); |
| 50 } |
| 51 |
| 52 scoped_ptr<OverscrollRefresh> CreateRefreshEffect( |
| 53 ui::WindowAndroidCompositor* compositor, |
| 54 OverscrollRefreshClient* client, |
| 55 float dpi_scale) { |
| 56 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 57 switches::kDisablePullToRefreshEffect)) { |
| 58 return nullptr; |
| 59 } |
| 60 |
| 61 return make_scoped_ptr( |
| 62 new OverscrollRefresh(&compositor->GetSystemUIResourceManager(), client, |
| 63 kDefaultRefreshDragTargetDips * dpi_scale)); |
| 64 } |
| 65 |
41 } // namespace | 66 } // namespace |
42 | 67 |
43 OverscrollControllerAndroid::OverscrollControllerAndroid( | 68 OverscrollControllerAndroid::OverscrollControllerAndroid( |
44 WebContents* web_contents, | 69 WebContents* web_contents, |
45 ui::WindowAndroidCompositor* compositor, | 70 ui::WindowAndroidCompositor* compositor, |
46 float dpi_scale) | 71 float dpi_scale) |
47 : WebContentsObserver(web_contents), | 72 : compositor_(compositor), |
48 compositor_(compositor), | |
49 dpi_scale_(dpi_scale), | 73 dpi_scale_(dpi_scale), |
50 enabled_(true), | 74 enabled_(true), |
51 glow_effect_(base::Bind(&CreateGlowEdgeEffect, | 75 glow_effect_(CreateGlowEffect(this, dpi_scale)), |
52 &compositor->GetSystemUIResourceManager(), | 76 refresh_effect_(CreateRefreshEffect(compositor, this, dpi_scale)), |
53 dpi_scale_)), | |
54 refresh_effect_(&compositor->GetSystemUIResourceManager(), | |
55 this, | |
56 kDefaultRefreshDragTargetDips * dpi_scale), | |
57 triggered_refresh_active_(false) { | 77 triggered_refresh_active_(false) { |
58 DCHECK(web_contents); | 78 DCHECK(web_contents); |
| 79 DCHECK(compositor); |
| 80 if (refresh_effect_) |
| 81 Observe(web_contents); |
59 } | 82 } |
60 | 83 |
61 OverscrollControllerAndroid::~OverscrollControllerAndroid() { | 84 OverscrollControllerAndroid::~OverscrollControllerAndroid() { |
62 } | 85 } |
63 | 86 |
64 bool OverscrollControllerAndroid::WillHandleGestureEvent( | 87 bool OverscrollControllerAndroid::WillHandleGestureEvent( |
65 const blink::WebGestureEvent& event) { | 88 const blink::WebGestureEvent& event) { |
66 if (!enabled_) | 89 if (!enabled_) |
67 return false; | 90 return false; |
68 | 91 |
| 92 if (!refresh_effect_) |
| 93 return false; |
| 94 |
69 bool handled = false; | 95 bool handled = false; |
70 bool maybe_needs_animate = false; | 96 bool maybe_needs_animate = false; |
71 switch (event.type) { | 97 switch (event.type) { |
72 case blink::WebInputEvent::GestureScrollBegin: | 98 case blink::WebInputEvent::GestureScrollBegin: |
73 refresh_effect_.OnScrollBegin(); | 99 refresh_effect_->OnScrollBegin(); |
74 break; | 100 break; |
75 | 101 |
76 case blink::WebInputEvent::GestureScrollUpdate: { | 102 case blink::WebInputEvent::GestureScrollUpdate: { |
77 gfx::Vector2dF scroll_delta(event.data.scrollUpdate.deltaX, | 103 gfx::Vector2dF scroll_delta(event.data.scrollUpdate.deltaX, |
78 event.data.scrollUpdate.deltaY); | 104 event.data.scrollUpdate.deltaY); |
79 scroll_delta.Scale(dpi_scale_); | 105 scroll_delta.Scale(dpi_scale_); |
80 maybe_needs_animate = true; | 106 maybe_needs_animate = true; |
81 handled = refresh_effect_.WillHandleScrollUpdate(scroll_delta); | 107 handled = refresh_effect_->WillHandleScrollUpdate(scroll_delta); |
82 } break; | 108 } break; |
83 | 109 |
84 case blink::WebInputEvent::GestureScrollEnd: | 110 case blink::WebInputEvent::GestureScrollEnd: |
85 refresh_effect_.OnScrollEnd(gfx::Vector2dF()); | 111 refresh_effect_->OnScrollEnd(gfx::Vector2dF()); |
86 maybe_needs_animate = true; | 112 maybe_needs_animate = true; |
87 break; | 113 break; |
88 | 114 |
89 case blink::WebInputEvent::GestureFlingStart: { | 115 case blink::WebInputEvent::GestureFlingStart: { |
90 gfx::Vector2dF scroll_velocity(event.data.flingStart.velocityX, | 116 gfx::Vector2dF scroll_velocity(event.data.flingStart.velocityX, |
91 event.data.flingStart.velocityY); | 117 event.data.flingStart.velocityY); |
92 scroll_velocity.Scale(dpi_scale_); | 118 scroll_velocity.Scale(dpi_scale_); |
93 refresh_effect_.OnScrollEnd(scroll_velocity); | 119 refresh_effect_->OnScrollEnd(scroll_velocity); |
94 if (refresh_effect_.IsActive()) { | 120 if (refresh_effect_->IsActive()) { |
95 // TODO(jdduke): Figure out a cleaner way of suppressing a fling. | 121 // TODO(jdduke): Figure out a cleaner way of suppressing a fling. |
96 // It's important that the any downstream code sees a scroll-ending | 122 // It's important that the any downstream code sees a scroll-ending |
97 // event (in this case GestureFlingStart) if it has seen a scroll begin. | 123 // event (in this case GestureFlingStart) if it has seen a scroll begin. |
98 // Thus, we cannot simply consume the fling. Changing the event type to | 124 // Thus, we cannot simply consume the fling. Changing the event type to |
99 // a GestureScrollEnd might work in practice, but could lead to | 125 // a GestureScrollEnd might work in practice, but could lead to |
100 // unexpected results. For now, simply truncate the fling velocity, but | 126 // unexpected results. For now, simply truncate the fling velocity, but |
101 // not to zero as downstream code may not expect a zero-velocity fling. | 127 // not to zero as downstream code may not expect a zero-velocity fling. |
102 blink::WebGestureEvent& modified_event = | 128 blink::WebGestureEvent& modified_event = |
103 const_cast<blink::WebGestureEvent&>(event); | 129 const_cast<blink::WebGestureEvent&>(event); |
104 modified_event.data.flingStart.velocityX = .01f; | 130 modified_event.data.flingStart.velocityX = .01f; |
105 modified_event.data.flingStart.velocityY = .01f; | 131 modified_event.data.flingStart.velocityY = .01f; |
106 } | 132 } |
107 maybe_needs_animate = true; | 133 maybe_needs_animate = true; |
108 } break; | 134 } break; |
109 | 135 |
110 default: | 136 default: |
111 break; | 137 break; |
112 } | 138 } |
113 | 139 |
114 if (maybe_needs_animate && refresh_effect_.IsActive()) | 140 if (maybe_needs_animate && refresh_effect_->IsActive()) |
115 SetNeedsAnimate(); | 141 SetNeedsAnimate(); |
116 | 142 |
117 return handled; | 143 return handled; |
118 } | 144 } |
119 | 145 |
120 void OverscrollControllerAndroid::OnGestureEventAck( | 146 void OverscrollControllerAndroid::OnGestureEventAck( |
121 const blink::WebGestureEvent& event, | 147 const blink::WebGestureEvent& event, |
122 InputEventAckState ack_result) { | 148 InputEventAckState ack_result) { |
123 if (!enabled_) | 149 if (!enabled_) |
124 return; | 150 return; |
125 | 151 |
126 // The overscroll effect requires an explicit release signal that may not be | 152 // The overscroll effect requires an explicit release signal that may not be |
127 // sent from the renderer compositor. | 153 // sent from the renderer compositor. |
128 if (event.type == blink::WebInputEvent::GestureScrollEnd || | 154 if (event.type == blink::WebInputEvent::GestureScrollEnd || |
129 event.type == blink::WebInputEvent::GestureFlingStart) { | 155 event.type == blink::WebInputEvent::GestureFlingStart) { |
130 OnOverscrolled(DidOverscrollParams()); | 156 OnOverscrolled(DidOverscrollParams()); |
131 } | 157 } |
132 | 158 |
133 if (event.type == blink::WebInputEvent::GestureScrollUpdate) { | 159 if (event.type == blink::WebInputEvent::GestureScrollUpdate && |
| 160 refresh_effect_) { |
134 // The effect should only be allowed if both the causal touch events go | 161 // The effect should only be allowed if both the causal touch events go |
135 // unconsumed and the generated scroll events go unconsumed. | 162 // unconsumed and the generated scroll events go unconsumed. |
136 bool consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED || | 163 bool consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED || |
137 event.data.scrollUpdate.previousUpdateInSequencePrevented; | 164 event.data.scrollUpdate.previousUpdateInSequencePrevented; |
138 refresh_effect_.OnScrollUpdateAck(consumed); | 165 refresh_effect_->OnScrollUpdateAck(consumed); |
139 } | 166 } |
140 } | 167 } |
141 | 168 |
142 void OverscrollControllerAndroid::OnOverscrolled( | 169 void OverscrollControllerAndroid::OnOverscrolled( |
143 const DidOverscrollParams& params) { | 170 const DidOverscrollParams& params) { |
144 if (!enabled_) | 171 if (!enabled_) |
145 return; | 172 return; |
146 | 173 |
147 if (refresh_effect_.IsActive() || | 174 if (refresh_effect_ && (refresh_effect_->IsActive() || |
148 refresh_effect_.IsAwaitingScrollUpdateAck()) { | 175 refresh_effect_->IsAwaitingScrollUpdateAck())) { |
149 // An active (or potentially active) refresh effect should always pre-empt | 176 // An active (or potentially active) refresh effect should always pre-empt |
150 // the passive glow effect. | 177 // the passive glow effect. |
151 return; | 178 return; |
152 } | 179 } |
153 | 180 |
154 if (glow_effect_.OnOverscrolled( | 181 if (glow_effect_ && |
155 base::TimeTicks::Now(), | 182 glow_effect_->OnOverscrolled( |
156 gfx::ScaleVector2d(params.accumulated_overscroll, dpi_scale_), | 183 base::TimeTicks::Now(), |
157 gfx::ScaleVector2d(params.latest_overscroll_delta, dpi_scale_), | 184 gfx::ScaleVector2d(params.accumulated_overscroll, dpi_scale_), |
158 gfx::ScaleVector2d(params.current_fling_velocity, dpi_scale_), | 185 gfx::ScaleVector2d(params.latest_overscroll_delta, dpi_scale_), |
159 gfx::ScaleVector2d(params.causal_event_viewport_point.OffsetFromOrigin(), | 186 gfx::ScaleVector2d(params.current_fling_velocity, dpi_scale_), |
160 dpi_scale_))) { | 187 gfx::ScaleVector2d( |
| 188 params.causal_event_viewport_point.OffsetFromOrigin(), |
| 189 dpi_scale_))) { |
161 SetNeedsAnimate(); | 190 SetNeedsAnimate(); |
162 } | 191 } |
163 } | 192 } |
164 | 193 |
165 bool OverscrollControllerAndroid::Animate(base::TimeTicks current_time, | 194 bool OverscrollControllerAndroid::Animate(base::TimeTicks current_time, |
166 cc::Layer* parent_layer) { | 195 cc::Layer* parent_layer) { |
167 DCHECK(parent_layer); | 196 DCHECK(parent_layer); |
168 if (!enabled_) | 197 if (!enabled_) |
169 return false; | 198 return false; |
170 | 199 |
171 bool needs_animate = refresh_effect_.Animate(current_time, parent_layer); | 200 bool needs_animate = false; |
172 needs_animate |= glow_effect_.Animate(current_time, parent_layer); | 201 if (refresh_effect_) |
| 202 needs_animate |= refresh_effect_->Animate(current_time, parent_layer); |
| 203 if (glow_effect_) |
| 204 needs_animate |= glow_effect_->Animate(current_time, parent_layer); |
173 return needs_animate; | 205 return needs_animate; |
174 } | 206 } |
175 | 207 |
176 void OverscrollControllerAndroid::OnFrameMetadataUpdated( | 208 void OverscrollControllerAndroid::OnFrameMetadataUpdated( |
177 const cc::CompositorFrameMetadata& frame_metadata) { | 209 const cc::CompositorFrameMetadata& frame_metadata) { |
| 210 if (!refresh_effect_ && !glow_effect_) |
| 211 return; |
| 212 |
178 const float scale_factor = | 213 const float scale_factor = |
179 frame_metadata.page_scale_factor * frame_metadata.device_scale_factor; | 214 frame_metadata.page_scale_factor * frame_metadata.device_scale_factor; |
180 gfx::SizeF viewport_size = | 215 gfx::SizeF viewport_size = |
181 gfx::ScaleSize(frame_metadata.scrollable_viewport_size, scale_factor); | 216 gfx::ScaleSize(frame_metadata.scrollable_viewport_size, scale_factor); |
182 gfx::SizeF content_size = | 217 gfx::SizeF content_size = |
183 gfx::ScaleSize(frame_metadata.root_layer_size, scale_factor); | 218 gfx::ScaleSize(frame_metadata.root_layer_size, scale_factor); |
184 gfx::Vector2dF content_scroll_offset = | 219 gfx::Vector2dF content_scroll_offset = |
185 gfx::ScaleVector2d(frame_metadata.root_scroll_offset, scale_factor); | 220 gfx::ScaleVector2d(frame_metadata.root_scroll_offset, scale_factor); |
186 | 221 |
187 refresh_effect_.UpdateDisplay(viewport_size, content_scroll_offset); | 222 if (refresh_effect_) |
188 glow_effect_.UpdateDisplay(viewport_size, content_size, | 223 refresh_effect_->UpdateDisplay(viewport_size, content_scroll_offset); |
189 content_scroll_offset); | 224 |
| 225 if (glow_effect_) { |
| 226 glow_effect_->UpdateDisplay(viewport_size, content_size, |
| 227 content_scroll_offset); |
| 228 } |
190 } | 229 } |
191 | 230 |
192 void OverscrollControllerAndroid::Enable() { | 231 void OverscrollControllerAndroid::Enable() { |
193 enabled_ = true; | 232 enabled_ = true; |
194 } | 233 } |
195 | 234 |
196 void OverscrollControllerAndroid::Disable() { | 235 void OverscrollControllerAndroid::Disable() { |
197 if (!enabled_) | 236 if (!enabled_) |
198 return; | 237 return; |
199 enabled_ = false; | 238 enabled_ = false; |
200 if (!enabled_) { | 239 if (!enabled_) { |
201 refresh_effect_.Reset(); | 240 if (refresh_effect_) |
202 glow_effect_.Reset(); | 241 refresh_effect_->Reset(); |
| 242 if (glow_effect_) |
| 243 glow_effect_->Reset(); |
203 } | 244 } |
204 } | 245 } |
205 | 246 |
206 void OverscrollControllerAndroid::DidNavigateMainFrame( | 247 void OverscrollControllerAndroid::DidNavigateMainFrame( |
207 const LoadCommittedDetails& details, | 248 const LoadCommittedDetails& details, |
208 const FrameNavigateParams& params) { | 249 const FrameNavigateParams& params) { |
209 // Once the main frame has navigated, there's little need to further animate | 250 // Once the main frame has navigated, there's little need to further animate |
210 // the reload effect. Note that the effect will naturally time out should the | 251 // the reload effect. Note that the effect will naturally time out should the |
211 // reload be interruped for any reason. | 252 // reload be interruped for any reason. |
212 triggered_refresh_active_ = false; | 253 triggered_refresh_active_ = false; |
213 } | 254 } |
214 | 255 |
215 void OverscrollControllerAndroid::TriggerRefresh() { | 256 void OverscrollControllerAndroid::TriggerRefresh() { |
216 triggered_refresh_active_ = false; | 257 triggered_refresh_active_ = false; |
217 if (!web_contents()) | 258 if (!web_contents()) |
218 return; | 259 return; |
219 | 260 |
220 triggered_refresh_active_ = true; | 261 triggered_refresh_active_ = true; |
221 web_contents()->ReloadFocusedFrame(false); | 262 web_contents()->ReloadFocusedFrame(false); |
222 } | 263 } |
223 | 264 |
224 bool OverscrollControllerAndroid::IsStillRefreshing() const { | 265 bool OverscrollControllerAndroid::IsStillRefreshing() const { |
225 return triggered_refresh_active_; | 266 return triggered_refresh_active_; |
226 } | 267 } |
227 | 268 |
| 269 scoped_ptr<EdgeEffectBase> OverscrollControllerAndroid::CreateEdgeEffect() { |
| 270 return CreateGlowEdgeEffect(&compositor_->GetSystemUIResourceManager(), |
| 271 dpi_scale_); |
| 272 } |
| 273 |
228 void OverscrollControllerAndroid::SetNeedsAnimate() { | 274 void OverscrollControllerAndroid::SetNeedsAnimate() { |
229 compositor_->SetNeedsAnimate(); | 275 compositor_->SetNeedsAnimate(); |
230 } | 276 } |
231 | 277 |
232 } // namespace content | 278 } // namespace content |
OLD | NEW |