#include "ui/base/ime/input_method_factory.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/compositor/layer_type.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/compositor/test/layer_animator_test_controller.h"
#include "ui/gfx/rect.h"
#include "ui/keyboard/keyboard_controller.h"
+#include "ui/keyboard/keyboard_controller_observer.h"
#include "ui/keyboard/keyboard_controller_proxy.h"
#include "ui/keyboard/keyboard_switches.h"
namespace keyboard {
namespace {
+// Steps a layer animation until it is completed. Animations must be enabled.
+void RunAnimationForLayer(ui::Layer* layer) {
+ // Animations must be enabled for stepping to work.
+ ASSERT_NE(ui::ScopedAnimationDurationScaleMode::duration_scale_mode(),
+ ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
+
+ ui::LayerAnimatorTestController controller(layer->GetAnimator());
+ gfx::AnimationContainerElement* element = layer->GetAnimator();
+ // Multiple steps are required to complete complex animations.
+ // TODO(vollick): This should not be necessary. crbug.com/154017
+ while (controller.animator()->is_animating()) {
+ controller.StartThreadedAnimationsIfNeeded();
+ base::TimeTicks step_time = controller.animator()->last_step_time();
+ element->Step(step_time + base::TimeDelta::FromMilliseconds(1000));
+ }
+}
+
// An event handler that focuses a window when it is clicked/touched on. This is
// used to match the focus manger behaviour in ash and views.
class TestFocusController : public ui::EventHandler {
}
// Overridden from KeyboardControllerProxy:
+ virtual bool HasKeyboardWindow() const OVERRIDE { return true; }
virtual aura::Window* GetKeyboardWindow() OVERRIDE { return window_.get(); }
virtual content::BrowserContext* GetBrowserContext() OVERRIDE { return NULL; }
virtual ui::InputMethod* GetInputMethod() OVERRIDE {
EXPECT_EQ(180, keyboard_window->bounds().height());
}
+class KeyboardControllerAnimationTest : public KeyboardControllerTest,
+ public KeyboardControllerObserver {
+ public:
+ KeyboardControllerAnimationTest() {}
+ virtual ~KeyboardControllerAnimationTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ // We cannot short-circuit animations for this test.
+ ui::ScopedAnimationDurationScaleMode normal_duration_mode(
+ ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+
+ KeyboardControllerTest::SetUp();
+
+ const gfx::Rect& root_bounds = root_window()->bounds();
+ keyboard_container()->SetBounds(root_bounds);
+ root_window()->AddChild(keyboard_container());
+ controller()->AddObserver(this);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ controller()->RemoveObserver(this);
+ KeyboardControllerTest::TearDown();
+ }
+
+ protected:
+ // KeyboardControllerObserver overrides
+ virtual void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) OVERRIDE {
+ notified_bounds_ = new_bounds;
+ }
+
+ const gfx::Rect& notified_bounds() { return notified_bounds_; }
+
+ aura::Window* keyboard_container() {
+ return controller()->GetContainerWindow();
+ }
+
+ aura::Window* keyboard_window() {
+ return proxy()->GetKeyboardWindow();
+ }
+
+ private:
+ gfx::Rect notified_bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyboardControllerAnimationTest);
+};
+
+// Tests virtual keyboard has correct show and hide animation.
+TEST_F(KeyboardControllerAnimationTest, ContainerAnimation) {
+ ui::Layer* layer = keyboard_container()->layer();
+ ShowKeyboard();
+
+ // Keyboard container and window should immediately become visible before
+ // animation starts.
+ EXPECT_TRUE(keyboard_container()->IsVisible());
+ EXPECT_TRUE(keyboard_window()->IsVisible());
+ float show_start_opacity = layer->opacity();
+ gfx::Transform transform;
+ transform.Translate(0, keyboard_window()->bounds().height());
+ EXPECT_EQ(transform, layer->transform());
+ EXPECT_EQ(gfx::Rect(), notified_bounds());
+
+ RunAnimationForLayer(layer);
+ EXPECT_TRUE(keyboard_container()->IsVisible());
+ EXPECT_TRUE(keyboard_window()->IsVisible());
+ float show_end_opacity = layer->opacity();
+ EXPECT_LT(show_start_opacity, show_end_opacity);
+ EXPECT_EQ(gfx::Transform(), layer->transform());
+ // KeyboardController should notify the bounds of keyboard window to its
+ // observers after show animation finished.
+ EXPECT_EQ(keyboard_window()->bounds(), notified_bounds());
+
+ // Directly hide keyboard without delay.
+ controller()->HideKeyboard(KeyboardController::HIDE_REASON_AUTOMATIC);
+ EXPECT_TRUE(keyboard_container()->IsVisible());
+ EXPECT_TRUE(keyboard_container()->layer()->visible());
+ EXPECT_TRUE(keyboard_window()->IsVisible());
+ float hide_start_opacity = layer->opacity();
+ // KeyboardController should notify the bounds of keyboard window to its
+ // observers before hide animation starts.
+ EXPECT_EQ(gfx::Rect(), notified_bounds());
+
+ RunAnimationForLayer(layer);
+ EXPECT_FALSE(keyboard_container()->IsVisible());
+ EXPECT_FALSE(keyboard_container()->layer()->visible());
+ EXPECT_FALSE(keyboard_window()->IsVisible());
+ float hide_end_opacity = layer->opacity();
+ EXPECT_GT(hide_start_opacity, hide_end_opacity);
+ EXPECT_EQ(transform, layer->transform());
+ EXPECT_EQ(gfx::Rect(), notified_bounds());
+}
+
+// Show keyboard during keyboard hide animation should abort the hide animation
+// and the keyboard should animate in.
+// Test for crbug.com/333284.
+TEST_F(KeyboardControllerAnimationTest, ContainerShowWhileHide) {
+ ui::Layer* layer = keyboard_container()->layer();
+ ShowKeyboard();
+ RunAnimationForLayer(layer);
+
+ controller()->HideKeyboard(KeyboardController::HIDE_REASON_AUTOMATIC);
+ // Before hide animation finishes, show keyboard again.
+ ShowKeyboard();
+ RunAnimationForLayer(layer);
+ EXPECT_TRUE(keyboard_container()->IsVisible());
+ EXPECT_TRUE(keyboard_window()->IsVisible());
+ EXPECT_EQ(1.0, layer->opacity());
+ EXPECT_EQ(gfx::Transform(), layer->transform());
+}
+
class KeyboardControllerUsabilityTest : public KeyboardControllerTest {
public:
KeyboardControllerUsabilityTest() {}