123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- // Copyright (c) 2012 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 "ui/views/accessible_pane_view.h"
- #include <utility>
- #include "base/memory/raw_ptr.h"
- #include "build/build_config.h"
- #include "build/chromeos_buildflags.h"
- #include "ui/base/accelerators/accelerator.h"
- #include "ui/views/controls/button/label_button.h"
- #include "ui/views/layout/fill_layout.h"
- #include "ui/views/test/views_test_base.h"
- #include "ui/views/widget/widget.h"
- namespace views {
- // TODO(alicet): bring pane rotation into views and add tests.
- // See browser_view.cc for details.
- using AccessiblePaneViewTest = ViewsTestBase;
- class TestBarView : public AccessiblePaneView {
- public:
- TestBarView();
- TestBarView(const TestBarView&) = delete;
- TestBarView& operator=(const TestBarView&) = delete;
- ~TestBarView() override;
- LabelButton* child_button() const { return child_button_; }
- LabelButton* second_child_button() const { return second_child_button_; }
- LabelButton* third_child_button() const { return third_child_button_; }
- LabelButton* not_child_button() const { return not_child_button_.get(); }
- View* GetDefaultFocusableChild() override;
- private:
- void Init();
- raw_ptr<LabelButton> child_button_;
- // TODO(crbug.com/1298696): Breaks views_unittests.
- raw_ptr<LabelButton, DegradeToNoOpWhenMTE> second_child_button_;
- raw_ptr<LabelButton> third_child_button_;
- std::unique_ptr<LabelButton> not_child_button_;
- };
- TestBarView::TestBarView() {
- Init();
- set_allow_deactivate_on_esc(true);
- }
- TestBarView::~TestBarView() = default;
- void TestBarView::Init() {
- SetLayoutManager(std::make_unique<FillLayout>());
- std::u16string label;
- child_button_ = AddChildView(std::make_unique<LabelButton>());
- second_child_button_ = AddChildView(std::make_unique<LabelButton>());
- third_child_button_ = AddChildView(std::make_unique<LabelButton>());
- not_child_button_ = std::make_unique<LabelButton>();
- }
- View* TestBarView::GetDefaultFocusableChild() {
- return child_button_;
- }
- TEST_F(AccessiblePaneViewTest, SimpleSetPaneFocus) {
- TestBarView* test_view = new TestBarView();
- std::unique_ptr<Widget> widget(new Widget());
- Widget::InitParams params =
- CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.bounds = gfx::Rect(50, 50, 650, 650);
- widget->Init(std::move(params));
- View* root = widget->GetRootView();
- root->AddChildView(test_view);
- widget->Show();
- widget->Activate();
- // Set pane focus succeeds, focus on child.
- EXPECT_TRUE(test_view->SetPaneFocusAndFocusDefault());
- EXPECT_EQ(test_view, test_view->GetPaneFocusTraversable());
- EXPECT_EQ(test_view->child_button(),
- test_view->GetWidget()->GetFocusManager()->GetFocusedView());
- // Set focus on non child view, focus failed, stays on pane.
- EXPECT_TRUE(test_view->SetPaneFocus(test_view->not_child_button()));
- EXPECT_FALSE(test_view->not_child_button() ==
- test_view->GetWidget()->GetFocusManager()->GetFocusedView());
- EXPECT_EQ(test_view->child_button(),
- test_view->GetWidget()->GetFocusManager()->GetFocusedView());
- widget->CloseNow();
- widget.reset();
- }
- TEST_F(AccessiblePaneViewTest, SetPaneFocusAndRestore) {
- View* test_view_main = new View();
- std::unique_ptr<Widget> widget_main(new Widget());
- Widget::InitParams params_main =
- CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
- params_main.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params_main.bounds = gfx::Rect(0, 0, 20, 20);
- widget_main->Init(std::move(params_main));
- View* root_main = widget_main->GetRootView();
- root_main->AddChildView(test_view_main);
- widget_main->Show();
- widget_main->Activate();
- test_view_main->GetFocusManager()->SetFocusedView(test_view_main);
- EXPECT_TRUE(widget_main->IsActive());
- EXPECT_TRUE(test_view_main->HasFocus());
- TestBarView* test_view_bar = new TestBarView();
- std::unique_ptr<Widget> widget_bar(new Widget());
- Widget::InitParams params_bar =
- CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
- params_bar.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params_bar.bounds = gfx::Rect(50, 50, 650, 650);
- widget_bar->Init(std::move(params_bar));
- View* root_bar = widget_bar->GetRootView();
- root_bar->AddChildView(test_view_bar);
- widget_bar->Show();
- widget_bar->Activate();
- // Set pane focus succeeds, focus on child.
- EXPECT_TRUE(test_view_bar->SetPaneFocusAndFocusDefault());
- EXPECT_FALSE(test_view_main->HasFocus());
- EXPECT_FALSE(widget_main->IsActive());
- EXPECT_EQ(test_view_bar, test_view_bar->GetPaneFocusTraversable());
- EXPECT_EQ(test_view_bar->child_button(),
- test_view_bar->GetWidget()->GetFocusManager()->GetFocusedView());
- // Deactivate() is only reliable on Ash. On Windows it uses
- // ::GetNextWindow() to simply activate another window, and which one is not
- // predictable. On Mac, Deactivate() is not implemented. Note that
- // TestBarView calls set_allow_deactivate_on_esc(true), which is only
- // otherwise used in Ash.
- #if !BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH)
- // Esc should deactivate the widget.
- test_view_bar->AcceleratorPressed(test_view_bar->escape_key());
- EXPECT_TRUE(widget_main->IsActive());
- EXPECT_FALSE(widget_bar->IsActive());
- #endif
- widget_bar->CloseNow();
- widget_bar.reset();
- widget_main->CloseNow();
- widget_main.reset();
- }
- TEST_F(AccessiblePaneViewTest, TwoSetPaneFocus) {
- TestBarView* test_view = new TestBarView();
- TestBarView* test_view_2 = new TestBarView();
- std::unique_ptr<Widget> widget(new Widget());
- Widget::InitParams params =
- CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.bounds = gfx::Rect(50, 50, 650, 650);
- widget->Init(std::move(params));
- View* root = widget->GetRootView();
- root->AddChildView(test_view);
- root->AddChildView(test_view_2);
- widget->Show();
- widget->Activate();
- // Set pane focus succeeds, focus on child.
- EXPECT_TRUE(test_view->SetPaneFocusAndFocusDefault());
- EXPECT_EQ(test_view, test_view->GetPaneFocusTraversable());
- EXPECT_EQ(test_view->child_button(),
- test_view->GetWidget()->GetFocusManager()->GetFocusedView());
- // Set focus on another test_view, focus move to that pane.
- EXPECT_TRUE(test_view_2->SetPaneFocus(test_view_2->second_child_button()));
- EXPECT_FALSE(test_view->child_button() ==
- test_view->GetWidget()->GetFocusManager()->GetFocusedView());
- EXPECT_EQ(test_view_2->second_child_button(),
- test_view->GetWidget()->GetFocusManager()->GetFocusedView());
- widget->CloseNow();
- widget.reset();
- }
- TEST_F(AccessiblePaneViewTest, PaneFocusTraversal) {
- TestBarView* test_view = new TestBarView();
- TestBarView* original_test_view = new TestBarView();
- std::unique_ptr<Widget> widget(new Widget());
- Widget::InitParams params =
- CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.bounds = gfx::Rect(50, 50, 650, 650);
- widget->Init(std::move(params));
- View* root = widget->GetRootView();
- root->AddChildView(original_test_view);
- root->AddChildView(test_view);
- widget->Show();
- widget->Activate();
- // Set pane focus on first view.
- EXPECT_TRUE(original_test_view->SetPaneFocus(
- original_test_view->third_child_button()));
- // Test traversal in second view.
- // Set pane focus on second child.
- EXPECT_TRUE(test_view->SetPaneFocus(test_view->second_child_button()));
- // home
- test_view->AcceleratorPressed(test_view->home_key());
- EXPECT_EQ(test_view->child_button(),
- test_view->GetWidget()->GetFocusManager()->GetFocusedView());
- // end
- test_view->AcceleratorPressed(test_view->end_key());
- EXPECT_EQ(test_view->third_child_button(),
- test_view->GetWidget()->GetFocusManager()->GetFocusedView());
- // left
- test_view->AcceleratorPressed(test_view->left_key());
- EXPECT_EQ(test_view->second_child_button(),
- test_view->GetWidget()->GetFocusManager()->GetFocusedView());
- // right, right
- test_view->AcceleratorPressed(test_view->right_key());
- test_view->AcceleratorPressed(test_view->right_key());
- EXPECT_EQ(test_view->child_button(),
- test_view->GetWidget()->GetFocusManager()->GetFocusedView());
- // ESC
- test_view->AcceleratorPressed(test_view->escape_key());
- EXPECT_EQ(original_test_view->third_child_button(),
- test_view->GetWidget()->GetFocusManager()->GetFocusedView());
- widget->CloseNow();
- widget.reset();
- }
- // TODO(crbug.com/1314275): Re-enable this test
- #if defined(ADDRESS_SANITIZER) && defined(LEAK_SANITIZER)
- #define MAYBE_DoesntCrashOnEscapeWithRemovedView \
- DISABLED_DoesntCrashOnEscapeWithRemovedView
- #else
- #define MAYBE_DoesntCrashOnEscapeWithRemovedView \
- DoesntCrashOnEscapeWithRemovedView
- #endif
- TEST_F(AccessiblePaneViewTest, MAYBE_DoesntCrashOnEscapeWithRemovedView) {
- TestBarView* test_view1 = new TestBarView();
- TestBarView* test_view2 = new TestBarView();
- Widget widget;
- Widget::InitParams params =
- CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.bounds = gfx::Rect(50, 50, 650, 650);
- widget.Init(std::move(params));
- View* root = widget.GetRootView();
- root->AddChildView(test_view1);
- root->AddChildView(test_view2);
- widget.Show();
- widget.Activate();
- View* v1 = test_view1->child_button();
- View* v2 = test_view2->child_button();
- // Do the following:
- // 1. focus |v1|.
- // 2. focus |v2|. This makes |test_view2| remember |v1| as having focus.
- // 3. Removes |v1| from it's parent.
- // 4. Presses escape on |test_view2|. Escape attempts to revert focus to |v1|
- // (because of step 2). Because |v1| is not in a widget this should not
- // attempt to focus anything.
- EXPECT_TRUE(test_view1->SetPaneFocus(v1));
- EXPECT_TRUE(test_view2->SetPaneFocus(v2));
- v1->parent()->RemoveChildView(v1);
- // This shouldn't hit a CHECK in the FocusManager.
- EXPECT_TRUE(test_view2->AcceleratorPressed(test_view2->escape_key()));
- }
- } // namespace views
|