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

Side by Side Diff: chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.cc

Issue 2600213002: Adds animated touch point and the hint box for touch calibration UX (Closed)
Patch Set: Resolving comments Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.h ('k') | ui/strings/ui_strings.grd » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698