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

Unified 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 4 years 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.cc
diff --git a/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.cc b/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.cc
index 4d155a6316751c33aa8231b8d03b95732bcb3cd3..f7e54dcf8844ca19d86b847273d3abbefa9f314e 100644
--- a/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.cc
+++ b/chrome/browser/chromeos/display/touch_calibrator/touch_calibrator_view.cc
@@ -10,6 +10,7 @@
#include "ui/aura/window.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/animation/linear_animation.h"
+#include "ui/gfx/animation/throb_animation.h"
#include "ui/gfx/canvas.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/controls/label.h"
@@ -29,6 +30,16 @@ const SkColor kExitLabelShadowColor = SkColorSetARGBInline(255, 11, 11, 11);
constexpr int kExitLabelWidth = 300;
constexpr int kExitLabelHeight = 20;
+const SkColor kHintLabelTextColor = SK_ColorBLACK;
+const SkColor kHintSublabelTextColor = SkColorSetARGBInline(255, 161, 161, 161);
+
+const SkColor kInnerCircleColor = SK_ColorWHITE;
+const SkColor kOuterCircleColor = SkColorSetA(kInnerCircleColor, 128);
+
+constexpr int kCircleAnimationDurationMs = 900;
+
+constexpr int kHintRectBorderRadius = 10;
+
constexpr float kBackgroundFinalOpacity = 0.75f;
// Returns the initialization params for the widget that contains the touch
@@ -47,13 +58,217 @@ views::Widget::InitParams GetWidgetParams(aura::Window* root_window) {
return params;
}
+// Returns a font size that would fit the text exactly in the given bounds.
+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
+ int font_size = 0;
+ gfx::FontList font_list;
+ int height, width;
+ do {
+ font_size++;
+ font_list = ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
+ font_size, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL);
+ gfx::Canvas::SizeStringInt(text, font_list, &width, &height, 0, 0);
+ } 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.
+ return font_size - 1;
+}
+
} // namespace
+// Creates a throbbing animated view with two concentric circles. The radius of
+// the inner circle is fixed while that of the outer circle oscillates between a
+// min and max radius. The animation takes |animation_duration| milliseconds
+// to complete. The center of these circles are at the center of the view
+// element.
+class CircularThrobberView : public views::View, public gfx::AnimationDelegate {
+ public:
+ CircularThrobberView(int width,
+ const SkColor& inner_circle_color,
+ const SkColor& outer_circle_color,
+ int animation_duration);
+ ~CircularThrobberView() override;
+
+ // views::View overrides:
+ void OnPaint(gfx::Canvas* canvas) override;
+
+ // gfx::AnimationDelegate overrides:
+ void AnimationProgressed(const gfx::Animation* animation) override;
+
+ private:
+ // Radius of the inner circle.
+ const int inner_radius_;
+
+ // Current radius of the outer circle.
+ int outer_radius_;
+
+ // Minimum radius for outer animated circle.
+ const int min_outer_radius_;
+
+ // Maximum radius for outer animated circle.
+ 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
+
+ SkPaint inner_circle_paint_;
+ SkPaint outer_circle_paint_;
+
+ std::unique_ptr<gfx::ThrobAnimation> animation_;
+
+ // Center of the concentric circles.
+ const gfx::Point center_;
+
+ DISALLOW_COPY_AND_ASSIGN(CircularThrobberView);
+};
+
+CircularThrobberView::CircularThrobberView(int width,
+ const SkColor& inner_circle_color,
+ const SkColor& outer_circle_color,
+ int animation_duration)
+ : inner_radius_(width / 4),
+ outer_radius_(inner_radius_),
+ 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
+ max_outer_radius_(width / 2),
+ center_(gfx::Point(width / 2, width / 2)) {
+ SetSize(gfx::Size(width, width));
+
+ inner_circle_paint_.setColor(inner_circle_color);
+ inner_circle_paint_.setStyle(SkPaint::kFill_Style);
+ inner_circle_paint_.setFlags(SkPaint::kAntiAlias_Flag);
+
+ outer_circle_paint_.setColor(outer_circle_color);
+ outer_circle_paint_.setStyle(SkPaint::kFill_Style);
+ outer_circle_paint_.setFlags(SkPaint::kAntiAlias_Flag);
+
+ animation_.reset(new gfx::ThrobAnimation(this));
+ animation_->SetThrobDuration(animation_duration);
+ animation_->StartThrobbing(-1);
+
+ SchedulePaint();
+}
+
+CircularThrobberView::~CircularThrobberView() {}
+
+void CircularThrobberView::OnPaint(gfx::Canvas* canvas) {
+ canvas->DrawCircle(center_, outer_radius_, outer_circle_paint_);
+ canvas->DrawCircle(center_, inner_radius_, inner_circle_paint_);
+}
+
+void CircularThrobberView::AnimationProgressed(
+ const gfx::Animation* animation) {
+ if (animation != animation_.get())
+ return;
+ outer_radius_ =
+ animation->CurrentValueBetween(min_outer_radius_, max_outer_radius_);
+ SchedulePaint();
+}
+
+// Circular _________________________________
+// Throbber | |
+// View | |
+// ___________ | |
+// | | | |
+// | | | |
+// | . | | Hint Box |
+// | | | |
+// |___________| | |
+// | |
+// | |
+// |_________________________________|
+//
+// This view is set next to the throbber circle view such that their centers
+// align. The hint box has a label text and a sublabel text to assist the
+// user by informing them about the next step in the calibration process.
+class HintBox : public views::View {
+ public:
+ 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
+ ~HintBox() override;
+
+ // views::View overrides:
+ void OnPaint(gfx::Canvas* canvas) override;
+
+ void SetLabel(const base::string16& text, const SkColor& color);
+ void SetSubLabel(const base::string16& text, const SkColor& color);
+
+ private:
+ base::string16 label_text_;
+ base::string16 sublabel_text_;
+
+ SkColor label_color_;
+ SkColor sublabel_color_;
+
+ const int border_radius_;
+
+ gfx::FontList label_font_list_;
+ gfx::FontList sublabel_font_list_;
+
+ gfx::Rect label_text_bounds_;
+ gfx::Rect sublabel_text_bounds_;
+
+ SkPaint paint_;
+
+ DISALLOW_COPY_AND_ASSIGN(HintBox);
+};
+
+HintBox::HintBox(const gfx::Rect& bounds, int border_radius)
+ : border_radius_(border_radius) {
+ SetBoundsRect(bounds);
+
+ paint_.setColor(SK_ColorWHITE);
+ paint_.setStyle(SkPaint::kFill_Style);
+ paint_.setFlags(SkPaint::kAntiAlias_Flag);
+
+ 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
+ int top_offset = left_offset;
+ int line_gap = height() * 0.015f;
+
+ label_text_bounds_.SetRect(left_offset, top_offset, width() - 4 * left_offset,
+ 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.
+
+ top_offset += label_text_bounds_.height() + line_gap;
+
+ sublabel_text_bounds_.SetRect(left_offset, top_offset,
+ width() - 2 * left_offset, height() * 0.12f);
+}
+
+HintBox::~HintBox() {}
+
+void HintBox::SetLabel(const base::string16& text, const SkColor& color) {
+ label_text_ = text;
+ label_color_ = color;
+
+ int font_size = GetFontSizeForRect(label_text_bounds_, label_text_);
+
+ label_font_list_ =
+ ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
+ font_size, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL);
+}
+
+void HintBox::SetSubLabel(const base::string16& text, const SkColor& color) {
+ sublabel_text_ = text;
+ sublabel_color_ = color;
+
+ int font_size = GetFontSizeForRect(sublabel_text_bounds_, sublabel_text_);
+
+ sublabel_font_list_ =
+ ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
+ font_size, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL);
+}
+
+void HintBox::OnPaint(gfx::Canvas* canvas) {
+ canvas->DrawRoundRect(GetLocalBounds(), border_radius_, paint_);
+ canvas->DrawStringRectWithFlags(label_text_, label_font_list_, label_color_,
+ label_text_bounds_, gfx::Canvas::NO_ELLIPSIS);
+ canvas->DrawStringRectWithFlags(sublabel_text_, sublabel_font_list_,
+ sublabel_color_, sublabel_text_bounds_,
+ gfx::Canvas::NO_ELLIPSIS);
+}
+
TouchCalibratorView::TouchCalibratorView(const display::Display& target_display,
bool is_primary_view)
: display_(target_display),
+ touch_point_offset_(display_.bounds().width() / 12),
is_primary_view_(is_primary_view),
- exit_label_(nullptr) {
+ exit_label_(nullptr),
+ throbber_circle_(nullptr),
+ hint_box_view_(nullptr),
+ touch_point_view_(nullptr) {
aura::Window* root = ash::Shell::GetInstance()
->window_tree_host_manager()
->GetRootWindowForDisplayId(display_.id());
@@ -100,6 +315,54 @@ void TouchCalibratorView::InitViewContents() {
exit_label_->SetVisible(false);
AddChildView(exit_label_);
+
+ // If this is not the screen that is being calibrated, then this is all we
+ // need to display.
+ if (!is_primary_view_)
+ return;
+
+ // Initialize the touch point view that contains the animated circle that the
+ // user needs to tap.
+ const float kThrobberCircleViewWidth = display_.bounds().width() / 10.f;
+ const int touch_point_offset_ = display_.bounds().width() / 12;
+ const float kTapLabelHeight = kThrobberCircleViewWidth * 3.f / 8.f;
+ const int kTouchPointViewHeight = kThrobberCircleViewWidth + kTapLabelHeight;
+
+ throbber_circle_ =
+ new CircularThrobberView(kThrobberCircleViewWidth, kInnerCircleColor,
+ kOuterCircleColor, kCircleAnimationDurationMs);
+ throbber_circle_->SetPosition(gfx::Point(0, 0));
+
+ touch_point_view_ = new views::View;
+ touch_point_view_->SetBounds(touch_point_offset_, touch_point_offset_,
+ kThrobberCircleViewWidth, kTouchPointViewHeight);
+ touch_point_view_->SetVisible(false);
+
+ touch_point_view_->AddChildView(throbber_circle_);
+
+ AddChildView(touch_point_view_);
+
+ // Initialize the Hint Box view.
+ base::string16 hint_label_text =
+ rb.GetLocalizedString(IDS_DISPLAY_TOUCH_CALIBRATION_HINT_LABEL_TEXT);
+ base::string16 hint_sublabel_text =
+ rb.GetLocalizedString(IDS_DISPLAY_TOUCH_CALIBRATION_HINT_SUBLABEL_TEXT);
+
+ int tpv_width = touch_point_view_->width();
+
+ gfx::Size size(tpv_width * 2.95f, tpv_width * 1.75f);
+
+ gfx::Point position(
+ touch_point_view_->x() + tpv_width * 1.2f,
+ touch_point_view_->y() + (tpv_width / 2.f) - (size.height() / 2.f));
+
+ hint_box_view_ =
+ new HintBox(gfx::Rect(position, size), kHintRectBorderRadius);
+ hint_box_view_->SetVisible(false);
+ hint_box_view_->SetLabel(hint_label_text, kHintLabelTextColor);
+ hint_box_view_->SetSubLabel(hint_sublabel_text, kHintSublabelTextColor);
+
+ AddChildView(hint_box_view_);
}
void TouchCalibratorView::OnPaint(gfx::Canvas* canvas) {
@@ -137,6 +400,10 @@ void TouchCalibratorView::AnimationEnded(const gfx::Animation* animation) {
case BACKGROUND_FADING_IN:
exit_label_->SetVisible(true);
state_ = is_primary_view_ ? DISPLAY_POINT_1 : CALIBRATION_COMPLETE;
+ if (is_primary_view_) {
+ touch_point_view_->SetVisible(true);
+ hint_box_view_->SetVisible(true);
+ }
break;
default:
break;

Powered by Google App Engine
This is Rietveld 408576698