Commit 0bf8c184 authored by Mitsuru Oshima's avatar Mitsuru Oshima Committed by Commit Bot

Animate frame color change

ARC++ app may update the color programatically, which
can result in noticable flashing.

This will make the color change transition smooth by
animating the color from currently used color".

TBR=wutao@chromium.org
BUG=b/88534690
TEST=manual. also covered by unit test

Change-Id: Ia15976cb1ec425ddb4e23ec6a253667fa6f774d9
Reviewed-on: https://chromium-review.googlesource.com/1101504
Commit-Queue: Mitsuru Oshima <oshima@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568474}
parent dbb8df33
......@@ -27,8 +27,10 @@ using views::Widget;
namespace {
// Color for the window title text.
const SkColor kTitleTextColor = SkColorSetRGB(40, 40, 40);
const SkColor kLightTitleTextColor = SK_ColorWHITE;
constexpr SkColor kTitleTextColor = SkColorSetRGB(40, 40, 40);
constexpr SkColor kLightTitleTextColor = SK_ColorWHITE;
// This is 2x of the slide ainmation duration.
constexpr int kColorUpdateDurationMs = 240;
// Tiles an image into an area, rounding the top corners.
void TileRoundRect(gfx::Canvas* canvas,
......@@ -54,6 +56,35 @@ void TileRoundRect(gfx::Canvas* canvas,
namespace ash {
DefaultFrameHeader::ColorAnimator::ColorAnimator(
gfx::AnimationDelegate* delegate)
: animation_(delegate) {
animation_.SetSlideDuration(kColorUpdateDurationMs);
animation_.SetTweenType(gfx::Tween::EASE_IN);
animation_.Reset(1);
}
DefaultFrameHeader::ColorAnimator::ColorAnimator::~ColorAnimator() = default;
void DefaultFrameHeader::ColorAnimator::SetTargetColor(SkColor target) {
target_color_ = target;
start_color_ = current_color_;
if (current_color_ == kDefaultFrameColor) {
// Changing from default should be set immediately.
current_color_ = target_color_;
animation_.Reset(1);
} else {
animation_.Reset(0);
}
animation_.Show();
}
SkColor DefaultFrameHeader::ColorAnimator::GetCurrentColor() {
current_color_ = color_utils::AlphaBlend(
target_color_, start_color_, animation_.CurrentValueBetween(0, 255));
return current_color_;
}
///////////////////////////////////////////////////////////////////////////////
// DefaultFrameHeader, public:
......@@ -62,8 +93,8 @@ DefaultFrameHeader::DefaultFrameHeader(
views::View* header_view,
FrameCaptionButtonContainerView* caption_button_container)
: FrameHeader(target_widget, header_view),
active_frame_color_(kDefaultFrameColor),
inactive_frame_color_(kDefaultFrameColor) {
active_frame_color_(this),
inactive_frame_color_(this) {
DCHECK(caption_button_container);
SetCaptionButtonContainer(caption_button_container);
}
......@@ -93,8 +124,9 @@ void DefaultFrameHeader::DoPaintHeader(gfx::Canvas* canvas) {
cc::PaintFlags flags;
int active_alpha = activation_animation().CurrentValueBetween(0, 255);
flags.setColor(color_utils::AlphaBlend(active_frame_color_,
inactive_frame_color_, active_alpha));
flags.setColor(color_utils::AlphaBlend(
active_frame_color_.GetCurrentColor(),
inactive_frame_color_.GetCurrentColor(), active_alpha));
flags.setAntiAlias(true);
if (width_in_pixels_ > 0) {
canvas->Save();
......@@ -131,12 +163,12 @@ SkColor DefaultFrameHeader::GetTitleColor() const {
void DefaultFrameHeader::SetFrameColorsImpl(SkColor active_frame_color,
SkColor inactive_frame_color) {
bool updated = false;
if (active_frame_color_ != active_frame_color) {
active_frame_color_ = active_frame_color;
if (active_frame_color_.target_color() != active_frame_color) {
active_frame_color_.SetTargetColor(active_frame_color);
updated = true;
}
if (inactive_frame_color_ != inactive_frame_color) {
inactive_frame_color_ = inactive_frame_color;
if (inactive_frame_color_.target_color() != inactive_frame_color) {
inactive_frame_color_.SetTargetColor(inactive_frame_color);
updated = true;
}
......@@ -147,7 +179,17 @@ void DefaultFrameHeader::SetFrameColorsImpl(SkColor active_frame_color,
}
SkColor DefaultFrameHeader::GetCurrentFrameColor() const {
return mode() == MODE_ACTIVE ? active_frame_color_ : inactive_frame_color_;
return mode() == MODE_ACTIVE ? active_frame_color_.target_color()
: inactive_frame_color_.target_color();
}
gfx::SlideAnimation*
DefaultFrameHeader::GetAnimationForActiveFrameColorForTest() {
return active_frame_color_.animation();
}
SkColor DefaultFrameHeader::GetActiveFrameColorForPaintForTest() {
return active_frame_color_.GetCurrentColor();
}
} // namespace ash
......@@ -9,6 +9,7 @@
#include "ash/ash_export.h"
#include "ash/frame/frame_header.h"
#include "ash/public/cpp/ash_constants.h"
#include "base/compiler_specific.h" // override
#include "base/gtest_prod_util.h"
#include "base/macros.h"
......@@ -27,8 +28,12 @@ class ASH_EXPORT DefaultFrameHeader : public FrameHeader {
void SetThemeColor(SkColor theme_color);
SkColor active_frame_color_for_testing() { return active_frame_color_; }
SkColor inactive_frame_color_for_testing() { return inactive_frame_color_; }
SkColor active_frame_color_for_testing() {
return active_frame_color_.target_color();
}
SkColor inactive_frame_color_for_testing() {
return inactive_frame_color_.target_color();
}
protected:
// FrameHeader:
......@@ -47,8 +52,34 @@ class ASH_EXPORT DefaultFrameHeader : public FrameHeader {
void SetFrameColorsImpl(SkColor active_frame_color,
SkColor inactive_frame_color);
SkColor active_frame_color_;
SkColor inactive_frame_color_;
gfx::SlideAnimation* GetAnimationForActiveFrameColorForTest();
SkColor GetActiveFrameColorForPaintForTest();
// A utility class to animate color value.
class ColorAnimator {
public:
explicit ColorAnimator(gfx::AnimationDelegate* delegate);
~ColorAnimator();
void SetTargetColor(SkColor target);
SkColor target_color() const { return target_color_; };
SkColor GetCurrentColor();
float get_value() const { return animation_.GetCurrentValue(); }
gfx::SlideAnimation* animation() { return &animation_; }
private:
gfx::SlideAnimation animation_;
SkColor start_color_ = kDefaultFrameColor;
SkColor target_color_ = kDefaultFrameColor;
;
SkColor current_color_ = kDefaultFrameColor;
DISALLOW_COPY_AND_ASSIGN(ColorAnimator);
};
ColorAnimator active_frame_color_;
ColorAnimator inactive_frame_color_;
int width_in_pixels_ = -1;
......
......@@ -10,6 +10,8 @@
#include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/test/ash_test_base.h"
#include "ui/gfx/animation/animation_test_api.h"
#include "ui/gfx/color_utils.h"
#include "ui/views/test/test_views.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/non_client_view.h"
......@@ -69,7 +71,6 @@ TEST_F(DefaultFrameHeaderTest, FrameColors) {
DefaultFrameHeader frame_header(w.get(), w->non_client_view()->frame_view(),
&container);
// Check frame color is sensitive to mode.
SkColor active = SkColorSetRGB(70, 70, 70);
SkColor inactive = SkColorSetRGB(200, 200, 200);
......@@ -78,6 +79,48 @@ TEST_F(DefaultFrameHeaderTest, FrameColors) {
EXPECT_EQ(active, frame_header.GetCurrentFrameColor());
frame_header.mode_ = FrameHeader::MODE_INACTIVE;
EXPECT_EQ(inactive, frame_header.GetCurrentFrameColor());
EXPECT_EQ(active, frame_header.GetActiveFrameColorForPaintForTest());
// Update to the new value which has no blue, which should animate.
frame_header.mode_ = FrameHeader::MODE_ACTIVE;
SkColor new_active = SkColorSetRGB(70, 70, 0);
frame_header.SetFrameColors(new_active, SK_ColorBLACK);
gfx::SlideAnimation* animation =
frame_header.GetAnimationForActiveFrameColorForTest();
gfx::AnimationTestApi test_api(animation);
// animate half way through.
base::TimeTicks now = base::TimeTicks::Now();
test_api.SetStartTime(now);
test_api.Step(now + base::TimeDelta::FromMilliseconds(120));
// GetCurrentFrameColor should return the target color.
EXPECT_EQ(new_active, frame_header.GetCurrentFrameColor());
// The color used for paint should be somewhere between 0 and 70.
SkColor new_active_for_paint =
frame_header.GetActiveFrameColorForPaintForTest();
EXPECT_NE(new_active, new_active_for_paint);
EXPECT_EQ(53u, SkColorGetB(new_active_for_paint));
// Now update to the new value which is full blue.
SkColor new_new_active = SkColorSetRGB(70, 70, 255);
frame_header.SetFrameColors(new_new_active, SK_ColorBLACK);
now = base::TimeTicks::Now();
test_api.SetStartTime(now);
test_api.Step(now + base::TimeDelta::FromMilliseconds(20));
// Again, GetCurrentFrameColor should return the target color.
EXPECT_EQ(new_new_active, frame_header.GetCurrentFrameColor());
// The start value should be the previous paint color, so it should be
// near 53.
SkColor new_new_active_for_paint =
frame_header.GetActiveFrameColorForPaintForTest();
EXPECT_NE(new_active_for_paint, new_new_active_for_paint);
EXPECT_EQ(54u, SkColorGetB(new_new_active_for_paint));
}
} // namespace ash
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment