OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view
.h" | 5 #include "chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view
.h" |
6 | 6 |
7 #include "ash/display/window_tree_host_manager.h" | 7 #include "ash/display/window_tree_host_manager.h" |
8 #include "ash/public/cpp/shell_window_ids.h" | 8 #include "ash/public/cpp/shell_window_ids.h" |
9 #include "ash/shell.h" | 9 #include "ash/shell.h" |
10 #include "ui/aura/window.h" | 10 #include "ui/aura/window.h" |
11 #include "ui/base/resource/resource_bundle.h" | 11 #include "ui/base/resource/resource_bundle.h" |
12 #include "ui/gfx/animation/linear_animation.h" | 12 #include "ui/gfx/animation/linear_animation.h" |
| 13 #include "ui/gfx/animation/throb_animation.h" |
13 #include "ui/gfx/canvas.h" | 14 #include "ui/gfx/canvas.h" |
14 #include "ui/strings/grit/ui_strings.h" | 15 #include "ui/strings/grit/ui_strings.h" |
15 #include "ui/views/controls/label.h" | 16 #include "ui/views/controls/label.h" |
16 #include "ui/views/widget/widget.h" | 17 #include "ui/views/widget/widget.h" |
17 | 18 |
18 namespace chromeos { | 19 namespace chromeos { |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
22 constexpr char kWidgetName[] = "TouchCalibratorOverlay"; | 23 constexpr char kWidgetName[] = "TouchCalibratorOverlay"; |
23 | 24 |
24 constexpr int kAnimationFrameRate = 100; | 25 constexpr int kAnimationFrameRate = 100; |
25 constexpr int kFadeDurationInMs = 150; | 26 constexpr int kFadeDurationInMs = 150; |
26 | 27 |
27 const SkColor kExitLabelColor = SkColorSetARGBInline(255, 96, 96, 96); | 28 const SkColor kExitLabelColor = SkColorSetARGBInline(255, 96, 96, 96); |
28 const SkColor kExitLabelShadowColor = SkColorSetARGBInline(255, 11, 11, 11); | 29 const SkColor kExitLabelShadowColor = SkColorSetARGBInline(255, 11, 11, 11); |
29 constexpr int kExitLabelWidth = 300; | 30 constexpr int kExitLabelWidth = 300; |
30 constexpr int kExitLabelHeight = 20; | 31 constexpr int kExitLabelHeight = 20; |
31 | 32 |
| 33 constexpr int kHintBoxWidth = 298; |
| 34 constexpr int kHintBoxHeight = 180; |
| 35 constexpr int kHintBoxLabelTextSize = 5; |
| 36 constexpr int kHintBoxSublabelTextSize = 3; |
| 37 |
| 38 constexpr int kThrobberCircleViewWidth = 128; |
| 39 constexpr float kThrobberCircleRadiusFactor = 3.f / 8.f; |
| 40 |
| 41 constexpr int kTouchPointViewOffset = 100; |
| 42 |
| 43 constexpr int kTapLabelHeight = 48; |
| 44 |
| 45 const SkColor kHintLabelTextColor = SK_ColorBLACK; |
| 46 const SkColor kHintSublabelTextColor = SkColorSetARGBInline(255, 161, 161, 161); |
| 47 |
| 48 const SkColor kInnerCircleColor = SK_ColorWHITE; |
| 49 const SkColor kOuterCircleColor = SkColorSetA(kInnerCircleColor, 128); |
| 50 |
| 51 constexpr int kCircleAnimationDurationMs = 900; |
| 52 |
| 53 constexpr int kHintRectBorderRadius = 10; |
| 54 |
32 constexpr float kBackgroundFinalOpacity = 0.75f; | 55 constexpr float kBackgroundFinalOpacity = 0.75f; |
33 | 56 |
34 // Returns the initialization params for the widget that contains the touch | 57 // Returns the initialization params for the widget that contains the touch |
35 // calibrator view. | 58 // calibrator view. |
36 views::Widget::InitParams GetWidgetParams(aura::Window* root_window) { | 59 views::Widget::InitParams GetWidgetParams(aura::Window* root_window) { |
37 views::Widget::InitParams params; | 60 views::Widget::InitParams params; |
38 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; | 61 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; |
39 params.name = kWidgetName; | 62 params.name = kWidgetName; |
40 params.keep_on_top = true; | 63 params.keep_on_top = true; |
41 params.accept_events = true; | 64 params.accept_events = true; |
42 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; | 65 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; |
43 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 66 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
44 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | 67 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
45 params.parent = ash::Shell::GetContainer( | 68 params.parent = ash::Shell::GetContainer( |
46 root_window, ash::kShellWindowId_OverlayContainer); | 69 root_window, ash::kShellWindowId_OverlayContainer); |
47 return params; | 70 return params; |
48 } | 71 } |
49 | 72 |
| 73 // Returns the size of bounding box required for |text| of given |font_list|. |
| 74 gfx::Size GetSizeForString(const base::string16& text, |
| 75 const gfx::FontList& font_list) { |
| 76 int height, width; |
| 77 gfx::Canvas::SizeStringInt(text, font_list, &width, &height, 0, 0); |
| 78 return gfx::Size(width, height); |
| 79 } |
| 80 |
50 } // namespace | 81 } // namespace |
51 | 82 |
| 83 // Creates a throbbing animated view with two concentric circles. The radius of |
| 84 // the inner circle is fixed while that of the outer circle oscillates between a |
| 85 // min and max radius. The animation takes |animation_duration| milliseconds |
| 86 // to complete. The center of these circles are at the center of the view |
| 87 // element. |
| 88 class CircularThrobberView : public views::View, public gfx::AnimationDelegate { |
| 89 public: |
| 90 CircularThrobberView(int width, |
| 91 const SkColor& inner_circle_color, |
| 92 const SkColor& outer_circle_color, |
| 93 int animation_duration); |
| 94 ~CircularThrobberView() override; |
| 95 |
| 96 // views::View overrides: |
| 97 void OnPaint(gfx::Canvas* canvas) override; |
| 98 |
| 99 // gfx::AnimationDelegate overrides: |
| 100 void AnimationProgressed(const gfx::Animation* animation) override; |
| 101 |
| 102 private: |
| 103 // Radius of the inner circle. |
| 104 const int inner_radius_; |
| 105 |
| 106 // Current radius of the outer circle. |
| 107 int outer_radius_; |
| 108 |
| 109 // Minimum radius for outer animated circle. |
| 110 const int smallest_radius_animated_circle_; |
| 111 |
| 112 // Maximum radius for outer animated circle. |
| 113 const int largest_radius_animated_circle_; |
| 114 |
| 115 SkPaint inner_circle_paint_; |
| 116 SkPaint outer_circle_paint_; |
| 117 |
| 118 std::unique_ptr<gfx::ThrobAnimation> animation_; |
| 119 |
| 120 // Center of the concentric circles. |
| 121 const gfx::Point center_; |
| 122 |
| 123 DISALLOW_COPY_AND_ASSIGN(CircularThrobberView); |
| 124 }; |
| 125 |
| 126 CircularThrobberView::CircularThrobberView(int width, |
| 127 const SkColor& inner_circle_color, |
| 128 const SkColor& outer_circle_color, |
| 129 int animation_duration) |
| 130 : inner_radius_(width / 4), |
| 131 outer_radius_(inner_radius_), |
| 132 smallest_radius_animated_circle_(width * kThrobberCircleRadiusFactor), |
| 133 largest_radius_animated_circle_(width / 2), |
| 134 center_(gfx::Point(width / 2, width / 2)) { |
| 135 SetSize(gfx::Size(width, width)); |
| 136 |
| 137 inner_circle_paint_.setColor(inner_circle_color); |
| 138 inner_circle_paint_.setStyle(SkPaint::kFill_Style); |
| 139 inner_circle_paint_.setFlags(SkPaint::kAntiAlias_Flag); |
| 140 |
| 141 outer_circle_paint_.setColor(outer_circle_color); |
| 142 outer_circle_paint_.setStyle(SkPaint::kFill_Style); |
| 143 outer_circle_paint_.setFlags(SkPaint::kAntiAlias_Flag); |
| 144 |
| 145 animation_.reset(new gfx::ThrobAnimation(this)); |
| 146 animation_->SetThrobDuration(animation_duration); |
| 147 animation_->StartThrobbing(-1); |
| 148 |
| 149 SchedulePaint(); |
| 150 } |
| 151 |
| 152 CircularThrobberView::~CircularThrobberView() {} |
| 153 |
| 154 void CircularThrobberView::OnPaint(gfx::Canvas* canvas) { |
| 155 canvas->DrawCircle(center_, outer_radius_, outer_circle_paint_); |
| 156 canvas->DrawCircle(center_, inner_radius_, inner_circle_paint_); |
| 157 } |
| 158 |
| 159 void CircularThrobberView::AnimationProgressed( |
| 160 const gfx::Animation* animation) { |
| 161 if (animation != animation_.get()) |
| 162 return; |
| 163 outer_radius_ = animation->CurrentValueBetween( |
| 164 smallest_radius_animated_circle_, largest_radius_animated_circle_); |
| 165 SchedulePaint(); |
| 166 } |
| 167 |
| 168 // Circular _________________________________ |
| 169 // Throbber | | |
| 170 // View | | |
| 171 // ___________ | | |
| 172 // | | | | |
| 173 // | | | | |
| 174 // | . | | Hint Box | |
| 175 // | | | | |
| 176 // |___________| | | |
| 177 // | | |
| 178 // | | |
| 179 // |_________________________________| |
| 180 // |
| 181 // This view is set next to the throbber circle view such that their centers |
| 182 // align. The hint box has a label text and a sublabel text to assist the |
| 183 // user by informing them about the next step in the calibration process. |
| 184 class HintBox : public views::View { |
| 185 public: |
| 186 HintBox(const gfx::Rect& bounds, int border_radius); |
| 187 ~HintBox() override; |
| 188 |
| 189 // views::View overrides: |
| 190 void OnPaint(gfx::Canvas* canvas) override; |
| 191 |
| 192 void SetLabel(const base::string16& text, const SkColor& color); |
| 193 void SetSubLabel(const base::string16& text, const SkColor& color); |
| 194 |
| 195 private: |
| 196 base::string16 label_text_; |
| 197 base::string16 sublabel_text_; |
| 198 |
| 199 SkColor label_color_; |
| 200 SkColor sublabel_color_; |
| 201 |
| 202 const int border_radius_; |
| 203 |
| 204 int horizontal_offset_; |
| 205 |
| 206 gfx::FontList label_font_list_; |
| 207 gfx::FontList sublabel_font_list_; |
| 208 |
| 209 gfx::Rect label_text_bounds_; |
| 210 gfx::Rect sublabel_text_bounds_; |
| 211 |
| 212 SkPaint paint_; |
| 213 |
| 214 DISALLOW_COPY_AND_ASSIGN(HintBox); |
| 215 }; |
| 216 |
| 217 HintBox::HintBox(const gfx::Rect& bounds, int border_radius) |
| 218 : border_radius_(border_radius) { |
| 219 SetBoundsRect(bounds); |
| 220 |
| 221 paint_.setColor(SK_ColorWHITE); |
| 222 paint_.setStyle(SkPaint::kFill_Style); |
| 223 paint_.setFlags(SkPaint::kAntiAlias_Flag); |
| 224 |
| 225 horizontal_offset_ = width() * 0.08f; |
| 226 int top_offset = horizontal_offset_; |
| 227 int line_gap = height() * 0.018f; |
| 228 int label_height = height() * 0.11f; |
| 229 |
| 230 label_text_bounds_.SetRect(horizontal_offset_, top_offset, 0, label_height); |
| 231 |
| 232 top_offset += label_text_bounds_.height() + line_gap; |
| 233 |
| 234 sublabel_text_bounds_.SetRect(horizontal_offset_, top_offset, 0, |
| 235 label_height); |
| 236 } |
| 237 |
| 238 HintBox::~HintBox() {} |
| 239 |
| 240 void HintBox::SetLabel(const base::string16& text, const SkColor& color) { |
| 241 label_text_ = text; |
| 242 label_color_ = color; |
| 243 |
| 244 label_font_list_ = |
| 245 ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta( |
| 246 kHintBoxLabelTextSize, gfx::Font::FontStyle::NORMAL, |
| 247 gfx::Font::Weight::NORMAL); |
| 248 |
| 249 // Adjust size of label bounds based on text and font. |
| 250 gfx::Size size = GetSizeForString(label_text_, label_font_list_); |
| 251 label_text_bounds_.set_size( |
| 252 gfx::Size(size.width(), label_text_bounds_.height())); |
| 253 |
| 254 // Check if the width of hint box needs to be updated. |
| 255 int minimum_expected_width = size.width() + 2 * horizontal_offset_; |
| 256 if (minimum_expected_width > width()) |
| 257 SetSize(gfx::Size(minimum_expected_width, height())); |
| 258 } |
| 259 |
| 260 void HintBox::SetSubLabel(const base::string16& text, const SkColor& color) { |
| 261 sublabel_text_ = text; |
| 262 sublabel_color_ = color; |
| 263 |
| 264 sublabel_font_list_ = |
| 265 ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta( |
| 266 kHintBoxSublabelTextSize, gfx::Font::FontStyle::NORMAL, |
| 267 gfx::Font::Weight::NORMAL); |
| 268 |
| 269 // Adjust size of sublabel label bounds based on text and font. |
| 270 gfx::Size size = GetSizeForString(sublabel_text_, sublabel_font_list_); |
| 271 sublabel_text_bounds_.set_size( |
| 272 gfx::Size(size.width(), sublabel_text_bounds_.height())); |
| 273 |
| 274 // Check if the width of hint box needs to be updated. |
| 275 int minimum_expected_width = size.width() + 2 * horizontal_offset_; |
| 276 if (minimum_expected_width > width()) |
| 277 SetSize(gfx::Size(minimum_expected_width, height())); |
| 278 } |
| 279 |
| 280 void HintBox::OnPaint(gfx::Canvas* canvas) { |
| 281 canvas->DrawRoundRect(GetLocalBounds(), border_radius_, paint_); |
| 282 canvas->DrawStringRectWithFlags(label_text_, label_font_list_, label_color_, |
| 283 label_text_bounds_, gfx::Canvas::NO_ELLIPSIS); |
| 284 canvas->DrawStringRectWithFlags(sublabel_text_, sublabel_font_list_, |
| 285 sublabel_color_, sublabel_text_bounds_, |
| 286 gfx::Canvas::NO_ELLIPSIS); |
| 287 } |
| 288 |
52 TouchCalibratorView::TouchCalibratorView(const display::Display& target_display, | 289 TouchCalibratorView::TouchCalibratorView(const display::Display& target_display, |
53 bool is_primary_view) | 290 bool is_primary_view) |
54 : display_(target_display), | 291 : display_(target_display), |
55 is_primary_view_(is_primary_view), | 292 is_primary_view_(is_primary_view), |
56 exit_label_(nullptr) { | 293 exit_label_(nullptr), |
| 294 throbber_circle_(nullptr), |
| 295 hint_box_view_(nullptr), |
| 296 touch_point_view_(nullptr) { |
57 aura::Window* root = ash::Shell::GetInstance() | 297 aura::Window* root = ash::Shell::GetInstance() |
58 ->window_tree_host_manager() | 298 ->window_tree_host_manager() |
59 ->GetRootWindowForDisplayId(display_.id()); | 299 ->GetRootWindowForDisplayId(display_.id()); |
60 widget_.reset(new views::Widget); | 300 widget_.reset(new views::Widget); |
61 widget_->Init(GetWidgetParams(root)); | 301 widget_->Init(GetWidgetParams(root)); |
62 widget_->SetContentsView(this); | 302 widget_->SetContentsView(this); |
63 widget_->SetBounds(display_.bounds()); | 303 widget_->SetBounds(display_.bounds()); |
64 widget_->Show(); | 304 widget_->Show(); |
65 set_owned_by_client(); | 305 set_owned_by_client(); |
66 | 306 |
(...skipping 26 matching lines...) Expand all Loading... |
93 display_.bounds().height() * 3.f / 4, kExitLabelWidth, | 333 display_.bounds().height() * 3.f / 4, kExitLabelWidth, |
94 kExitLabelHeight); | 334 kExitLabelHeight); |
95 exit_label_->SetEnabledColor(kExitLabelColor); | 335 exit_label_->SetEnabledColor(kExitLabelColor); |
96 exit_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER); | 336 exit_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER); |
97 exit_label_->SetShadows(gfx::ShadowValues( | 337 exit_label_->SetShadows(gfx::ShadowValues( |
98 1, gfx::ShadowValue(gfx::Vector2d(1, 1), 1, kExitLabelShadowColor))); | 338 1, gfx::ShadowValue(gfx::Vector2d(1, 1), 1, kExitLabelShadowColor))); |
99 exit_label_->SetSubpixelRenderingEnabled(false); | 339 exit_label_->SetSubpixelRenderingEnabled(false); |
100 exit_label_->SetVisible(false); | 340 exit_label_->SetVisible(false); |
101 | 341 |
102 AddChildView(exit_label_); | 342 AddChildView(exit_label_); |
| 343 |
| 344 // If this is not the screen that is being calibrated, then this is all we |
| 345 // need to display. |
| 346 if (!is_primary_view_) |
| 347 return; |
| 348 |
| 349 // Initialize the touch point view that contains the animated circle that the |
| 350 // user needs to tap. |
| 351 const int kTouchPointViewHeight = kThrobberCircleViewWidth + kTapLabelHeight; |
| 352 |
| 353 throbber_circle_ = |
| 354 new CircularThrobberView(kThrobberCircleViewWidth, kInnerCircleColor, |
| 355 kOuterCircleColor, kCircleAnimationDurationMs); |
| 356 throbber_circle_->SetPosition(gfx::Point(0, 0)); |
| 357 |
| 358 touch_point_view_ = new views::View; |
| 359 touch_point_view_->SetBounds(kTouchPointViewOffset, kTouchPointViewOffset, |
| 360 kThrobberCircleViewWidth, kTouchPointViewHeight); |
| 361 touch_point_view_->SetVisible(false); |
| 362 |
| 363 touch_point_view_->AddChildView(throbber_circle_); |
| 364 |
| 365 AddChildView(touch_point_view_); |
| 366 |
| 367 // Initialize the Hint Box view. |
| 368 base::string16 hint_label_text = |
| 369 rb.GetLocalizedString(IDS_DISPLAY_TOUCH_CALIBRATION_HINT_LABEL_TEXT); |
| 370 base::string16 hint_sublabel_text = |
| 371 rb.GetLocalizedString(IDS_DISPLAY_TOUCH_CALIBRATION_HINT_SUBLABEL_TEXT); |
| 372 |
| 373 int tpv_width = touch_point_view_->width(); |
| 374 |
| 375 gfx::Size size(kHintBoxWidth, kHintBoxHeight); |
| 376 |
| 377 gfx::Point position( |
| 378 touch_point_view_->x() + tpv_width * 1.2f, |
| 379 touch_point_view_->y() + (tpv_width / 2.f) - (size.height() / 2.f)); |
| 380 |
| 381 HintBox* hint_box = |
| 382 new HintBox(gfx::Rect(position, size), kHintRectBorderRadius); |
| 383 hint_box->SetVisible(false); |
| 384 hint_box->SetLabel(hint_label_text, kHintLabelTextColor); |
| 385 hint_box->SetSubLabel(hint_sublabel_text, kHintSublabelTextColor); |
| 386 hint_box_view_ = hint_box; |
| 387 |
| 388 AddChildView(hint_box_view_); |
103 } | 389 } |
104 | 390 |
105 void TouchCalibratorView::OnPaint(gfx::Canvas* canvas) { | 391 void TouchCalibratorView::OnPaint(gfx::Canvas* canvas) { |
106 OnPaintBackground(canvas); | 392 OnPaintBackground(canvas); |
107 } | 393 } |
108 | 394 |
109 void TouchCalibratorView::OnPaintBackground(gfx::Canvas* canvas) { | 395 void TouchCalibratorView::OnPaintBackground(gfx::Canvas* canvas) { |
110 float opacity; | 396 float opacity; |
111 | 397 |
112 // If current state is a fade in or fade out state then update opacity | 398 // If current state is a fade in or fade out state then update opacity |
(...skipping 17 matching lines...) Expand all Loading... |
130 | 416 |
131 void TouchCalibratorView::AnimationCanceled(const gfx::Animation* animation) { | 417 void TouchCalibratorView::AnimationCanceled(const gfx::Animation* animation) { |
132 AnimationEnded(animation); | 418 AnimationEnded(animation); |
133 } | 419 } |
134 | 420 |
135 void TouchCalibratorView::AnimationEnded(const gfx::Animation* animation) { | 421 void TouchCalibratorView::AnimationEnded(const gfx::Animation* animation) { |
136 switch (state_) { | 422 switch (state_) { |
137 case BACKGROUND_FADING_IN: | 423 case BACKGROUND_FADING_IN: |
138 exit_label_->SetVisible(true); | 424 exit_label_->SetVisible(true); |
139 state_ = is_primary_view_ ? DISPLAY_POINT_1 : CALIBRATION_COMPLETE; | 425 state_ = is_primary_view_ ? DISPLAY_POINT_1 : CALIBRATION_COMPLETE; |
| 426 if (is_primary_view_) { |
| 427 touch_point_view_->SetVisible(true); |
| 428 hint_box_view_->SetVisible(true); |
| 429 } |
140 break; | 430 break; |
141 default: | 431 default: |
142 break; | 432 break; |
143 } | 433 } |
144 } | 434 } |
145 | 435 |
146 void TouchCalibratorView::AdvanceToNextState() { | 436 void TouchCalibratorView::AdvanceToNextState() { |
147 // Stop any previous animations and skip them to the end. | 437 // Stop any previous animations and skip them to the end. |
148 animator_->End(); | 438 animator_->End(); |
149 | 439 |
(...skipping 21 matching lines...) Expand all Loading... |
171 } | 461 } |
172 | 462 |
173 void TouchCalibratorView::SkipToFinalState() {} | 463 void TouchCalibratorView::SkipToFinalState() {} |
174 | 464 |
175 void TouchCalibratorView::SkipCurrentAnimationForTest() { | 465 void TouchCalibratorView::SkipCurrentAnimationForTest() { |
176 if (animator_->is_animating()) | 466 if (animator_->is_animating()) |
177 animator_->End(); | 467 animator_->End(); |
178 } | 468 } |
179 | 469 |
180 } // namespace chromeos | 470 } // namespace chromeos |
OLD | NEW |