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/command_line.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/content_view_core_impl.h" |
11 #include "content/browser/android/edge_effect.h" | 12 #include "content/browser/android/edge_effect.h" |
12 #include "content/browser/android/edge_effect_l.h" | 13 #include "content/browser/android/edge_effect_l.h" |
13 #include "content/browser/web_contents/web_contents_impl.h" | 14 #include "content/browser/web_contents/web_contents_impl.h" |
14 #include "content/common/input/did_overscroll_params.h" | 15 #include "content/common/input/did_overscroll_params.h" |
15 #include "content/public/browser/navigation_controller.h" | 16 #include "content/public/browser/navigation_controller.h" |
16 #include "content/public/browser/user_metrics.h" | 17 #include "content/public/browser/user_metrics.h" |
17 #include "content/public/common/content_switches.h" | 18 #include "content/public/common/content_switches.h" |
18 #include "third_party/WebKit/public/web/WebInputEvent.h" | 19 #include "third_party/WebKit/public/web/WebInputEvent.h" |
19 #include "ui/android/resources/resource_manager.h" | 20 #include "ui/android/resources/resource_manager.h" |
| 21 #include "ui/android/window_android.h" |
20 #include "ui/android/window_android_compositor.h" | 22 #include "ui/android/window_android_compositor.h" |
21 #include "ui/base/l10n/l10n_util_android.h" | 23 #include "ui/base/l10n/l10n_util_android.h" |
22 | 24 |
23 namespace content { | 25 namespace content { |
24 namespace { | 26 namespace { |
25 | 27 |
26 // Used for conditional creation of EdgeEffect types for the overscroll glow. | 28 // Used for conditional creation of EdgeEffect types for the overscroll glow. |
27 const int kAndroidLSDKVersion = 21; | 29 const int kAndroidLSDKVersion = 21; |
28 | 30 |
29 // Default offset in dips from the top of the view beyond which the refresh | |
30 // action will be activated. | |
31 const int kDefaultRefreshDragTargetDips = 64; | |
32 | |
33 // If the glow effect alpha is greater than this value, the refresh effect will | 31 // If the glow effect alpha is greater than this value, the refresh effect will |
34 // be suppressed. This value was experimentally determined to provide a | 32 // be suppressed. This value was experimentally determined to provide a |
35 // reasonable balance between avoiding accidental refresh activation and | 33 // reasonable balance between avoiding accidental refresh activation and |
36 // minimizing the wait required to refresh after the glow has been triggered. | 34 // minimizing the wait required to refresh after the glow has been triggered. |
37 const float kMinGlowAlphaToDisableRefreshOnL = 0.085f; | 35 const float kMinGlowAlphaToDisableRefreshOnL = 0.085f; |
38 | 36 |
39 bool IsAndroidLOrNewer() { | 37 bool IsAndroidLOrNewer() { |
40 static bool android_l_or_newer = | 38 static bool android_l_or_newer = |
41 base::android::BuildInfo::GetInstance()->sdk_int() >= kAndroidLSDKVersion; | 39 base::android::BuildInfo::GetInstance()->sdk_int() >= kAndroidLSDKVersion; |
42 return android_l_or_newer; | 40 return android_l_or_newer; |
(...skipping 29 matching lines...) Expand all Loading... |
72 float dpi_scale) { | 70 float dpi_scale) { |
73 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 71 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
74 switches::kDisableOverscrollEdgeEffect)) { | 72 switches::kDisableOverscrollEdgeEffect)) { |
75 return nullptr; | 73 return nullptr; |
76 } | 74 } |
77 | 75 |
78 return make_scoped_ptr(new OverscrollGlow(client)); | 76 return make_scoped_ptr(new OverscrollGlow(client)); |
79 } | 77 } |
80 | 78 |
81 scoped_ptr<OverscrollRefresh> CreateRefreshEffect( | 79 scoped_ptr<OverscrollRefresh> CreateRefreshEffect( |
82 ui::WindowAndroidCompositor* compositor, | 80 OverscrollRefreshHandler* handler) { |
83 OverscrollRefreshClient* client, | |
84 float dpi_scale) { | |
85 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 81 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
86 switches::kDisablePullToRefreshEffect)) { | 82 switches::kDisablePullToRefreshEffect)) { |
87 return nullptr; | 83 return nullptr; |
88 } | 84 } |
89 | 85 |
90 return make_scoped_ptr(new OverscrollRefresh( | 86 return make_scoped_ptr(new OverscrollRefresh(handler)); |
91 &compositor->GetResourceManager(), client, | |
92 kDefaultRefreshDragTargetDips * dpi_scale, l10n_util::IsLayoutRtl())); | |
93 } | 87 } |
94 | 88 |
95 } // namespace | 89 } // namespace |
96 | 90 |
97 OverscrollControllerAndroid::OverscrollControllerAndroid( | 91 OverscrollControllerAndroid::OverscrollControllerAndroid( |
98 WebContents* web_contents, | 92 ContentViewCoreImpl* content_view_core) |
99 ui::WindowAndroidCompositor* compositor, | 93 : compositor_(content_view_core->GetWindowAndroid()->GetCompositor()), |
100 float dpi_scale) | 94 dpi_scale_(content_view_core->GetDpiScale()), |
101 : compositor_(compositor), | |
102 dpi_scale_(dpi_scale), | |
103 enabled_(true), | 95 enabled_(true), |
104 glow_effect_(CreateGlowEffect(this, dpi_scale)), | 96 glow_effect_(CreateGlowEffect(this, dpi_scale_)), |
105 refresh_effect_(CreateRefreshEffect(compositor, this, dpi_scale)), | 97 refresh_effect_(CreateRefreshEffect(content_view_core)), |
106 triggered_refresh_active_(false), | 98 is_fullscreen_(false) { |
107 is_fullscreen_(static_cast<WebContentsImpl*>(web_contents) | 99 DCHECK(compositor_); |
108 ->IsFullscreenForCurrentTab()) { | |
109 DCHECK(web_contents); | |
110 DCHECK(compositor); | |
111 if (refresh_effect_) | |
112 Observe(web_contents); | |
113 } | 100 } |
114 | 101 |
115 OverscrollControllerAndroid::~OverscrollControllerAndroid() { | 102 OverscrollControllerAndroid::~OverscrollControllerAndroid() { |
116 } | 103 } |
117 | 104 |
118 bool OverscrollControllerAndroid::WillHandleGestureEvent( | 105 bool OverscrollControllerAndroid::WillHandleGestureEvent( |
119 const blink::WebGestureEvent& event) { | 106 const blink::WebGestureEvent& event) { |
120 if (!enabled_) | 107 if (!enabled_) |
121 return false; | 108 return false; |
122 | 109 |
123 if (!refresh_effect_) | 110 if (!refresh_effect_) |
124 return false; | 111 return false; |
125 | 112 |
126 // Suppress refresh detection for fullscreen HTML5 scenarios, e.g., video. | 113 // Suppress refresh detection for fullscreen HTML5 scenarios, e.g., video. |
127 if (is_fullscreen_) | 114 if (is_fullscreen_) |
128 return false; | 115 return false; |
129 | 116 |
130 // Suppress refresh detection if the glow effect is still prominent. | 117 // Suppress refresh detection if the glow effect is still prominent. |
131 if (glow_effect_ && glow_effect_->IsActive()) { | 118 if (glow_effect_ && glow_effect_->IsActive()) { |
132 if (glow_effect_->GetVisibleAlpha() > MinGlowAlphaToDisableRefresh()) | 119 if (glow_effect_->GetVisibleAlpha() > MinGlowAlphaToDisableRefresh()) |
133 return false; | 120 return false; |
134 } | 121 } |
135 | 122 |
136 bool handled = false; | 123 bool handled = false; |
137 bool maybe_needs_animate = false; | |
138 switch (event.type) { | 124 switch (event.type) { |
139 case blink::WebInputEvent::GestureScrollBegin: | 125 case blink::WebInputEvent::GestureScrollBegin: |
140 refresh_effect_->OnScrollBegin(); | 126 refresh_effect_->OnScrollBegin(); |
141 break; | 127 break; |
142 | 128 |
143 case blink::WebInputEvent::GestureScrollUpdate: { | 129 case blink::WebInputEvent::GestureScrollUpdate: { |
144 gfx::Vector2dF scroll_delta(event.data.scrollUpdate.deltaX, | 130 gfx::Vector2dF scroll_delta(event.data.scrollUpdate.deltaX, |
145 event.data.scrollUpdate.deltaY); | 131 event.data.scrollUpdate.deltaY); |
146 scroll_delta.Scale(dpi_scale_); | 132 scroll_delta.Scale(dpi_scale_); |
147 maybe_needs_animate = true; | |
148 handled = refresh_effect_->WillHandleScrollUpdate(scroll_delta); | 133 handled = refresh_effect_->WillHandleScrollUpdate(scroll_delta); |
149 } break; | 134 } break; |
150 | 135 |
151 case blink::WebInputEvent::GestureScrollEnd: | 136 case blink::WebInputEvent::GestureScrollEnd: |
152 refresh_effect_->OnScrollEnd(gfx::Vector2dF()); | 137 refresh_effect_->OnScrollEnd(gfx::Vector2dF()); |
153 maybe_needs_animate = true; | |
154 break; | 138 break; |
155 | 139 |
156 case blink::WebInputEvent::GestureFlingStart: { | 140 case blink::WebInputEvent::GestureFlingStart: { |
157 gfx::Vector2dF scroll_velocity(event.data.flingStart.velocityX, | |
158 event.data.flingStart.velocityY); | |
159 scroll_velocity.Scale(dpi_scale_); | |
160 refresh_effect_->OnScrollEnd(scroll_velocity); | |
161 if (refresh_effect_->IsActive()) { | 141 if (refresh_effect_->IsActive()) { |
| 142 gfx::Vector2dF scroll_velocity(event.data.flingStart.velocityX, |
| 143 event.data.flingStart.velocityY); |
| 144 scroll_velocity.Scale(dpi_scale_); |
| 145 refresh_effect_->OnScrollEnd(scroll_velocity); |
162 // TODO(jdduke): Figure out a cleaner way of suppressing a fling. | 146 // TODO(jdduke): Figure out a cleaner way of suppressing a fling. |
163 // It's important that the any downstream code sees a scroll-ending | 147 // It's important that the any downstream code sees a scroll-ending |
164 // event (in this case GestureFlingStart) if it has seen a scroll begin. | 148 // event (in this case GestureFlingStart) if it has seen a scroll begin. |
165 // Thus, we cannot simply consume the fling. Changing the event type to | 149 // Thus, we cannot simply consume the fling. Changing the event type to |
166 // a GestureScrollEnd might work in practice, but could lead to | 150 // a GestureScrollEnd might work in practice, but could lead to |
167 // unexpected results. For now, simply truncate the fling velocity, but | 151 // unexpected results. For now, simply truncate the fling velocity, but |
168 // not to zero as downstream code may not expect a zero-velocity fling. | 152 // not to zero as downstream code may not expect a zero-velocity fling. |
169 blink::WebGestureEvent& modified_event = | 153 blink::WebGestureEvent& modified_event = |
170 const_cast<blink::WebGestureEvent&>(event); | 154 const_cast<blink::WebGestureEvent&>(event); |
171 modified_event.data.flingStart.velocityX = .01f; | 155 modified_event.data.flingStart.velocityX = .01f; |
172 modified_event.data.flingStart.velocityY = .01f; | 156 modified_event.data.flingStart.velocityY = .01f; |
173 } | 157 } |
174 maybe_needs_animate = true; | |
175 } break; | 158 } break; |
176 | 159 |
177 case blink::WebInputEvent::GesturePinchBegin: | 160 case blink::WebInputEvent::GesturePinchBegin: |
178 refresh_effect_->ReleaseWithoutActivation(); | 161 refresh_effect_->ReleaseWithoutActivation(); |
179 break; | 162 break; |
180 | 163 |
181 default: | 164 default: |
182 break; | 165 break; |
183 } | 166 } |
184 | 167 |
185 if (maybe_needs_animate && refresh_effect_->IsActive()) | |
186 SetNeedsAnimate(); | |
187 | |
188 return handled; | 168 return handled; |
189 } | 169 } |
190 | 170 |
191 void OverscrollControllerAndroid::OnGestureEventAck( | 171 void OverscrollControllerAndroid::OnGestureEventAck( |
192 const blink::WebGestureEvent& event, | 172 const blink::WebGestureEvent& event, |
193 InputEventAckState ack_result) { | 173 InputEventAckState ack_result) { |
194 if (!enabled_) | 174 if (!enabled_) |
195 return; | 175 return; |
196 | 176 |
197 // The overscroll effect requires an explicit release signal that may not be | 177 // The overscroll effect requires an explicit release signal that may not be |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 SetNeedsAnimate(); | 215 SetNeedsAnimate(); |
236 } | 216 } |
237 } | 217 } |
238 | 218 |
239 bool OverscrollControllerAndroid::Animate(base::TimeTicks current_time, | 219 bool OverscrollControllerAndroid::Animate(base::TimeTicks current_time, |
240 cc::Layer* parent_layer) { | 220 cc::Layer* parent_layer) { |
241 DCHECK(parent_layer); | 221 DCHECK(parent_layer); |
242 if (!enabled_) | 222 if (!enabled_) |
243 return false; | 223 return false; |
244 | 224 |
245 bool needs_animate = false; | 225 return glow_effect_->Animate(current_time, parent_layer); |
246 if (refresh_effect_) | |
247 needs_animate |= refresh_effect_->Animate(current_time, parent_layer); | |
248 if (glow_effect_) | |
249 needs_animate |= glow_effect_->Animate(current_time, parent_layer); | |
250 return needs_animate; | |
251 } | 226 } |
252 | 227 |
253 void OverscrollControllerAndroid::OnFrameMetadataUpdated( | 228 void OverscrollControllerAndroid::OnFrameMetadataUpdated( |
254 const cc::CompositorFrameMetadata& frame_metadata) { | 229 const cc::CompositorFrameMetadata& frame_metadata) { |
255 if (!refresh_effect_ && !glow_effect_) | 230 if (!refresh_effect_ && !glow_effect_) |
256 return; | 231 return; |
257 | 232 |
258 const float scale_factor = | 233 const float scale_factor = |
259 frame_metadata.page_scale_factor * frame_metadata.device_scale_factor; | 234 frame_metadata.page_scale_factor * frame_metadata.device_scale_factor; |
260 gfx::SizeF viewport_size = | 235 gfx::SizeF viewport_size = |
261 gfx::ScaleSize(frame_metadata.scrollable_viewport_size, scale_factor); | 236 gfx::ScaleSize(frame_metadata.scrollable_viewport_size, scale_factor); |
262 gfx::SizeF content_size = | 237 gfx::SizeF content_size = |
263 gfx::ScaleSize(frame_metadata.root_layer_size, scale_factor); | 238 gfx::ScaleSize(frame_metadata.root_layer_size, scale_factor); |
264 gfx::Vector2dF content_scroll_offset = | 239 gfx::Vector2dF content_scroll_offset = |
265 gfx::ScaleVector2d(frame_metadata.root_scroll_offset, scale_factor); | 240 gfx::ScaleVector2d(frame_metadata.root_scroll_offset, scale_factor); |
266 | 241 |
267 if (refresh_effect_) { | 242 if (refresh_effect_) { |
268 refresh_effect_->UpdateDisplay(viewport_size, content_scroll_offset, | 243 refresh_effect_->OnFrameUpdated(content_scroll_offset, |
269 frame_metadata.root_overflow_y_hidden); | 244 frame_metadata.root_overflow_y_hidden); |
270 } | 245 } |
271 | 246 |
272 if (glow_effect_) { | 247 if (glow_effect_) { |
273 glow_effect_->UpdateDisplay(viewport_size, content_size, | 248 glow_effect_->OnFrameUpdated(viewport_size, content_size, |
274 content_scroll_offset); | 249 content_scroll_offset); |
275 } | 250 } |
276 } | 251 } |
277 | 252 |
278 void OverscrollControllerAndroid::Enable() { | 253 void OverscrollControllerAndroid::Enable() { |
279 enabled_ = true; | 254 enabled_ = true; |
280 } | 255 } |
281 | 256 |
282 void OverscrollControllerAndroid::Disable() { | 257 void OverscrollControllerAndroid::Disable() { |
283 if (!enabled_) | 258 if (!enabled_) |
284 return; | 259 return; |
285 enabled_ = false; | 260 enabled_ = false; |
286 if (!enabled_) { | 261 if (!enabled_) { |
287 if (refresh_effect_) | 262 if (refresh_effect_) |
288 refresh_effect_->Reset(); | 263 refresh_effect_->Reset(); |
289 if (glow_effect_) | 264 if (glow_effect_) |
290 glow_effect_->Reset(); | 265 glow_effect_->Reset(); |
291 } | 266 } |
292 } | 267 } |
293 | 268 |
294 void OverscrollControllerAndroid::DidNavigateMainFrame( | |
295 const LoadCommittedDetails& details, | |
296 const FrameNavigateParams& params) { | |
297 // Once the main frame has navigated, there's little need to further animate | |
298 // the reload effect. Note that the effect will naturally time out should the | |
299 // reload be interruped for any reason. | |
300 triggered_refresh_active_ = false; | |
301 } | |
302 | |
303 void OverscrollControllerAndroid::DidToggleFullscreenModeForTab( | 269 void OverscrollControllerAndroid::DidToggleFullscreenModeForTab( |
304 bool entered_fullscreen) { | 270 bool entered_fullscreen) { |
305 if (is_fullscreen_ == entered_fullscreen) | 271 if (is_fullscreen_ == entered_fullscreen) |
306 return; | 272 return; |
307 is_fullscreen_ = entered_fullscreen; | 273 is_fullscreen_ = entered_fullscreen; |
308 if (is_fullscreen_) | 274 if (is_fullscreen_) |
309 refresh_effect_->ReleaseWithoutActivation(); | 275 refresh_effect_->ReleaseWithoutActivation(); |
310 } | 276 } |
311 | 277 |
312 void OverscrollControllerAndroid::TriggerRefresh() { | |
313 triggered_refresh_active_ = false; | |
314 if (!web_contents()) | |
315 return; | |
316 | |
317 triggered_refresh_active_ = true; | |
318 RecordAction(base::UserMetricsAction("MobilePullGestureReload")); | |
319 web_contents()->GetController().Reload(true); | |
320 } | |
321 | |
322 bool OverscrollControllerAndroid::IsStillRefreshing() const { | |
323 return triggered_refresh_active_; | |
324 } | |
325 | |
326 scoped_ptr<EdgeEffectBase> OverscrollControllerAndroid::CreateEdgeEffect() { | 278 scoped_ptr<EdgeEffectBase> OverscrollControllerAndroid::CreateEdgeEffect() { |
327 return CreateGlowEdgeEffect(&compositor_->GetResourceManager(), dpi_scale_); | 279 return CreateGlowEdgeEffect(&compositor_->GetResourceManager(), dpi_scale_); |
328 } | 280 } |
329 | 281 |
330 void OverscrollControllerAndroid::SetNeedsAnimate() { | 282 void OverscrollControllerAndroid::SetNeedsAnimate() { |
331 compositor_->SetNeedsAnimate(); | 283 compositor_->SetNeedsAnimate(); |
332 } | 284 } |
333 | 285 |
334 } // namespace content | 286 } // namespace content |
OLD | NEW |