// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "ash/shell.h" #include "chrome/browser/chromeos/input_method/input_method_util.h" #include "chrome/browser/chromeos/input_method/mode_indicator_controller.h" #include "chrome/test/base/in_process_browser_test.h" #include "chromeos/ime/component_extension_ime_manager.h" #include "chromeos/ime/extension_ime_util.h" #include "chromeos/ime/input_method_manager.h" #include "chromeos/ime/input_method_whitelist.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_utils.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/ime/chromeos/ime_bridge.h" #include "ui/base/ime/input_method_factory.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_observer.h" namespace chromeos { namespace input_method { class ScopedModeIndicatorObserverForTesting : public ModeIndicatorObserverInterface { public: ScopedModeIndicatorObserverForTesting() : max_widget_list_size_(0) { ModeIndicatorController::SetModeIndicatorObserverForTesting(this); } virtual ~ScopedModeIndicatorObserverForTesting() { for (size_t i = 0; i < widget_list_.size(); ++i) { widget_list_[i]->RemoveObserver(this); } ModeIndicatorController::SetModeIndicatorObserverForTesting(NULL); } gfx::Rect last_bounds() const { return last_bounds_; } bool is_displayed() const { return is_displayed_; } const std::vector& widget_list() const { return widget_list_; } size_t widget_list_size() const { return widget_list_.size(); } size_t max_widget_list_size() const { return max_widget_list_size_; } // ModeIndicatorObserverInterface override: virtual void AddModeIndicatorWidget(views::Widget* widget) OVERRIDE { widget_list_.push_back(widget); max_widget_list_size_ = std::max(max_widget_list_size_, widget_list_.size()); widget->AddObserver(this); } // views::WidgetObserver override: virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE { std::vector::iterator it = std::find(widget_list_.begin(), widget_list_.end(), widget); if (it != widget_list_.end()) widget_list_.erase(it); } // views::WidgetObserver override: virtual void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) OVERRIDE { last_bounds_ = widget->GetWindowBoundsInScreen(); is_displayed_ |= visible; } private: bool is_displayed_; gfx::Rect last_bounds_; size_t max_widget_list_size_; std::vector widget_list_; }; class ModeIndicatorBrowserTest : public InProcessBrowserTest { public: ModeIndicatorBrowserTest() : InProcessBrowserTest() {} virtual ~ModeIndicatorBrowserTest() {} virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { ui::SetUpInputMethodFactoryForTesting(); } void InitializeIMF() { InputMethodManager::Get() ->GetInputMethodUtil() ->InitXkbInputMethodsForTesting(); } private: DISALLOW_COPY_AND_ASSIGN(ModeIndicatorBrowserTest); }; namespace { // 43 is the designed size of the inner contents. // This value corresponds with kMinSize defined in // mode_indicator_delegate_view.cc. const int kInnerSize = 43; } // namespace IN_PROC_BROWSER_TEST_F(ModeIndicatorBrowserTest, Bounds) { InitializeIMF(); InputMethodManager* imm = InputMethodManager::Get(); ASSERT_TRUE(imm); std::vector keyboard_layouts; keyboard_layouts.push_back( extension_ime_util::GetInputMethodIDByEngineID("xkb:fr::fra")); // Add keyboard layouts to enable the mode indicator. imm->GetActiveIMEState()->EnableLoginLayouts("fr", keyboard_layouts); ASSERT_LT(1UL, imm->GetActiveIMEState()->GetNumActiveInputMethods()); chromeos::IMECandidateWindowHandlerInterface* candidate_window = chromeos::IMEBridge::Get()->GetCandidateWindowHandler(); candidate_window->FocusStateChanged(true); // Check if the size of the mode indicator is expected. gfx::Rect cursor1_bounds(100, 100, 1, 20); gfx::Rect mi1_bounds; { ScopedModeIndicatorObserverForTesting observer; candidate_window->SetCursorBounds(cursor1_bounds, cursor1_bounds); EXPECT_TRUE(imm->GetActiveIMEState()->SwitchToNextInputMethod()); mi1_bounds = observer.last_bounds(); // The bounds should be bigger than the inner size. EXPECT_LE(kInnerSize, mi1_bounds.width()); EXPECT_LE(kInnerSize, mi1_bounds.height()); EXPECT_TRUE(observer.is_displayed()); } // Check if the location of the mode indicator is coresponded to // the cursor bounds. gfx::Rect cursor2_bounds(50, 200, 1, 20); gfx::Rect mi2_bounds; { ScopedModeIndicatorObserverForTesting observer; candidate_window->SetCursorBounds(cursor2_bounds, cursor2_bounds); EXPECT_TRUE(imm->GetActiveIMEState()->SwitchToNextInputMethod()); mi2_bounds = observer.last_bounds(); EXPECT_TRUE(observer.is_displayed()); } EXPECT_EQ(cursor1_bounds.x() - cursor2_bounds.x(), mi1_bounds.x() - mi2_bounds.x()); EXPECT_EQ(cursor1_bounds.y() - cursor2_bounds.y(), mi1_bounds.y() - mi2_bounds.y()); EXPECT_EQ(mi1_bounds.width(), mi2_bounds.width()); EXPECT_EQ(mi1_bounds.height(), mi2_bounds.height()); const gfx::Rect screen_bounds = ash::Shell::GetScreen()->GetDisplayMatching(cursor1_bounds).work_area(); // Check if the location of the mode indicator is concidered with // the screen size. const gfx::Rect cursor3_bounds(100, screen_bounds.bottom() - 25, 1, 20); gfx::Rect mi3_bounds; { ScopedModeIndicatorObserverForTesting observer; candidate_window->SetCursorBounds(cursor3_bounds, cursor3_bounds); EXPECT_TRUE(imm->GetActiveIMEState()->SwitchToNextInputMethod()); mi3_bounds = observer.last_bounds(); EXPECT_TRUE(observer.is_displayed()); EXPECT_LT(mi3_bounds.bottom(), screen_bounds.bottom()); } } IN_PROC_BROWSER_TEST_F(ModeIndicatorBrowserTest, NumOfWidgets) { InitializeIMF(); InputMethodManager* imm = InputMethodManager::Get(); ASSERT_TRUE(imm); std::vector keyboard_layouts; keyboard_layouts.push_back( extension_ime_util::GetInputMethodIDByEngineID("xkb:fr::fra")); // Add keyboard layouts to enable the mode indicator. imm->GetActiveIMEState()->EnableLoginLayouts("fr", keyboard_layouts); ASSERT_LT(1UL, imm->GetActiveIMEState()->GetNumActiveInputMethods()); chromeos::IMECandidateWindowHandlerInterface* candidate_window = chromeos::IMEBridge::Get()->GetCandidateWindowHandler(); candidate_window->FocusStateChanged(true); { ScopedModeIndicatorObserverForTesting observer; EXPECT_TRUE(imm->GetActiveIMEState()->SwitchToNextInputMethod()); EXPECT_EQ(1UL, observer.max_widget_list_size()); const views::Widget* widget1 = observer.widget_list()[0]; EXPECT_TRUE(imm->GetActiveIMEState()->SwitchToNextInputMethod()); EXPECT_EQ(2UL, observer.max_widget_list_size()); // When a new mode indicator is displayed, the previous one should be // closed. content::RunAllPendingInMessageLoop(); EXPECT_EQ(1UL, observer.widget_list_size()); const views::Widget* widget2 = observer.widget_list()[0]; EXPECT_NE(widget1, widget2); } } } // namespace input_method } // namespace chromeos