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

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: Adds animated touch point and the hint box for touch calibration UX Created 3 years, 12 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 const SkColor kHintLabelTextColor = SK_ColorBLACK;
34 const SkColor kHintSublabelTextColor = SkColorSetARGBInline(255, 161, 161, 161);
35
36 const SkColor kInnerCircleColor = SK_ColorWHITE;
37 const SkColor kOuterCircleColor = SkColorSetA(kInnerCircleColor, 128);
38
39 constexpr int kCircleAnimationDurationMs = 900;
40
41 constexpr int kHintRectBorderRadius = 10;
42
32 constexpr float kBackgroundFinalOpacity = 0.75f; 43 constexpr float kBackgroundFinalOpacity = 0.75f;
33 44
34 // Returns the initialization params for the widget that contains the touch 45 // Returns the initialization params for the widget that contains the touch
35 // calibrator view. 46 // calibrator view.
36 views::Widget::InitParams GetWidgetParams(aura::Window* root_window) { 47 views::Widget::InitParams GetWidgetParams(aura::Window* root_window) {
37 views::Widget::InitParams params; 48 views::Widget::InitParams params;
38 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; 49 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
39 params.name = kWidgetName; 50 params.name = kWidgetName;
40 params.keep_on_top = true; 51 params.keep_on_top = true;
41 params.accept_events = true; 52 params.accept_events = true;
42 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; 53 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
43 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 54 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
44 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 55 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
45 params.parent = ash::Shell::GetContainer( 56 params.parent = ash::Shell::GetContainer(
46 root_window, ash::kShellWindowId_OverlayContainer); 57 root_window, ash::kShellWindowId_OverlayContainer);
47 return params; 58 return params;
48 } 59 }
49 60
61 // Returns a font size that would fit the text exactly in the given bounds.
62 int GetFontSizeForRect(gfx::Rect bounds, base::string16 text) {
oshima 2017/01/05 23:29:04 a few questions. 1) Why do we want to use fixed si
malaykeshav 2017/01/09 18:59:41 Font size is now fixed along with the bounds which
oshima 2017/01/10 17:11:18 I thought we're going to adjust the bounds using G
malaykeshav 2017/01/10 23:07:48 Done
63 int font_size = 0;
64 gfx::FontList font_list;
65 int height, width;
66 do {
67 font_size++;
68 font_list = ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
69 font_size, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL);
70 gfx::Canvas::SizeStringInt(text, font_list, &width, &height, 0, 0);
71 } while (width <= bounds.width() && height <= bounds.height());
stevenjb 2016/12/28 01:04:50 Is this guaranteed to exit? It seems like if font_
malaykeshav 2017/01/09 18:59:40 Removed. No longer required.
72 return font_size - 1;
73 }
74
50 } // namespace 75 } // namespace
51 76
77 // Creates a throbbing animated view with two concentric circles. The radius of
78 // the inner circle is fixed while that of the outer circle oscillates between a
79 // min and max radius. The animation takes |animation_duration| milliseconds
80 // to complete. The center of these circles are at the center of the view
81 // element.
82 class CircularThrobberView : public views::View, public gfx::AnimationDelegate {
83 public:
84 CircularThrobberView(int width,
85 const SkColor& inner_circle_color,
86 const SkColor& outer_circle_color,
87 int animation_duration);
88 ~CircularThrobberView() override;
89
90 // views::View overrides:
91 void OnPaint(gfx::Canvas* canvas) override;
92
93 // gfx::AnimationDelegate overrides:
94 void AnimationProgressed(const gfx::Animation* animation) override;
95
96 private:
97 // Radius of the inner circle.
98 const int inner_radius_;
99
100 // Current radius of the outer circle.
101 int outer_radius_;
102
103 // Minimum radius for outer animated circle.
104 const int min_outer_radius_;
105
106 // Maximum radius for outer animated circle.
107 const int max_outer_radius_;
oshima 2017/01/05 23:29:04 It's probably better to say "smallest/largest size
malaykeshav 2017/01/09 18:59:41 Done
108
109 SkPaint inner_circle_paint_;
110 SkPaint outer_circle_paint_;
111
112 std::unique_ptr<gfx::ThrobAnimation> animation_;
113
114 // Center of the concentric circles.
115 const gfx::Point center_;
116
117 DISALLOW_COPY_AND_ASSIGN(CircularThrobberView);
118 };
119
120 CircularThrobberView::CircularThrobberView(int width,
121 const SkColor& inner_circle_color,
122 const SkColor& outer_circle_color,
123 int animation_duration)
124 : inner_radius_(width / 4),
125 outer_radius_(inner_radius_),
126 min_outer_radius_(3.f * width / 8.f),
oshima 2017/01/05 23:29:04 can you define a constant for this factor against
malaykeshav 2017/01/09 18:59:40 Done
127 max_outer_radius_(width / 2),
128 center_(gfx::Point(width / 2, width / 2)) {
129 SetSize(gfx::Size(width, width));
130
131 inner_circle_paint_.setColor(inner_circle_color);
132 inner_circle_paint_.setStyle(SkPaint::kFill_Style);
133 inner_circle_paint_.setFlags(SkPaint::kAntiAlias_Flag);
134
135 outer_circle_paint_.setColor(outer_circle_color);
136 outer_circle_paint_.setStyle(SkPaint::kFill_Style);
137 outer_circle_paint_.setFlags(SkPaint::kAntiAlias_Flag);
138
139 animation_.reset(new gfx::ThrobAnimation(this));
140 animation_->SetThrobDuration(animation_duration);
141 animation_->StartThrobbing(-1);
142
143 SchedulePaint();
144 }
145
146 CircularThrobberView::~CircularThrobberView() {}
147
148 void CircularThrobberView::OnPaint(gfx::Canvas* canvas) {
149 canvas->DrawCircle(center_, outer_radius_, outer_circle_paint_);
150 canvas->DrawCircle(center_, inner_radius_, inner_circle_paint_);
151 }
152
153 void CircularThrobberView::AnimationProgressed(
154 const gfx::Animation* animation) {
155 if (animation != animation_.get())
156 return;
157 outer_radius_ =
158 animation->CurrentValueBetween(min_outer_radius_, max_outer_radius_);
159 SchedulePaint();
160 }
161
162 // Circular _________________________________
163 // Throbber | |
164 // View | |
165 // ___________ | |
166 // | | | |
167 // | | | |
168 // | . | | Hint Box |
169 // | | | |
170 // |___________| | |
171 // | |
172 // | |
173 // |_________________________________|
174 //
175 // This view is set next to the throbber circle view such that their centers
176 // align. The hint box has a label text and a sublabel text to assist the
177 // user by informing them about the next step in the calibration process.
178 class HintBox : public views::View {
179 public:
180 explicit HintBox(const gfx::Rect& bounds, int border_radius);
oshima 2017/01/05 23:29:04 no explicit
malaykeshav 2017/01/09 18:59:40 Done
181 ~HintBox() override;
182
183 // views::View overrides:
184 void OnPaint(gfx::Canvas* canvas) override;
185
186 void SetLabel(const base::string16& text, const SkColor& color);
187 void SetSubLabel(const base::string16& text, const SkColor& color);
188
189 private:
190 base::string16 label_text_;
191 base::string16 sublabel_text_;
192
193 SkColor label_color_;
194 SkColor sublabel_color_;
195
196 const int border_radius_;
197
198 gfx::FontList label_font_list_;
199 gfx::FontList sublabel_font_list_;
200
201 gfx::Rect label_text_bounds_;
202 gfx::Rect sublabel_text_bounds_;
203
204 SkPaint paint_;
205
206 DISALLOW_COPY_AND_ASSIGN(HintBox);
207 };
208
209 HintBox::HintBox(const gfx::Rect& bounds, int border_radius)
210 : border_radius_(border_radius) {
211 SetBoundsRect(bounds);
212
213 paint_.setColor(SK_ColorWHITE);
214 paint_.setStyle(SkPaint::kFill_Style);
215 paint_.setFlags(SkPaint::kAntiAlias_Flag);
216
217 int left_offset = width() * 0.08f;
stevenjb 2016/12/28 01:04:50 Does this work as expected with RTL?
malaykeshav 2017/01/09 18:59:40 The updated code works with RTL. https://screensho
218 int top_offset = left_offset;
219 int line_gap = height() * 0.015f;
220
221 label_text_bounds_.SetRect(left_offset, top_offset, width() - 4 * left_offset,
222 height() * 0.11f);
oshima 2017/01/05 23:29:04 Can you use Inset()?
malaykeshav 2017/01/09 18:59:40 Done.
oshima 2017/01/09 19:44:16 My apologies, I misread the code. SetRect looks ok
malaykeshav 2017/01/09 22:29:57 Done.
223
224 top_offset += label_text_bounds_.height() + line_gap;
225
226 sublabel_text_bounds_.SetRect(left_offset, top_offset,
227 width() - 2 * left_offset, height() * 0.12f);
228 }
229
230 HintBox::~HintBox() {}
231
232 void HintBox::SetLabel(const base::string16& text, const SkColor& color) {
233 label_text_ = text;
234 label_color_ = color;
235
236 int font_size = GetFontSizeForRect(label_text_bounds_, label_text_);
237
238 label_font_list_ =
239 ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
240 font_size, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL);
241 }
242
243 void HintBox::SetSubLabel(const base::string16& text, const SkColor& color) {
244 sublabel_text_ = text;
245 sublabel_color_ = color;
246
247 int font_size = GetFontSizeForRect(sublabel_text_bounds_, sublabel_text_);
248
249 sublabel_font_list_ =
250 ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
251 font_size, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL);
252 }
253
254 void HintBox::OnPaint(gfx::Canvas* canvas) {
255 canvas->DrawRoundRect(GetLocalBounds(), border_radius_, paint_);
256 canvas->DrawStringRectWithFlags(label_text_, label_font_list_, label_color_,
257 label_text_bounds_, gfx::Canvas::NO_ELLIPSIS);
258 canvas->DrawStringRectWithFlags(sublabel_text_, sublabel_font_list_,
259 sublabel_color_, sublabel_text_bounds_,
260 gfx::Canvas::NO_ELLIPSIS);
261 }
262
52 TouchCalibratorView::TouchCalibratorView(const display::Display& target_display, 263 TouchCalibratorView::TouchCalibratorView(const display::Display& target_display,
53 bool is_primary_view) 264 bool is_primary_view)
54 : display_(target_display), 265 : display_(target_display),
266 touch_point_offset_(display_.bounds().width() / 12),
55 is_primary_view_(is_primary_view), 267 is_primary_view_(is_primary_view),
56 exit_label_(nullptr) { 268 exit_label_(nullptr),
269 throbber_circle_(nullptr),
270 hint_box_view_(nullptr),
271 touch_point_view_(nullptr) {
57 aura::Window* root = ash::Shell::GetInstance() 272 aura::Window* root = ash::Shell::GetInstance()
58 ->window_tree_host_manager() 273 ->window_tree_host_manager()
59 ->GetRootWindowForDisplayId(display_.id()); 274 ->GetRootWindowForDisplayId(display_.id());
60 widget_.reset(new views::Widget); 275 widget_.reset(new views::Widget);
61 widget_->Init(GetWidgetParams(root)); 276 widget_->Init(GetWidgetParams(root));
62 widget_->SetContentsView(this); 277 widget_->SetContentsView(this);
63 widget_->SetBounds(display_.bounds()); 278 widget_->SetBounds(display_.bounds());
64 widget_->Show(); 279 widget_->Show();
65 set_owned_by_client(); 280 set_owned_by_client();
66 281
(...skipping 26 matching lines...) Expand all
93 display_.bounds().height() * 3.f / 4, kExitLabelWidth, 308 display_.bounds().height() * 3.f / 4, kExitLabelWidth,
94 kExitLabelHeight); 309 kExitLabelHeight);
95 exit_label_->SetEnabledColor(kExitLabelColor); 310 exit_label_->SetEnabledColor(kExitLabelColor);
96 exit_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER); 311 exit_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
97 exit_label_->SetShadows(gfx::ShadowValues( 312 exit_label_->SetShadows(gfx::ShadowValues(
98 1, gfx::ShadowValue(gfx::Vector2d(1, 1), 1, kExitLabelShadowColor))); 313 1, gfx::ShadowValue(gfx::Vector2d(1, 1), 1, kExitLabelShadowColor)));
99 exit_label_->SetSubpixelRenderingEnabled(false); 314 exit_label_->SetSubpixelRenderingEnabled(false);
100 exit_label_->SetVisible(false); 315 exit_label_->SetVisible(false);
101 316
102 AddChildView(exit_label_); 317 AddChildView(exit_label_);
318
319 // If this is not the screen that is being calibrated, then this is all we
320 // need to display.
321 if (!is_primary_view_)
322 return;
323
324 // Initialize the touch point view that contains the animated circle that the
325 // user needs to tap.
326 const float kThrobberCircleViewWidth = display_.bounds().width() / 10.f;
327 const int touch_point_offset_ = display_.bounds().width() / 12;
328 const float kTapLabelHeight = kThrobberCircleViewWidth * 3.f / 8.f;
329 const int kTouchPointViewHeight = kThrobberCircleViewWidth + kTapLabelHeight;
330
331 throbber_circle_ =
332 new CircularThrobberView(kThrobberCircleViewWidth, kInnerCircleColor,
333 kOuterCircleColor, kCircleAnimationDurationMs);
334 throbber_circle_->SetPosition(gfx::Point(0, 0));
335
336 touch_point_view_ = new views::View;
337 touch_point_view_->SetBounds(touch_point_offset_, touch_point_offset_,
338 kThrobberCircleViewWidth, kTouchPointViewHeight);
339 touch_point_view_->SetVisible(false);
340
341 touch_point_view_->AddChildView(throbber_circle_);
342
343 AddChildView(touch_point_view_);
344
345 // Initialize the Hint Box view.
346 base::string16 hint_label_text =
347 rb.GetLocalizedString(IDS_DISPLAY_TOUCH_CALIBRATION_HINT_LABEL_TEXT);
348 base::string16 hint_sublabel_text =
349 rb.GetLocalizedString(IDS_DISPLAY_TOUCH_CALIBRATION_HINT_SUBLABEL_TEXT);
350
351 int tpv_width = touch_point_view_->width();
352
353 gfx::Size size(tpv_width * 2.95f, tpv_width * 1.75f);
354
355 gfx::Point position(
356 touch_point_view_->x() + tpv_width * 1.2f,
357 touch_point_view_->y() + (tpv_width / 2.f) - (size.height() / 2.f));
358
359 hint_box_view_ =
360 new HintBox(gfx::Rect(position, size), kHintRectBorderRadius);
361 hint_box_view_->SetVisible(false);
362 hint_box_view_->SetLabel(hint_label_text, kHintLabelTextColor);
363 hint_box_view_->SetSubLabel(hint_sublabel_text, kHintSublabelTextColor);
364
365 AddChildView(hint_box_view_);
103 } 366 }
104 367
105 void TouchCalibratorView::OnPaint(gfx::Canvas* canvas) { 368 void TouchCalibratorView::OnPaint(gfx::Canvas* canvas) {
106 OnPaintBackground(canvas); 369 OnPaintBackground(canvas);
107 } 370 }
108 371
109 void TouchCalibratorView::OnPaintBackground(gfx::Canvas* canvas) { 372 void TouchCalibratorView::OnPaintBackground(gfx::Canvas* canvas) {
110 float opacity; 373 float opacity;
111 374
112 // If current state is a fade in or fade out state then update opacity 375 // If current state is a fade in or fade out state then update opacity
(...skipping 17 matching lines...) Expand all
130 393
131 void TouchCalibratorView::AnimationCanceled(const gfx::Animation* animation) { 394 void TouchCalibratorView::AnimationCanceled(const gfx::Animation* animation) {
132 AnimationEnded(animation); 395 AnimationEnded(animation);
133 } 396 }
134 397
135 void TouchCalibratorView::AnimationEnded(const gfx::Animation* animation) { 398 void TouchCalibratorView::AnimationEnded(const gfx::Animation* animation) {
136 switch (state_) { 399 switch (state_) {
137 case BACKGROUND_FADING_IN: 400 case BACKGROUND_FADING_IN:
138 exit_label_->SetVisible(true); 401 exit_label_->SetVisible(true);
139 state_ = is_primary_view_ ? DISPLAY_POINT_1 : CALIBRATION_COMPLETE; 402 state_ = is_primary_view_ ? DISPLAY_POINT_1 : CALIBRATION_COMPLETE;
403 if (is_primary_view_) {
404 touch_point_view_->SetVisible(true);
405 hint_box_view_->SetVisible(true);
406 }
140 break; 407 break;
141 default: 408 default:
142 break; 409 break;
143 } 410 }
144 } 411 }
145 412
146 void TouchCalibratorView::AdvanceToNextState() { 413 void TouchCalibratorView::AdvanceToNextState() {
147 // Stop any previous animations and skip them to the end. 414 // Stop any previous animations and skip them to the end.
148 animator_->End(); 415 animator_->End();
149 416
(...skipping 21 matching lines...) Expand all
171 } 438 }
172 439
173 void TouchCalibratorView::SkipToFinalState() {} 440 void TouchCalibratorView::SkipToFinalState() {}
174 441
175 void TouchCalibratorView::SkipCurrentAnimationForTest() { 442 void TouchCalibratorView::SkipCurrentAnimationForTest() {
176 if (animator_->is_animating()) 443 if (animator_->is_animating())
177 animator_->End(); 444 animator_->End();
178 } 445 }
179 446
180 } // namespace chromeos 447 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698