Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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 "ash/shelf/voice_interaction_overlay.h" | 5 #include "ash/shelf/voice_interaction_overlay.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <memory> | 8 #include <memory> |
| 9 #include <string> | |
| 9 #include <utility> | 10 #include <utility> |
| 10 | 11 |
| 11 #include "ash/public/cpp/shelf_types.h" | 12 #include "ash/public/cpp/shelf_types.h" |
| 12 #include "ash/resources/vector_icons/vector_icons.h" | 13 #include "ash/resources/vector_icons/vector_icons.h" |
| 13 #include "ash/shelf/app_list_button.h" | 14 #include "ash/shelf/app_list_button.h" |
| 14 #include "ash/shelf/ink_drop_button_listener.h" | 15 #include "ash/shelf/ink_drop_button_listener.h" |
| 15 #include "ash/shelf/shelf.h" | 16 #include "ash/shelf/shelf.h" |
| 16 #include "ash/shelf/shelf_constants.h" | 17 #include "ash/shelf/shelf_constants.h" |
| 17 #include "ash/shelf/shelf_view.h" | 18 #include "ash/shelf/shelf_view.h" |
| 18 #include "ash/shell.h" | 19 #include "ash/shell.h" |
| 19 #include "ash/strings/grit/ash_strings.h" | 20 #include "ash/strings/grit/ash_strings.h" |
| 20 #include "ash/system/tray/tray_popup_utils.h" | 21 #include "ash/system/tray/tray_popup_utils.h" |
| 21 #include "base/command_line.h" | 22 #include "base/command_line.h" |
| 22 #include "base/memory/ptr_util.h" | 23 #include "base/memory/ptr_util.h" |
| 23 #include "base/metrics/user_metrics.h" | 24 #include "base/metrics/user_metrics.h" |
| 24 #include "base/metrics/user_metrics_action.h" | 25 #include "base/metrics/user_metrics_action.h" |
| 25 #include "chromeos/chromeos_switches.h" | 26 #include "chromeos/chromeos_switches.h" |
| 26 #include "ui/accessibility/ax_node_data.h" | 27 #include "ui/accessibility/ax_node_data.h" |
| 27 #include "ui/app_list/presenter/app_list.h" | 28 #include "ui/app_list/presenter/app_list.h" |
| 28 #include "ui/base/l10n/l10n_util.h" | 29 #include "ui/base/l10n/l10n_util.h" |
| 30 #include "ui/compositor/callback_layer_animation_observer.h" | |
| 29 #include "ui/compositor/layer_animation_element.h" | 31 #include "ui/compositor/layer_animation_element.h" |
| 30 #include "ui/compositor/layer_animation_observer.h" | 32 #include "ui/compositor/layer_animation_observer.h" |
| 31 #include "ui/compositor/layer_animation_sequence.h" | 33 #include "ui/compositor/layer_animation_sequence.h" |
| 32 #include "ui/compositor/layer_animator.h" | 34 #include "ui/compositor/layer_animator.h" |
| 33 #include "ui/compositor/paint_context.h" | 35 #include "ui/compositor/paint_context.h" |
| 34 #include "ui/compositor/paint_recorder.h" | 36 #include "ui/compositor/paint_recorder.h" |
| 35 #include "ui/compositor/scoped_layer_animation_settings.h" | 37 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 36 #include "ui/gfx/canvas.h" | 38 #include "ui/gfx/canvas.h" |
| 37 #include "ui/gfx/image/canvas_image_source.h" | 39 #include "ui/gfx/image/canvas_image_source.h" |
| 38 #include "ui/gfx/image/image_skia.h" | 40 #include "ui/gfx/image/image_skia.h" |
| 39 #include "ui/gfx/image/image_skia_operations.h" | 41 #include "ui/gfx/image/image_skia_operations.h" |
| 40 #include "ui/gfx/paint_vector_icon.h" | 42 #include "ui/gfx/paint_vector_icon.h" |
| 41 #include "ui/gfx/scoped_canvas.h" | 43 #include "ui/gfx/scoped_canvas.h" |
| 42 #include "ui/gfx/skia_paint_util.h" | 44 #include "ui/gfx/skia_paint_util.h" |
| 43 #include "ui/views/animation/flood_fill_ink_drop_ripple.h" | 45 #include "ui/views/animation/flood_fill_ink_drop_ripple.h" |
| 44 #include "ui/views/animation/ink_drop_impl.h" | 46 #include "ui/views/animation/ink_drop_impl.h" |
| 45 #include "ui/views/animation/ink_drop_mask.h" | 47 #include "ui/views/animation/ink_drop_mask.h" |
| 48 #include "ui/views/animation/ink_drop_painted_layer_delegates.h" | |
| 46 #include "ui/views/painter.h" | 49 #include "ui/views/painter.h" |
| 47 #include "ui/views/widget/widget.h" | 50 #include "ui/views/widget/widget.h" |
| 48 | 51 |
| 49 namespace ash { | 52 namespace ash { |
| 50 namespace { | 53 namespace { |
| 51 constexpr int kFullExpandDurationMs = 450; | 54 constexpr int kFullExpandDurationMs = 450; |
| 52 constexpr int kFullRetractDurationMs = 300; | 55 constexpr int kFullRetractDurationMs = 300; |
| 53 constexpr int kFullBurstDurationMs = 200; | 56 constexpr int kFullBurstDurationMs = 200; |
| 54 | 57 |
| 55 constexpr float kRippleCircleInitRadiusDip = 40.f; | 58 constexpr float kRippleCircleInitRadiusDip = 40.f; |
| 56 constexpr float kRippleCircleStartRadiusDip = 1.f; | 59 constexpr float kRippleCircleStartRadiusDip = 1.f; |
| 57 constexpr float kRippleCircleRadiusDip = 77.f; | 60 constexpr float kRippleCircleRadiusDip = 77.f; |
| 58 constexpr float kRippleCircleBurstRadiusDip = 96.f; | 61 constexpr float kRippleCircleBurstRadiusDip = 96.f; |
| 59 constexpr SkColor kRippleColor = SK_ColorWHITE; | 62 constexpr SkColor kRippleColor = SK_ColorWHITE; |
| 60 constexpr int kRippleExpandDurationMs = 400; | 63 constexpr int kRippleExpandDurationMs = 400; |
| 61 constexpr int kRippleOpacityDurationMs = 100; | 64 constexpr int kRippleOpacityDurationMs = 100; |
| 62 constexpr int kRippleOpacityRetractDurationMs = 200; | 65 constexpr int kRippleOpacityRetractDurationMs = 200; |
| 63 constexpr float kRippleOpacity = 0.2f; | 66 constexpr float kRippleOpacity = 0.2f; |
| 64 | 67 |
| 65 constexpr float kIconInitSizeDip = 24.f; | 68 constexpr float kIconInitSizeDip = 48.f; |
| 66 constexpr float kIconStartSizeDip = 4.f; | 69 constexpr float kIconStartSizeDip = 4.f; |
| 67 constexpr float kIconSizeDip = 24.f; | 70 constexpr float kIconSizeDip = 24.f; |
| 71 constexpr float kIconEndSizeDip = 48.f; | |
| 68 constexpr float kIconOffsetDip = 56.f; | 72 constexpr float kIconOffsetDip = 56.f; |
| 69 constexpr float kIconOpacity = 1.f; | 73 constexpr float kIconOpacity = 1.f; |
| 70 constexpr int kIconBurstDurationMs = 100; | |
| 71 | 74 |
| 72 constexpr float kBackgroundInitSizeDip = 48.f; | 75 constexpr float kBackgroundInitSizeDip = 48.f; |
| 73 constexpr float kBackgroundStartSizeDip = 10.f; | 76 constexpr float kBackgroundStartSizeDip = 10.f; |
| 74 constexpr float kBackgroundSizeDip = 48.f; | 77 constexpr float kBackgroundSizeDip = 48.f; |
| 75 constexpr int kBackgroundOpacityDurationMs = 200; | 78 constexpr int kBackgroundOpacityDurationMs = 200; |
| 76 constexpr float kBackgroundShadowElevationDip = 24.f; | 79 constexpr float kBackgroundShadowElevationDip = 24.f; |
| 80 // TODO(xiaohuic): this is 2x device size, 1x actually have a different size. | |
| 81 // Need to figure out a way to dynamically change sizes. | |
| 82 constexpr float kBackgroundLargeWidthDip = 352.5f; | |
| 83 constexpr float kBackgroundLargeHeightDip = 540.0f; | |
| 84 constexpr float kBackgroundCornerRadiusDip = 2.f; | |
| 85 constexpr float kBackgroundPaddingDip = 6.f; | |
| 86 constexpr int kBackgroundMorphDurationMs = 300; | |
| 87 | |
| 88 constexpr int kHideDurationMs = 200; | |
| 89 | |
| 90 // The minimum scale factor to use when scaling rectangle layers. Smaller values | |
| 91 // were causing visual anomalies. | |
| 92 constexpr float kMinimumRectScale = 0.0001f; | |
| 93 | |
| 94 // The minimum scale factor to use when scaling circle layers. Smaller values | |
| 95 // were causing visual anomalies. | |
| 96 constexpr float kMinimumCircleScale = 0.001f; | |
| 97 | |
| 98 class VoiceInteractionIcon : public ui::Layer, public ui::LayerDelegate { | |
| 99 public: | |
| 100 VoiceInteractionIcon() { | |
| 101 set_name("VoiceInteractionOverlay:ICON_LAYER"); | |
| 102 SetBounds(gfx::Rect(0, 0, kIconInitSizeDip, kIconInitSizeDip)); | |
| 103 SetFillsBoundsOpaquely(false); | |
| 104 SetMasksToBounds(false); | |
| 105 set_delegate(this); | |
| 106 } | |
| 107 | |
| 108 private: | |
| 109 // ui::LayerDelegate: | |
| 110 void OnPaintLayer(const ui::PaintContext& context) override { | |
| 111 ui::PaintRecorder recorder(context, size()); | |
| 112 gfx::PaintVectorIcon(recorder.canvas(), kShelfVoiceInteractionIcon, | |
| 113 kIconInitSizeDip, 0); | |
| 114 } | |
| 115 | |
| 116 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} | |
| 117 | |
| 118 void OnDeviceScaleFactorChanged(float device_scale_factor) override {} | |
| 119 | |
| 120 DISALLOW_COPY_AND_ASSIGN(VoiceInteractionIcon); | |
| 121 }; | |
| 122 } // namespace | |
| 77 | 123 |
| 78 class VoiceInteractionIconBackground : public ui::Layer, | 124 class VoiceInteractionIconBackground : public ui::Layer, |
| 79 public ui::LayerDelegate { | 125 public ui::LayerDelegate { |
| 80 public: | 126 public: |
| 81 VoiceInteractionIconBackground() : Layer(ui::LAYER_NOT_DRAWN) { | 127 VoiceInteractionIconBackground() |
| 128 : Layer(ui::LAYER_NOT_DRAWN), | |
| 129 large_size_( | |
| 130 gfx::Size(kBackgroundLargeWidthDip, kBackgroundLargeHeightDip)), | |
| 131 small_size_(gfx::Size(kBackgroundSizeDip, kBackgroundSizeDip)), | |
| 132 center_point_( | |
|
oshima
2017/07/06 22:04:42
I was thinking something like
HalfSize(small_siz
xc
2017/07/07 16:38:15
I see, some of the places are getting points, some
| |
| 133 gfx::PointF(kBackgroundSizeDip / 2, kBackgroundSizeDip / 2)), | |
| 134 circle_layer_delegate_( | |
| 135 new views::CircleLayerDelegate(SK_ColorWHITE, | |
| 136 kBackgroundSizeDip / 2)), | |
| 137 rect_layer_delegate_( | |
| 138 new views::RectangleLayerDelegate(SK_ColorWHITE, | |
|
oshima
2017/07/06 22:04:42
MakeUnique
xc
2017/07/07 16:38:15
Done.
| |
| 139 gfx::SizeF(small_size_))) { | |
| 82 set_name("VoiceInteractionOverlay:BACKGROUND_LAYER"); | 140 set_name("VoiceInteractionOverlay:BACKGROUND_LAYER"); |
| 83 SetBounds(gfx::Rect(0, 0, kBackgroundInitSizeDip, kBackgroundInitSizeDip)); | 141 SetBounds(gfx::Rect(0, 0, kBackgroundInitSizeDip, kBackgroundInitSizeDip)); |
| 84 SetFillsBoundsOpaquely(false); | 142 SetFillsBoundsOpaquely(false); |
| 85 SetMasksToBounds(false); | 143 SetMasksToBounds(false); |
| 86 | 144 |
| 145 for (int i = 0; i < static_cast<int>(PaintedShape::PAINTED_SHAPE_COUNT); | |
| 146 ++i) | |
|
oshima
2017/07/06 22:04:42
alternatively, you can define
const PaintedShape
xc
2017/07/07 16:38:15
Done.
| |
| 147 AddPaintLayer(static_cast<PaintedShape>(i)); | |
| 148 | |
| 87 shadow_values_ = | 149 shadow_values_ = |
| 88 gfx::ShadowValue::MakeMdShadowValues(kBackgroundShadowElevationDip); | 150 gfx::ShadowValue::MakeMdShadowValues(kBackgroundShadowElevationDip); |
| 89 const gfx::Insets shadow_margin = | 151 const gfx::Insets shadow_margin = |
| 90 gfx::ShadowValue::GetMargin(shadow_values_); | 152 gfx::ShadowValue::GetMargin(shadow_values_); |
| 91 | 153 |
| 92 shadow_layer_.reset(new ui::Layer()); | 154 shadow_layer_.reset(new ui::Layer()); |
| 93 shadow_layer_->set_delegate(this); | 155 shadow_layer_->set_delegate(this); |
| 94 shadow_layer_->SetFillsBoundsOpaquely(false); | 156 shadow_layer_->SetFillsBoundsOpaquely(false); |
| 95 shadow_layer_->SetBounds( | 157 shadow_layer_->SetBounds( |
| 96 gfx::Rect(shadow_margin.left(), shadow_margin.top(), | 158 gfx::Rect(shadow_margin.left(), shadow_margin.top(), |
| 97 kBackgroundInitSizeDip - shadow_margin.width(), | 159 kBackgroundInitSizeDip - shadow_margin.width(), |
| 98 kBackgroundInitSizeDip - shadow_margin.height())); | 160 kBackgroundInitSizeDip - shadow_margin.height())); |
| 99 Add(shadow_layer_.get()); | 161 Add(shadow_layer_.get()); |
| 100 } | 162 } |
| 101 ~VoiceInteractionIconBackground() override{}; | 163 ~VoiceInteractionIconBackground() override{}; |
| 102 | 164 |
| 165 void AnimateToLarge(const gfx::PointF& new_center, | |
| 166 ui::LayerAnimationObserver* animation_observer) { | |
| 167 PaintedShapeTransforms transforms; | |
| 168 // Setup the painted layers to be the small round size and show it | |
| 169 CalculateCircleTransforms(small_size_, &transforms); | |
| 170 SetTransforms(transforms); | |
| 171 SetPaintedLayersVisible(true); | |
| 172 | |
| 173 // Hide the shadow layer | |
| 174 shadow_layer_->SetVisible(false); | |
| 175 | |
| 176 center_point_ = new_center; | |
| 177 // Animate the painted layers to the large rectangle size | |
| 178 CalculateRectTransforms(large_size_, kBackgroundCornerRadiusDip, | |
| 179 &transforms); | |
| 180 | |
| 181 AnimateToTransforms( | |
| 182 transforms, | |
| 183 base::TimeDelta::FromMilliseconds(kBackgroundMorphDurationMs), | |
| 184 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, | |
| 185 gfx::Tween::LINEAR_OUT_SLOW_IN, animation_observer); | |
| 186 } | |
| 187 | |
| 188 void ResetShape() { | |
| 189 // This reverts to the original small round shape. | |
| 190 shadow_layer_->SetVisible(true); | |
| 191 SetPaintedLayersVisible(false); | |
| 192 center_point_.SetPoint(small_size_.width() / 2.f, | |
| 193 small_size_.height() / 2.f); | |
| 194 } | |
| 195 | |
| 103 private: | 196 private: |
| 197 // Enumeration of the different shapes that compose the background. | |
| 198 enum class PaintedShape { | |
| 199 TOP_LEFT_CIRCLE = 0, | |
| 200 TOP_RIGHT_CIRCLE, | |
| 201 BOTTOM_RIGHT_CIRCLE, | |
| 202 BOTTOM_LEFT_CIRCLE, | |
| 203 HORIZONTAL_RECT, | |
| 204 VERTICAL_RECT, | |
| 205 // The total number of shapes, not an actual shape. | |
| 206 PAINTED_SHAPE_COUNT | |
| 207 }; | |
|
oshima
2017/07/07 19:15:38
How about moving this to anonymous class, and defi
xc
2017/07/07 23:35:39
changed back to enum.
| |
| 208 | |
| 209 typedef gfx::Transform PaintedShapeTransforms[static_cast<int>( | |
| 210 PaintedShape::PAINTED_SHAPE_COUNT)]; | |
| 211 | |
| 212 void AddPaintLayer(PaintedShape painted_shape) { | |
| 213 ui::LayerDelegate* delegate = nullptr; | |
| 214 switch (painted_shape) { | |
| 215 case PaintedShape::TOP_LEFT_CIRCLE: | |
| 216 case PaintedShape::TOP_RIGHT_CIRCLE: | |
| 217 case PaintedShape::BOTTOM_RIGHT_CIRCLE: | |
| 218 case PaintedShape::BOTTOM_LEFT_CIRCLE: | |
| 219 delegate = circle_layer_delegate_.get(); | |
| 220 break; | |
| 221 case PaintedShape::HORIZONTAL_RECT: | |
| 222 case PaintedShape::VERTICAL_RECT: | |
| 223 delegate = rect_layer_delegate_.get(); | |
| 224 break; | |
| 225 case PaintedShape::PAINTED_SHAPE_COUNT: | |
| 226 NOTREACHED() << "PAINTED_SHAPE_COUNT is not an actual shape type."; | |
| 227 break; | |
| 228 } | |
| 229 | |
| 230 ui::Layer* layer = new ui::Layer(); | |
| 231 Add(layer); | |
| 232 | |
| 233 layer->SetBounds(gfx::Rect(small_size_)); | |
| 234 layer->SetFillsBoundsOpaquely(false); | |
| 235 layer->set_delegate(delegate); | |
| 236 layer->SetVisible(true); | |
| 237 layer->SetOpacity(1.0); | |
| 238 layer->SetMasksToBounds(false); | |
| 239 layer->set_name("PAINTED_SHAPE_COUNT:" + ToLayerName(painted_shape)); | |
| 240 | |
| 241 painted_layers_[static_cast<int>(painted_shape)].reset(layer); | |
| 242 } | |
| 243 | |
| 244 void SetTransforms(const PaintedShapeTransforms transforms) { | |
| 245 for (int i = 0; i < static_cast<int>(PaintedShape::PAINTED_SHAPE_COUNT); | |
| 246 ++i) | |
|
oshima
2017/07/07 19:15:37
kAllShapse
xc
2017/07/07 23:35:39
changed back to enum
| |
| 247 painted_layers_[i]->SetTransform(transforms[i]); | |
| 248 } | |
| 249 | |
| 250 void SetPaintedLayersVisible(bool visible) { | |
| 251 for (int i = 0; i < static_cast<int>(PaintedShape::PAINTED_SHAPE_COUNT); | |
| 252 ++i) | |
|
oshima
2017/07/07 19:15:37
ditto
xc
2017/07/07 23:35:39
changed back to enum
| |
| 253 painted_layers_[i]->SetVisible(visible); | |
| 254 } | |
| 255 | |
| 256 void CalculateCircleTransforms(const gfx::Size& size, | |
| 257 PaintedShapeTransforms* transforms_out) const { | |
| 258 CalculateRectTransforms(size, std::min(size.width(), size.height()) / 2.0f, | |
| 259 transforms_out); | |
| 260 } | |
| 261 | |
| 262 void CalculateRectTransforms(const gfx::Size& desired_size, | |
| 263 float corner_radius, | |
| 264 PaintedShapeTransforms* transforms_out) const { | |
| 265 DCHECK_GE(desired_size.width() / 2.0f, corner_radius) | |
| 266 << "The circle's diameter should not be greater than the total width."; | |
| 267 DCHECK_GE(desired_size.height() / 2.0f, corner_radius) | |
| 268 << "The circle's diameter should not be greater than the total height."; | |
| 269 | |
| 270 gfx::SizeF size(desired_size); | |
| 271 // This function can be called before the layer's been added to a view, | |
| 272 // either at construction time or in tests. | |
| 273 if (GetCompositor()) { | |
| 274 // Modify |desired_size| so that the ripple aligns to pixel bounds. | |
| 275 const float dsf = GetCompositor()->device_scale_factor(); | |
| 276 gfx::RectF ripple_bounds((gfx::PointF(center_point_)), gfx::SizeF()); | |
| 277 ripple_bounds.Inset(-gfx::InsetsF(desired_size.height() / 2.0f, | |
| 278 desired_size.width() / 2.0f)); | |
| 279 ripple_bounds.Scale(dsf); | |
| 280 ripple_bounds = gfx::RectF(gfx::ToEnclosingRect(ripple_bounds)); | |
|
oshima
2017/07/06 22:04:42
gfx::ScaleToEnclosingRect?
xc
2017/07/07 16:38:15
This one does not support RectF
oshima
2017/07/07 19:15:38
Doh, too bad.
xc
2017/07/07 23:35:39
Acknowledged.
| |
| 281 ripple_bounds.Scale(1.0f / dsf); | |
| 282 size = ripple_bounds.size(); | |
| 283 } | |
| 284 | |
| 285 // The shapes are drawn such that their center points are not at the origin. | |
| 286 // Thus we use the CalculateCircleTransform() and CalculateRectTransform() | |
| 287 // methods to calculate the complex Transforms. | |
| 288 | |
| 289 const float circle_scale = std::max( | |
| 290 kMinimumCircleScale, | |
| 291 corner_radius / static_cast<float>(circle_layer_delegate_->radius())); | |
| 292 | |
| 293 const float circle_target_x_offset = size.width() / 2.0f - corner_radius; | |
| 294 const float circle_target_y_offset = size.height() / 2.0f - corner_radius; | |
| 295 | |
| 296 (*transforms_out)[static_cast<int>(PaintedShape::TOP_LEFT_CIRCLE)] = | |
| 297 CalculateCircleTransform(circle_scale, -circle_target_x_offset, | |
| 298 -circle_target_y_offset); | |
| 299 (*transforms_out)[static_cast<int>(PaintedShape::TOP_RIGHT_CIRCLE)] = | |
| 300 CalculateCircleTransform(circle_scale, circle_target_x_offset, | |
| 301 -circle_target_y_offset); | |
| 302 (*transforms_out)[static_cast<int>(PaintedShape::BOTTOM_RIGHT_CIRCLE)] = | |
| 303 CalculateCircleTransform(circle_scale, circle_target_x_offset, | |
| 304 circle_target_y_offset); | |
| 305 (*transforms_out)[static_cast<int>(PaintedShape::BOTTOM_LEFT_CIRCLE)] = | |
| 306 CalculateCircleTransform(circle_scale, -circle_target_x_offset, | |
| 307 circle_target_y_offset); | |
| 308 | |
| 309 const float rect_delegate_width = rect_layer_delegate_->size().width(); | |
| 310 const float rect_delegate_height = rect_layer_delegate_->size().height(); | |
| 311 | |
| 312 (*transforms_out)[static_cast<int>(PaintedShape::HORIZONTAL_RECT)] = | |
| 313 CalculateRectTransform( | |
| 314 std::max(kMinimumRectScale, size.width() / rect_delegate_width), | |
| 315 std::max(kMinimumRectScale, (size.height() - 2.0f * corner_radius) / | |
| 316 rect_delegate_height)); | |
| 317 | |
| 318 (*transforms_out)[static_cast<int>(PaintedShape::VERTICAL_RECT)] = | |
| 319 CalculateRectTransform( | |
| 320 std::max(kMinimumRectScale, (size.width() - 2.0f * corner_radius) / | |
| 321 rect_delegate_width), | |
| 322 std::max(kMinimumRectScale, size.height() / rect_delegate_height)); | |
| 323 } | |
| 324 | |
| 325 gfx::Transform CalculateCircleTransform(float scale, | |
| 326 float target_center_x, | |
| 327 float target_center_y) const { | |
| 328 gfx::Transform transform; | |
| 329 // Offset for the center point of the ripple. | |
| 330 transform.Translate(center_point_.x(), center_point_.y()); | |
| 331 // Move circle to target. | |
| 332 transform.Translate(target_center_x, target_center_y); | |
| 333 transform.Scale(scale, scale); | |
| 334 // Align center point of the painted circle. | |
| 335 const gfx::Vector2dF circle_center_offset = | |
| 336 circle_layer_delegate_->GetCenteringOffset(); | |
| 337 transform.Translate(-circle_center_offset.x(), -circle_center_offset.y()); | |
| 338 return transform; | |
| 339 } | |
| 340 | |
| 341 gfx::Transform CalculateRectTransform(float x_scale, float y_scale) const { | |
| 342 gfx::Transform transform; | |
| 343 transform.Translate(center_point_.x(), center_point_.y()); | |
| 344 transform.Scale(x_scale, y_scale); | |
| 345 const gfx::Vector2dF rect_center_offset = | |
| 346 rect_layer_delegate_->GetCenteringOffset(); | |
| 347 transform.Translate(-rect_center_offset.x(), -rect_center_offset.y()); | |
| 348 return transform; | |
| 349 } | |
| 350 | |
| 351 void AnimateToTransforms( | |
| 352 const PaintedShapeTransforms transforms, | |
| 353 base::TimeDelta duration, | |
| 354 ui::LayerAnimator::PreemptionStrategy preemption_strategy, | |
| 355 gfx::Tween::Type tween, | |
| 356 ui::LayerAnimationObserver* animation_observer) { | |
| 357 for (int i = 0; i < static_cast<int>(PaintedShape::PAINTED_SHAPE_COUNT); | |
| 358 ++i) { | |
| 359 ui::LayerAnimator* animator = painted_layers_[i]->GetAnimator(); | |
| 360 ui::ScopedLayerAnimationSettings animation(animator); | |
| 361 animation.SetPreemptionStrategy(preemption_strategy); | |
| 362 animation.SetTweenType(tween); | |
| 363 std::unique_ptr<ui::LayerAnimationElement> element = | |
| 364 ui::LayerAnimationElement::CreateTransformElement(transforms[i], | |
| 365 duration); | |
| 366 ui::LayerAnimationSequence* sequence = | |
| 367 new ui::LayerAnimationSequence(std::move(element)); | |
| 368 | |
| 369 if (animation_observer) | |
| 370 sequence->AddObserver(animation_observer); | |
| 371 | |
| 372 animator->StartAnimation(sequence); | |
| 373 } | |
| 374 } | |
| 375 | |
| 376 std::string ToLayerName(PaintedShape painted_shape) { | |
| 377 switch (painted_shape) { | |
| 378 case PaintedShape::TOP_LEFT_CIRCLE: | |
| 379 return "TOP_LEFT_CIRCLE"; | |
| 380 case PaintedShape::TOP_RIGHT_CIRCLE: | |
| 381 return "TOP_RIGHT_CIRCLE"; | |
| 382 case PaintedShape::BOTTOM_RIGHT_CIRCLE: | |
| 383 return "BOTTOM_RIGHT_CIRCLE"; | |
| 384 case PaintedShape::BOTTOM_LEFT_CIRCLE: | |
| 385 return "BOTTOM_LEFT_CIRCLE"; | |
| 386 case PaintedShape::HORIZONTAL_RECT: | |
| 387 return "HORIZONTAL_RECT"; | |
| 388 case PaintedShape::VERTICAL_RECT: | |
| 389 return "VERTICAL_RECT"; | |
| 390 case PaintedShape::PAINTED_SHAPE_COUNT: | |
| 391 NOTREACHED() << "The PAINTED_SHAPE_COUNT value should never be used."; | |
| 392 return "PAINTED_SHAPE_COUNT"; | |
| 393 } | |
| 394 return "UNKNOWN"; | |
| 395 } | |
| 396 | |
| 104 void OnPaintLayer(const ui::PaintContext& context) override { | 397 void OnPaintLayer(const ui::PaintContext& context) override { |
| 105 // Radius is based on the parent layer size, the shadow layer is expanded | 398 // Radius is based on the parent layer size, the shadow layer is expanded |
| 106 // to make room for the shadow. | 399 // to make room for the shadow. |
| 107 float radius = size().width() / 2.f; | 400 float radius = size().width() / 2.f; |
| 108 | 401 |
| 109 ui::PaintRecorder recorder(context, shadow_layer_->size()); | 402 ui::PaintRecorder recorder(context, shadow_layer_->size()); |
| 110 gfx::Canvas* canvas = recorder.canvas(); | 403 gfx::Canvas* canvas = recorder.canvas(); |
| 111 | 404 |
| 112 cc::PaintFlags flags; | 405 cc::PaintFlags flags; |
| 113 flags.setColor(SK_ColorWHITE); | 406 flags.setColor(SK_ColorWHITE); |
| 114 flags.setAntiAlias(true); | 407 flags.setAntiAlias(true); |
| 115 flags.setStyle(cc::PaintFlags::kFill_Style); | 408 flags.setStyle(cc::PaintFlags::kFill_Style); |
| 116 flags.setLooper(gfx::CreateShadowDrawLooper(shadow_values_)); | 409 flags.setLooper(gfx::CreateShadowDrawLooper(shadow_values_)); |
| 117 gfx::Rect shadow_bounds = shadow_layer_->bounds(); | 410 gfx::Rect shadow_bounds = shadow_layer_->bounds(); |
| 118 canvas->DrawCircle( | 411 canvas->DrawCircle( |
| 119 gfx::PointF(radius - shadow_bounds.x(), radius - shadow_bounds.y()), | 412 gfx::PointF(radius - shadow_bounds.x(), radius - shadow_bounds.y()), |
| 120 radius, flags); | 413 radius, flags); |
| 121 } | 414 } |
| 122 | 415 |
| 123 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} | 416 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} |
| 124 | 417 |
| 125 void OnDeviceScaleFactorChanged(float device_scale_factor) override {} | 418 void OnDeviceScaleFactorChanged(float device_scale_factor) override {} |
| 126 | 419 |
| 420 // ui::Layers for all of the painted shape layers that compose the morphing | |
| 421 // shape. | |
| 422 std::unique_ptr<ui::Layer> | |
| 423 painted_layers_[static_cast<int>(PaintedShape::PAINTED_SHAPE_COUNT)]; | |
|
oshima
2017/07/06 22:04:42
alternatively, you can do
std::map<PaintedShape,
xc
2017/07/07 16:38:15
isn't map much slower than just indexing an array?
oshima
2017/07/07 19:15:39
std::map is implemented as a tree and accessing it
xc
2017/07/07 23:35:39
changed back to enum as discussed offline.
| |
| 424 | |
| 425 const gfx::Size large_size_; | |
| 426 | |
| 427 const gfx::Size small_size_; | |
|
oshima
2017/07/06 22:04:42
looks like SizeF is better choice?
xc
2017/07/07 16:38:15
I have to use this to set the layer bounds, which
| |
| 428 | |
| 429 // The center point of the painted shape. | |
| 430 gfx::PointF center_point_; | |
| 431 | |
| 432 // ui::LayerDelegate to paint circles for all the circle layers. | |
| 433 std::unique_ptr<views::CircleLayerDelegate> circle_layer_delegate_; | |
| 434 | |
| 435 // ui::LayerDelegate to paint rectangles for all the rectangle layers. | |
| 436 std::unique_ptr<views::RectangleLayerDelegate> rect_layer_delegate_; | |
| 437 | |
| 127 gfx::ShadowValues shadow_values_; | 438 gfx::ShadowValues shadow_values_; |
| 128 | 439 |
| 129 std::unique_ptr<ui::Layer> shadow_layer_; | 440 std::unique_ptr<ui::Layer> shadow_layer_; |
| 130 | 441 |
| 131 DISALLOW_COPY_AND_ASSIGN(VoiceInteractionIconBackground); | 442 DISALLOW_COPY_AND_ASSIGN(VoiceInteractionIconBackground); |
| 132 }; | 443 }; |
| 133 | 444 |
| 134 class VoiceInteractionIcon : public ui::Layer, public ui::LayerDelegate { | |
| 135 public: | |
| 136 VoiceInteractionIcon() { | |
| 137 set_name("VoiceInteractionOverlay:ICON_LAYER"); | |
| 138 SetBounds(gfx::Rect(0, 0, kIconInitSizeDip, kIconInitSizeDip)); | |
| 139 SetFillsBoundsOpaquely(false); | |
| 140 SetMasksToBounds(false); | |
| 141 set_delegate(this); | |
| 142 } | |
| 143 | |
| 144 private: | |
| 145 void OnPaintLayer(const ui::PaintContext& context) override { | |
| 146 ui::PaintRecorder recorder(context, size()); | |
| 147 gfx::PaintVectorIcon(recorder.canvas(), kShelfVoiceInteractionIcon, | |
| 148 kIconInitSizeDip, 0); | |
| 149 } | |
| 150 | |
| 151 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} | |
| 152 | |
| 153 void OnDeviceScaleFactorChanged(float device_scale_factor) override {} | |
| 154 | |
| 155 DISALLOW_COPY_AND_ASSIGN(VoiceInteractionIcon); | |
| 156 }; | |
| 157 } // namespace | |
| 158 | |
| 159 VoiceInteractionOverlay::VoiceInteractionOverlay(AppListButton* host_view) | 445 VoiceInteractionOverlay::VoiceInteractionOverlay(AppListButton* host_view) |
| 160 : ripple_layer_(new ui::Layer()), | 446 : ripple_layer_(new ui::Layer()), |
| 161 icon_layer_(new VoiceInteractionIcon()), | 447 icon_layer_(new VoiceInteractionIcon()), |
| 162 background_layer_(new VoiceInteractionIconBackground()), | 448 background_layer_(new VoiceInteractionIconBackground()), |
| 163 host_view_(host_view), | 449 host_view_(host_view), |
| 164 is_bursting_(false), | 450 is_bursting_(false), |
|
oshima
2017/07/06 22:04:42
initialize show_icons_ and should_hide_animation_
xc
2017/07/07 16:38:15
Done. Generally is it preferred to init here or in
oshima
2017/07/07 19:15:38
I usually initialize bool/(null)pointer in header,
xc
2017/07/07 23:35:39
Acknowledged.
| |
| 165 circle_layer_delegate_(kRippleColor, kRippleCircleInitRadiusDip) { | 451 circle_layer_delegate_(kRippleColor, kRippleCircleInitRadiusDip) { |
| 166 SetPaintToLayer(ui::LAYER_NOT_DRAWN); | 452 SetPaintToLayer(ui::LAYER_NOT_DRAWN); |
| 167 layer()->set_name("VoiceInteractionOverlay:ROOT_LAYER"); | 453 layer()->set_name("VoiceInteractionOverlay:ROOT_LAYER"); |
| 168 layer()->SetMasksToBounds(false); | 454 layer()->SetMasksToBounds(false); |
| 169 | 455 |
| 170 ripple_layer_->SetBounds(gfx::Rect(0, 0, kRippleCircleInitRadiusDip * 2, | 456 ripple_layer_->SetBounds(gfx::Rect(0, 0, kRippleCircleInitRadiusDip * 2, |
| 171 kRippleCircleInitRadiusDip * 2)); | 457 kRippleCircleInitRadiusDip * 2)); |
| 172 ripple_layer_->set_delegate(&circle_layer_delegate_); | 458 ripple_layer_->set_delegate(&circle_layer_delegate_); |
| 173 ripple_layer_->SetFillsBoundsOpaquely(false); | 459 ripple_layer_->SetFillsBoundsOpaquely(false); |
| 174 ripple_layer_->SetMasksToBounds(true); | 460 ripple_layer_->SetMasksToBounds(true); |
| 175 ripple_layer_->set_name("VoiceInteractionOverlay:PAINTED_LAYER"); | 461 ripple_layer_->set_name("VoiceInteractionOverlay:PAINTED_LAYER"); |
| 176 layer()->Add(ripple_layer_.get()); | 462 layer()->Add(ripple_layer_.get()); |
| 177 | 463 |
| 178 layer()->Add(background_layer_.get()); | 464 layer()->Add(background_layer_.get()); |
| 179 | 465 |
| 180 layer()->Add(icon_layer_.get()); | 466 layer()->Add(icon_layer_.get()); |
| 181 } | 467 } |
| 182 | 468 |
| 183 VoiceInteractionOverlay::~VoiceInteractionOverlay() {} | 469 VoiceInteractionOverlay::~VoiceInteractionOverlay() {} |
| 184 | 470 |
| 185 void VoiceInteractionOverlay::StartAnimation() { | 471 void VoiceInteractionOverlay::StartAnimation(bool show_icon) { |
| 186 is_bursting_ = false; | 472 is_bursting_ = false; |
| 473 show_icon_ = show_icon; | |
| 187 SetVisible(true); | 474 SetVisible(true); |
| 188 | 475 |
| 189 // Setup ripple initial state. | 476 // Setup ripple initial state. |
| 190 ripple_layer_->SetOpacity(0); | 477 ripple_layer_->SetOpacity(0); |
| 191 | 478 |
| 192 SkMScalar scale_factor = | 479 SkMScalar scale_factor = |
| 193 kRippleCircleStartRadiusDip / kRippleCircleInitRadiusDip; | 480 kRippleCircleStartRadiusDip / kRippleCircleInitRadiusDip; |
| 194 gfx::Transform transform; | 481 gfx::Transform transform; |
| 195 | 482 |
| 196 const gfx::Point center = host_view_->GetCenterPoint(); | 483 const gfx::Point center = host_view_->GetCenterPoint(); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 212 base::TimeDelta::FromMilliseconds(kRippleExpandDurationMs)); | 499 base::TimeDelta::FromMilliseconds(kRippleExpandDurationMs)); |
| 213 settings.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN_2); | 500 settings.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN_2); |
| 214 | 501 |
| 215 ripple_layer_->SetTransform(transform); | 502 ripple_layer_->SetTransform(transform); |
| 216 | 503 |
| 217 settings.SetTransitionDuration( | 504 settings.SetTransitionDuration( |
| 218 base::TimeDelta::FromMilliseconds(kRippleOpacityDurationMs)); | 505 base::TimeDelta::FromMilliseconds(kRippleOpacityDurationMs)); |
| 219 ripple_layer_->SetOpacity(kRippleOpacity); | 506 ripple_layer_->SetOpacity(kRippleOpacity); |
| 220 } | 507 } |
| 221 | 508 |
| 222 // We need to determine the animation direction based on shelf alignment. | 509 icon_layer_->SetOpacity(0); |
| 223 ShelfAlignment alignment = | 510 background_layer_->SetOpacity(0); |
| 224 Shelf::ForWindow(host_view_->GetWidget()->GetNativeWindow())->alignment(); | 511 if (!show_icon_) |
| 512 return; | |
| 225 | 513 |
| 226 // Setup icon initial state. | 514 // Setup icon initial state. |
| 227 icon_layer_->SetOpacity(0); | |
| 228 transform.MakeIdentity(); | 515 transform.MakeIdentity(); |
| 229 | |
| 230 transform.Translate(center.x() - kIconStartSizeDip / 2.f, | 516 transform.Translate(center.x() - kIconStartSizeDip / 2.f, |
| 231 center.y() - kIconStartSizeDip / 2.f); | 517 center.y() - kIconStartSizeDip / 2.f); |
| 232 | 518 |
| 233 scale_factor = kIconStartSizeDip / kIconInitSizeDip; | 519 scale_factor = kIconStartSizeDip / kIconInitSizeDip; |
| 234 transform.Scale(scale_factor, scale_factor); | 520 transform.Scale(scale_factor, scale_factor); |
| 235 icon_layer_->SetTransform(transform); | 521 icon_layer_->SetTransform(transform); |
| 236 | 522 |
| 237 // Setup icon animation. | 523 // Setup icon animation. |
| 238 scale_factor = kIconSizeDip / kIconInitSizeDip; | 524 scale_factor = kIconSizeDip / kIconInitSizeDip; |
| 239 transform.MakeIdentity(); | 525 transform.MakeIdentity(); |
| 240 if (alignment == SHELF_ALIGNMENT_BOTTOM || | 526 transform.Translate(center.x() - kIconSizeDip / 2 + kIconOffsetDip, |
| 241 alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED) { | 527 center.y() - kIconSizeDip / 2 - kIconOffsetDip); |
| 242 transform.Translate(center.x() - kIconSizeDip / 2 + kIconOffsetDip, | |
| 243 center.y() - kIconSizeDip / 2 - kIconOffsetDip); | |
| 244 } else if (alignment == SHELF_ALIGNMENT_RIGHT) { | |
| 245 transform.Translate(center.x() - kIconSizeDip / 2 - kIconOffsetDip, | |
| 246 center.y() - kIconSizeDip / 2 + kIconOffsetDip); | |
| 247 } else { | |
| 248 DCHECK_EQ(alignment, SHELF_ALIGNMENT_LEFT); | |
| 249 transform.Translate(center.x() - kIconSizeDip / 2 + kIconOffsetDip, | |
| 250 center.y() - kIconSizeDip / 2 + kIconOffsetDip); | |
| 251 } | |
| 252 transform.Scale(scale_factor, scale_factor); | 528 transform.Scale(scale_factor, scale_factor); |
| 253 | 529 |
| 254 { | 530 { |
| 255 ui::ScopedLayerAnimationSettings settings(icon_layer_->GetAnimator()); | 531 ui::ScopedLayerAnimationSettings settings(icon_layer_->GetAnimator()); |
| 256 settings.SetTransitionDuration( | 532 settings.SetTransitionDuration( |
| 257 base::TimeDelta::FromMilliseconds(kFullExpandDurationMs)); | 533 base::TimeDelta::FromMilliseconds(kFullExpandDurationMs)); |
| 258 settings.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN_2); | 534 settings.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN_2); |
| 259 | 535 |
| 260 icon_layer_->SetTransform(transform); | 536 icon_layer_->SetTransform(transform); |
| 261 icon_layer_->SetOpacity(kIconOpacity); | 537 icon_layer_->SetOpacity(kIconOpacity); |
| 262 } | 538 } |
| 263 | 539 |
| 264 // Setup background initial state. | 540 // Setup background initial state. |
| 265 background_layer_->SetOpacity(0); | 541 background_layer_->ResetShape(); |
| 266 | 542 |
| 267 transform.MakeIdentity(); | 543 transform.MakeIdentity(); |
| 268 transform.Translate(center.x() - kBackgroundStartSizeDip / 2.f, | 544 transform.Translate(center.x() - kBackgroundStartSizeDip / 2.f, |
| 269 center.y() - kBackgroundStartSizeDip / 2.f); | 545 center.y() - kBackgroundStartSizeDip / 2.f); |
| 270 | 546 |
| 271 scale_factor = kBackgroundStartSizeDip / kBackgroundInitSizeDip; | 547 scale_factor = kBackgroundStartSizeDip / kBackgroundInitSizeDip; |
| 272 transform.Scale(scale_factor, scale_factor); | 548 transform.Scale(scale_factor, scale_factor); |
| 273 background_layer_->SetTransform(transform); | 549 background_layer_->SetTransform(transform); |
| 274 | 550 |
| 275 // Setup background animation. | 551 // Setup background animation. |
| 276 scale_factor = kBackgroundSizeDip / kBackgroundInitSizeDip; | 552 scale_factor = kBackgroundSizeDip / kBackgroundInitSizeDip; |
| 277 transform.MakeIdentity(); | 553 transform.MakeIdentity(); |
| 278 if (alignment == SHELF_ALIGNMENT_BOTTOM || | 554 transform.Translate(center.x() - kBackgroundSizeDip / 2 + kIconOffsetDip, |
| 279 alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED) { | 555 center.y() - kBackgroundSizeDip / 2 - kIconOffsetDip); |
| 280 transform.Translate(center.x() - kBackgroundSizeDip / 2 + kIconOffsetDip, | |
| 281 center.y() - kBackgroundSizeDip / 2 - kIconOffsetDip); | |
| 282 } else if (alignment == SHELF_ALIGNMENT_RIGHT) { | |
| 283 transform.Translate(center.x() - kBackgroundSizeDip / 2 - kIconOffsetDip, | |
| 284 center.y() - kBackgroundSizeDip / 2 + kIconOffsetDip); | |
| 285 } else { | |
| 286 DCHECK_EQ(alignment, SHELF_ALIGNMENT_LEFT); | |
| 287 transform.Translate(center.x() - kBackgroundSizeDip / 2 + kIconOffsetDip, | |
| 288 center.y() - kBackgroundSizeDip / 2 + kIconOffsetDip); | |
| 289 } | |
| 290 transform.Scale(scale_factor, scale_factor); | 556 transform.Scale(scale_factor, scale_factor); |
| 291 | 557 |
| 292 { | 558 { |
| 293 ui::ScopedLayerAnimationSettings settings(background_layer_->GetAnimator()); | 559 ui::ScopedLayerAnimationSettings settings(background_layer_->GetAnimator()); |
| 294 settings.SetTransitionDuration( | 560 settings.SetTransitionDuration( |
| 295 base::TimeDelta::FromMilliseconds(kFullExpandDurationMs)); | 561 base::TimeDelta::FromMilliseconds(kFullExpandDurationMs)); |
| 296 settings.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN_2); | 562 settings.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN_2); |
| 297 | 563 |
| 298 background_layer_->SetTransform(transform); | 564 background_layer_->SetTransform(transform); |
| 299 } | 565 } |
| 300 | 566 |
| 301 { | 567 { |
| 302 ui::ScopedLayerAnimationSettings settings(background_layer_->GetAnimator()); | 568 ui::ScopedLayerAnimationSettings settings(background_layer_->GetAnimator()); |
| 303 settings.SetTransitionDuration( | 569 settings.SetTransitionDuration( |
| 304 base::TimeDelta::FromMilliseconds(kBackgroundOpacityDurationMs)); | 570 base::TimeDelta::FromMilliseconds(kBackgroundOpacityDurationMs)); |
| 305 settings.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN_2); | 571 settings.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN_2); |
| 306 | 572 |
| 307 background_layer_->SetOpacity(1); | 573 background_layer_->SetOpacity(1); |
| 308 } | 574 } |
| 309 } | 575 } |
| 310 | 576 |
| 311 void VoiceInteractionOverlay::BurstAnimation() { | 577 void VoiceInteractionOverlay::BurstAnimation() { |
| 312 is_bursting_ = true; | 578 is_bursting_ = true; |
| 579 should_hide_animation_ = false; | |
| 313 | 580 |
| 314 gfx::Point center = host_view_->GetCenterPoint(); | 581 gfx::Point center = host_view_->GetCenterPoint(); |
| 582 gfx::Transform transform; | |
| 315 | 583 |
| 316 // Setup ripple animations. | 584 // Setup ripple animations. |
| 317 { | 585 { |
| 318 SkMScalar scale_factor = | 586 SkMScalar scale_factor = |
| 319 kRippleCircleBurstRadiusDip / kRippleCircleInitRadiusDip; | 587 kRippleCircleBurstRadiusDip / kRippleCircleInitRadiusDip; |
| 320 std::unique_ptr<gfx::Transform> transform(new gfx::Transform()); | 588 transform.Translate(center.x() - kRippleCircleBurstRadiusDip, |
| 321 transform->Translate(center.x() - kRippleCircleBurstRadiusDip, | 589 center.y() - kRippleCircleBurstRadiusDip); |
| 322 center.y() - kRippleCircleBurstRadiusDip); | 590 transform.Scale(scale_factor, scale_factor); |
| 323 transform->Scale(scale_factor, scale_factor); | |
| 324 | 591 |
| 325 ui::ScopedLayerAnimationSettings settings(ripple_layer_->GetAnimator()); | 592 ui::ScopedLayerAnimationSettings settings(ripple_layer_->GetAnimator()); |
| 326 settings.SetTransitionDuration( | 593 settings.SetTransitionDuration( |
| 327 base::TimeDelta::FromMilliseconds(kFullBurstDurationMs)); | 594 base::TimeDelta::FromMilliseconds(kFullBurstDurationMs)); |
| 328 settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN); | 595 settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN); |
| 596 settings.SetPreemptionStrategy( | |
| 597 ui::LayerAnimator::PreemptionStrategy::ENQUEUE_NEW_ANIMATION); | |
| 329 | 598 |
| 330 ripple_layer_->SetTransform(*transform.get()); | 599 ripple_layer_->SetTransform(transform); |
| 331 ripple_layer_->SetOpacity(0); | 600 ripple_layer_->SetOpacity(0); |
| 332 } | 601 } |
| 333 | 602 |
| 603 if (!show_icon_) | |
| 604 return; | |
| 605 | |
| 334 // Setup icon animation. | 606 // Setup icon animation. |
| 335 { | 607 { |
| 336 ui::ScopedLayerAnimationSettings settings(icon_layer_->GetAnimator()); | 608 ui::ScopedLayerAnimationSettings settings(icon_layer_->GetAnimator()); |
| 337 settings.SetTransitionDuration( | 609 settings.SetTransitionDuration( |
| 338 base::TimeDelta::FromMilliseconds(kIconBurstDurationMs)); | 610 base::TimeDelta::FromMilliseconds(kBackgroundMorphDurationMs)); |
| 611 settings.SetPreemptionStrategy( | |
| 612 ui::LayerAnimator::PreemptionStrategy::ENQUEUE_NEW_ANIMATION); | |
| 339 settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN); | 613 settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN); |
| 340 | 614 |
| 341 icon_layer_->SetOpacity(0); | 615 transform.MakeIdentity(); |
| 616 transform.Translate(kBackgroundLargeWidthDip / 2 + kBackgroundPaddingDip - | |
| 617 kIconEndSizeDip / 2, | |
| 618 -kBackgroundLargeHeightDip / 2 - kBackgroundPaddingDip - | |
| 619 kIconEndSizeDip / 2); | |
| 620 SkMScalar scale_factor = kIconEndSizeDip / kIconInitSizeDip; | |
| 621 transform.Scale(scale_factor, scale_factor); | |
| 622 | |
| 623 icon_layer_->SetTransform(transform); | |
| 342 } | 624 } |
| 343 | 625 |
| 344 // Setup background animation. | 626 // Setup background animation. |
| 345 { | 627 ui::CallbackLayerAnimationObserver* observer = |
| 346 ui::ScopedLayerAnimationSettings settings(background_layer_->GetAnimator()); | 628 new ui::CallbackLayerAnimationObserver( |
| 347 settings.SetTransitionDuration( | 629 base::Bind(&VoiceInteractionOverlay::AnimationEndedCallback, |
| 348 base::TimeDelta::FromMilliseconds(kIconBurstDurationMs)); | 630 base::Unretained(this))); |
| 349 settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN); | 631 // Transform to new shape. |
| 632 // We want to animate from the background's current position into a larger | |
| 633 // size. The animation moves the background's center point while morphing from | |
| 634 // circle to a rectangle. | |
| 635 float x_offset = center.x() - kBackgroundSizeDip / 2 + kIconOffsetDip; | |
| 636 float y_offset = center.y() - kBackgroundSizeDip / 2 - kIconOffsetDip; | |
| 350 | 637 |
| 351 background_layer_->SetOpacity(0); | 638 background_layer_->AnimateToLarge( |
| 352 } | 639 gfx::PointF( |
| 640 kBackgroundLargeWidthDip / 2 + kBackgroundPaddingDip - x_offset, | |
| 641 -kBackgroundLargeHeightDip / 2 - kBackgroundPaddingDip - y_offset), | |
| 642 observer); | |
| 643 observer->SetActive(); | |
| 353 } | 644 } |
| 354 | 645 |
| 355 void VoiceInteractionOverlay::EndAnimation() { | 646 void VoiceInteractionOverlay::EndAnimation() { |
| 356 if (is_bursting_) { | 647 if (is_bursting_) { |
| 357 // Too late, user action already fired, we have to finish what's started. | 648 // Too late, user action already fired, we have to finish what's started. |
| 358 return; | 649 return; |
| 359 } | 650 } |
| 360 | 651 |
| 361 // Play reverse animation | 652 // Play reverse animation |
| 362 // Setup ripple animations. | 653 // Setup ripple animations. |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 377 base::TimeDelta::FromMilliseconds(kFullRetractDurationMs)); | 668 base::TimeDelta::FromMilliseconds(kFullRetractDurationMs)); |
| 378 settings.SetTweenType(gfx::Tween::SLOW_OUT_LINEAR_IN); | 669 settings.SetTweenType(gfx::Tween::SLOW_OUT_LINEAR_IN); |
| 379 | 670 |
| 380 ripple_layer_->SetTransform(transform); | 671 ripple_layer_->SetTransform(transform); |
| 381 | 672 |
| 382 settings.SetTransitionDuration( | 673 settings.SetTransitionDuration( |
| 383 base::TimeDelta::FromMilliseconds(kRippleOpacityRetractDurationMs)); | 674 base::TimeDelta::FromMilliseconds(kRippleOpacityRetractDurationMs)); |
| 384 ripple_layer_->SetOpacity(0); | 675 ripple_layer_->SetOpacity(0); |
| 385 } | 676 } |
| 386 | 677 |
| 678 if (!show_icon_) | |
| 679 return; | |
| 680 | |
| 387 // Setup icon animation. | 681 // Setup icon animation. |
| 388 transform.MakeIdentity(); | 682 transform.MakeIdentity(); |
| 389 | 683 |
| 390 transform.Translate(center.x() - kIconStartSizeDip / 2.f, | 684 transform.Translate(center.x() - kIconStartSizeDip / 2.f, |
| 391 center.y() - kIconStartSizeDip / 2.f); | 685 center.y() - kIconStartSizeDip / 2.f); |
| 392 | 686 |
| 393 scale_factor = kIconStartSizeDip / kIconInitSizeDip; | 687 scale_factor = kIconStartSizeDip / kIconInitSizeDip; |
| 394 transform.Scale(scale_factor, scale_factor); | 688 transform.Scale(scale_factor, scale_factor); |
| 395 | 689 |
| 396 { | 690 { |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 420 IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | 714 IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| 421 settings.SetTransitionDuration( | 715 settings.SetTransitionDuration( |
| 422 base::TimeDelta::FromMilliseconds(kFullRetractDurationMs)); | 716 base::TimeDelta::FromMilliseconds(kFullRetractDurationMs)); |
| 423 settings.SetTweenType(gfx::Tween::SLOW_OUT_LINEAR_IN); | 717 settings.SetTweenType(gfx::Tween::SLOW_OUT_LINEAR_IN); |
| 424 | 718 |
| 425 background_layer_->SetTransform(transform); | 719 background_layer_->SetTransform(transform); |
| 426 background_layer_->SetOpacity(0); | 720 background_layer_->SetOpacity(0); |
| 427 } | 721 } |
| 428 } | 722 } |
| 429 | 723 |
| 724 void VoiceInteractionOverlay::HideAnimation() { | |
| 725 is_bursting_ = false; | |
| 726 | |
| 727 should_hide_animation_ = true; | |
|
oshima
2017/07/06 22:04:42
should this be inside following if, and reset afte
xc
2017/07/07 16:38:15
Done.
| |
| 728 if (background_layer_->GetAnimator()->is_animating()) { | |
| 729 // Wait for current animation to finish | |
| 730 return; | |
| 731 } | |
| 732 | |
| 733 // Setup ripple animations. | |
| 734 { | |
| 735 ui::ScopedLayerAnimationSettings settings(ripple_layer_->GetAnimator()); | |
| 736 settings.SetTransitionDuration( | |
| 737 base::TimeDelta::FromMilliseconds(kHideDurationMs)); | |
| 738 settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN); | |
| 739 settings.SetPreemptionStrategy( | |
| 740 ui::LayerAnimator::PreemptionStrategy::ENQUEUE_NEW_ANIMATION); | |
| 741 | |
| 742 ripple_layer_->SetOpacity(0); | |
| 743 } | |
| 744 | |
| 745 // Setup icon animation. | |
| 746 { | |
| 747 ui::ScopedLayerAnimationSettings settings(icon_layer_->GetAnimator()); | |
| 748 settings.SetTransitionDuration( | |
| 749 base::TimeDelta::FromMilliseconds(kHideDurationMs)); | |
| 750 settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN); | |
| 751 settings.SetPreemptionStrategy( | |
| 752 ui::LayerAnimator::PreemptionStrategy::ENQUEUE_NEW_ANIMATION); | |
| 753 | |
| 754 icon_layer_->SetOpacity(0); | |
| 755 } | |
| 756 | |
| 757 // Setup background animation. | |
| 758 { | |
| 759 ui::ScopedLayerAnimationSettings settings(background_layer_->GetAnimator()); | |
| 760 settings.SetTransitionDuration( | |
| 761 base::TimeDelta::FromMilliseconds(kHideDurationMs)); | |
| 762 settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN); | |
| 763 settings.SetPreemptionStrategy( | |
| 764 ui::LayerAnimator::PreemptionStrategy::ENQUEUE_NEW_ANIMATION); | |
| 765 | |
| 766 background_layer_->SetOpacity(0); | |
| 767 } | |
| 768 } | |
| 769 | |
| 770 bool VoiceInteractionOverlay::AnimationEndedCallback( | |
| 771 const ui::CallbackLayerAnimationObserver& observer) { | |
| 772 if (should_hide_animation_) | |
| 773 HideAnimation(); | |
| 774 | |
| 775 return true; | |
| 776 } | |
| 777 | |
| 430 } // namespace ash | 778 } // namespace ash |
| OLD | NEW |