Commit 6044414a authored by Manu Cornet's avatar Manu Cornet Committed by Commit Bot

CrOS: Handle focus rotation between shelf and status area

Note that the main logic to handle focus transitions from status area
--> shelf was added in CL 1475149. This makes some small tweaks and
mainly adds the logic for transitions in the other direction.

This is a little more involved because we need to handle situations
where the overflow bubble is showing.

This also adds some extensive tests covering focus-cycling between all
these elements.

You can see a screencast of what this looks like in
    https://bugs.chromium.org/p/chromium/issues/detail?id=753409#c34

Bug: 753409
Change-Id: Ia903c27f54226b4d67cf796d2d076f9da72225a9
Reviewed-on: https://chromium-review.googlesource.com/c/1477464
Commit-Queue: Manu Cornet <manucornet@chromium.org>
Reviewed-by: default avatarSammie Quon <sammiequon@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#634723}
parent 611faa01
...@@ -430,13 +430,11 @@ void LoginShelfView::AboutToRequestFocusFromTabTraversal(bool reverse) { ...@@ -430,13 +430,11 @@ void LoginShelfView::AboutToRequestFocusFromTabTraversal(bool reverse) {
} }
} else { } else {
// Focus goes to status area. // Focus goes to status area.
Shelf::ForWindow(GetWidget()->GetNativeWindow()) StatusAreaWidget* status_area_widget =
->GetStatusAreaWidget() Shelf::ForWindow(GetWidget()->GetNativeWindow())->GetStatusAreaWidget();
->status_area_widget_delegate() status_area_widget->status_area_widget_delegate()
->set_default_last_focusable_child(reverse); ->set_default_last_focusable_child(reverse);
Shell::Get()->focus_cycler()->FocusWidget( Shell::Get()->focus_cycler()->FocusWidget(status_area_widget);
Shelf::ForWindow(GetWidget()->GetNativeWindow())
->GetStatusAreaWidget());
} }
} }
......
...@@ -54,6 +54,10 @@ bool ShelfButton::OnMouseDragged(const ui::MouseEvent& event) { ...@@ -54,6 +54,10 @@ bool ShelfButton::OnMouseDragged(const ui::MouseEvent& event) {
return true; return true;
} }
void ShelfButton::AboutToRequestFocusFromTabTraversal(bool reverse) {
shelf_view_->OnShelfButtonAboutToRequestFocusFromTabTraversal(this, reverse);
}
// Do not remove this function to avoid unnecessary ChromeVox announcement // Do not remove this function to avoid unnecessary ChromeVox announcement
// triggered by Button::GetAccessibleNodeData. (See https://crbug.com/932200) // triggered by Button::GetAccessibleNodeData. (See https://crbug.com/932200)
void ShelfButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { void ShelfButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
......
...@@ -23,6 +23,7 @@ class ASH_EXPORT ShelfButton : public views::Button { ...@@ -23,6 +23,7 @@ class ASH_EXPORT ShelfButton : public views::Button {
void OnMouseReleased(const ui::MouseEvent& event) override; void OnMouseReleased(const ui::MouseEvent& event) override;
void OnMouseCaptureLost() override; void OnMouseCaptureLost() override;
bool OnMouseDragged(const ui::MouseEvent& event) override; bool OnMouseDragged(const ui::MouseEvent& event) override;
void AboutToRequestFocusFromTabTraversal(bool reverse) override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
bool GetTooltipText(const gfx::Point& p, bool GetTooltipText(const gfx::Point& p,
base::string16* tooltip) const override; base::string16* tooltip) const override;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <memory> #include <memory>
#include "ash/drag_drop/drag_image_view.h" #include "ash/drag_drop/drag_image_view.h"
#include "ash/focus_cycler.h"
#include "ash/metrics/user_metrics_recorder.h" #include "ash/metrics/user_metrics_recorder.h"
#include "ash/public/cpp/ash_constants.h" #include "ash/public/cpp/ash_constants.h"
#include "ash/public/cpp/shelf_item_delegate.h" #include "ash/public/cpp/shelf_item_delegate.h"
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
#include "ash/system/model/system_tray_model.h" #include "ash/system/model/system_tray_model.h"
#include "ash/system/model/virtual_keyboard_model.h" #include "ash/system/model/virtual_keyboard_model.h"
#include "ash/system/status_area_widget.h" #include "ash/system/status_area_widget.h"
#include "ash/system/status_area_widget_delegate.h"
#include "ash/wm/mru_window_tracker.h" #include "ash/wm/mru_window_tracker.h"
#include "ash/wm/root_window_finder.h" #include "ash/wm/root_window_finder.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h"
...@@ -204,7 +206,7 @@ class ShelfFocusSearch : public views::FocusSearch { ...@@ -204,7 +206,7 @@ class ShelfFocusSearch : public views::FocusSearch {
new_index = 0; new_index = 0;
if (new_index >= overflow_cutoff) if (new_index >= overflow_cutoff)
shelf_view_->shelf_widget()->set_activated_from_overflow_bubble(true); shelf_view_->shelf_widget()->set_activated_from_other_widget(true);
return focusable_views[new_index]; return focusable_views[new_index];
} }
...@@ -816,13 +818,44 @@ const std::vector<aura::Window*> ShelfView::GetOpenWindowsForShelfView( ...@@ -816,13 +818,44 @@ const std::vector<aura::Window*> ShelfView::GetOpenWindowsForShelfView(
return open_windows; return open_windows;
} }
views::View* ShelfView::FindFirstFocusableChild() {
if (is_overflow_mode())
return main_shelf()->FindFirstFocusableChild();
return view_model_->view_at(first_visible_index());
}
views::View* ShelfView::FindLastFocusableChild() {
if (is_showing_overflow_bubble())
return overflow_shelf()->FindLastFocusableChild();
return overflow_button_->visible()
? overflow_button_
: view_model_->view_at(last_visible_index());
}
views::View* ShelfView::FindFirstOrLastFocusableChild(bool last) { views::View* ShelfView::FindFirstOrLastFocusableChild(bool last) {
if (last) { return last ? FindLastFocusableChild() : FindFirstFocusableChild();
return overflow_button_->visible() }
? overflow_button_
: view_model_->view_at(last_visible_index()); void ShelfView::OnShelfButtonAboutToRequestFocusFromTabTraversal(
} else { ShelfButton* button,
return view_model_->view_at(first_visible_index()); bool reverse) {
if (is_overflow_mode()) {
main_shelf()->OnShelfButtonAboutToRequestFocusFromTabTraversal(button,
reverse);
return;
}
// The logic here seems backwards, but is actually correct. For instance if
// the ShelfView's internal focus cycling logic attemmpts to focus the first
// child (e.g. app list button) after hitting Tab, we intercept that and
// instead, advance through to the status area.
if ((reverse && button == FindLastFocusableChild()) ||
(!reverse && button == FindFirstFocusableChild())) {
StatusAreaWidget* status_area_widget =
Shelf::ForWindow(GetWidget()->GetNativeWindow())->GetStatusAreaWidget();
status_area_widget->status_area_widget_delegate()
->set_default_last_focusable_child(reverse);
Shell::Get()->focus_cycler()->FocusWidget(status_area_widget);
} }
} }
......
...@@ -54,6 +54,7 @@ class OverflowButton; ...@@ -54,6 +54,7 @@ class OverflowButton;
class ScopedRootWindowForNewWindows; class ScopedRootWindowForNewWindows;
class Shelf; class Shelf;
class ShelfAppButton; class ShelfAppButton;
class ShelfButton;
class ShelfModel; class ShelfModel;
struct ShelfItem; struct ShelfItem;
class ShelfMenuModelAdapter; class ShelfMenuModelAdapter;
...@@ -264,7 +265,20 @@ class ASH_EXPORT ShelfView : public views::View, ...@@ -264,7 +265,20 @@ class ASH_EXPORT ShelfView : public views::View,
const std::vector<aura::Window*> GetOpenWindowsForShelfView( const std::vector<aura::Window*> GetOpenWindowsForShelfView(
views::View* view); views::View* view);
// The three methods below return the first or last focusable child of the
// set including both the main shelf and the overflow shelf it it's showing.
// - The first focusable child is either the app list button, or the back
// button in tablet mode.
// - The last focusable child can be either 1) the last app icon on the main
// shelf if there aren't enough apps to overflow, 2) the overflow button
// if it's visible but the overflow bubble isn't showing, or 3) the last
// app icon in the overflow bubble if it's showing.
views::View* FindFirstOrLastFocusableChild(bool last); views::View* FindFirstOrLastFocusableChild(bool last);
views::View* FindFirstFocusableChild();
views::View* FindLastFocusableChild();
void OnShelfButtonAboutToRequestFocusFromTabTraversal(ShelfButton* button,
bool reverse);
// Return the view model for test purposes. // Return the view model for test purposes.
const views::ViewModel* view_model_for_test() const { const views::ViewModel* view_model_for_test() const {
...@@ -292,6 +306,9 @@ class ASH_EXPORT ShelfView : public views::View, ...@@ -292,6 +306,9 @@ class ASH_EXPORT ShelfView : public views::View,
// small resolution screen, the overflow bubble can show the app list // small resolution screen, the overflow bubble can show the app list
// button. // button.
bool is_overflow_mode() const { return overflow_mode_; } bool is_overflow_mode() const { return overflow_mode_; }
bool is_showing_overflow_bubble() const {
return overflow_bubble_ && overflow_bubble_->IsShowing();
}
int first_visible_index() const { return first_visible_index_; } int first_visible_index() const { return first_visible_index_; }
int last_visible_index() const { return last_visible_index_; } int last_visible_index() const { return last_visible_index_; }
......
...@@ -90,6 +90,16 @@ int64_t GetPrimaryDisplayId() { ...@@ -90,6 +90,16 @@ int64_t GetPrimaryDisplayId() {
return display::Screen::GetScreen()->GetPrimaryDisplay().id(); return display::Screen::GetScreen()->GetPrimaryDisplay().id();
} }
void ExpectFocused(views::View* view) {
EXPECT_TRUE(view->GetWidget()->IsActive());
EXPECT_TRUE(view->Contains(view->GetFocusManager()->GetFocusedView()));
}
void ExpectNotFocused(views::View* view) {
EXPECT_FALSE(view->GetWidget()->IsActive());
EXPECT_FALSE(view->Contains(view->GetFocusManager()->GetFocusedView()));
}
class TestShelfObserver : public ShelfObserver { class TestShelfObserver : public ShelfObserver {
public: public:
explicit TestShelfObserver(Shelf* shelf) : shelf_(shelf) { explicit TestShelfObserver(Shelf* shelf) : shelf_(shelf) {
...@@ -3450,8 +3460,13 @@ class ShelfViewFocusTest : public ShelfViewTest { ...@@ -3450,8 +3460,13 @@ class ShelfViewFocusTest : public ShelfViewTest {
AddAppShortcut(); AddAppShortcut();
AddAppShortcut(); AddAppShortcut();
// Focus the shelf.
Shelf* shelf = Shelf::ForWindow(Shell::GetPrimaryRootWindow()); Shelf* shelf = Shelf::ForWindow(Shell::GetPrimaryRootWindow());
gfx::NativeWindow window = shelf->shelf_widget()->GetNativeWindow();
status_area_ = RootWindowController::ForWindow(window)
->GetStatusAreaWidget()
->GetContentsView();
// Focus the shelf.
Shell::Get()->focus_cycler()->FocusWidget(shelf->shelf_widget()); Shell::Get()->focus_cycler()->FocusWidget(shelf->shelf_widget());
} }
...@@ -3466,6 +3481,9 @@ class ShelfViewFocusTest : public ShelfViewTest { ...@@ -3466,6 +3481,9 @@ class ShelfViewFocusTest : public ShelfViewTest {
ui::EventFlags::EF_SHIFT_DOWN); ui::EventFlags::EF_SHIFT_DOWN);
} }
protected:
views::View* status_area_ = nullptr;
private: private:
DISALLOW_COPY_AND_ASSIGN(ShelfViewFocusTest); DISALLOW_COPY_AND_ASSIGN(ShelfViewFocusTest);
}; };
...@@ -3496,19 +3514,16 @@ TEST_F(ShelfViewFocusTest, ForwardCycling) { ...@@ -3496,19 +3514,16 @@ TEST_F(ShelfViewFocusTest, ForwardCycling) {
DoTab(); DoTab();
DoTab(); DoTab();
EXPECT_TRUE(test_api_->GetViewAt(4)->HasFocus()); EXPECT_TRUE(test_api_->GetViewAt(4)->HasFocus());
// The last element is currently focused so pressing tab once should advance
// focus to the first element.
DoTab();
EXPECT_TRUE(test_api_->GetViewAt(1)->HasFocus());
} }
// Tests that the expected views have focus when cycling backwards through shelf // Tests that the expected views have focus when cycling backwards through shelf
// items with shift tab. // items with shift tab.
TEST_F(ShelfViewFocusTest, BackwardCycling) { TEST_F(ShelfViewFocusTest, BackwardCycling) {
// The first element is currently focused so pressing shift tab once should // The first element is currently focused. Let's advance to the last element
// advance focus to the last element. // first.
DoShiftTab(); DoTab();
DoTab();
DoTab();
EXPECT_TRUE(test_api_->GetViewAt(4)->HasFocus()); EXPECT_TRUE(test_api_->GetViewAt(4)->HasFocus());
// Pressing shift tab once should advance focus to the previous element. // Pressing shift tab once should advance focus to the previous element.
...@@ -3526,6 +3541,41 @@ TEST_F(ShelfViewFocusTest, OverflowNotActivatedWhenOpened) { ...@@ -3526,6 +3541,41 @@ TEST_F(ShelfViewFocusTest, OverflowNotActivatedWhenOpened) {
EXPECT_TRUE(::wm::IsActiveWindow(window.get())); EXPECT_TRUE(::wm::IsActiveWindow(window.get()));
} }
// Verifies that focus moves as expected between the shelf and the status area.
TEST_F(ShelfViewFocusTest, FocusCyclingBetweenShelfAndStatusWidget) {
// The first element of the shelf is focused at start.
// Focus the next few elements.
DoTab();
EXPECT_TRUE(test_api_->GetViewAt(2)->HasFocus());
DoTab();
EXPECT_TRUE(test_api_->GetViewAt(3)->HasFocus());
DoTab();
EXPECT_TRUE(test_api_->GetViewAt(4)->HasFocus());
// This is the last element. Tabbing once more should go into the status
// area.
DoTab();
ExpectNotFocused(shelf_view_);
ExpectFocused(status_area_);
// Shift-tab: we should be back at the last element in the shelf.
DoShiftTab();
EXPECT_TRUE(test_api_->GetViewAt(4)->HasFocus());
ExpectNotFocused(status_area_);
// Go into the status area again.
DoTab();
ExpectNotFocused(shelf_view_);
ExpectFocused(status_area_);
// And keep going forward, now we should be cycling back to the first shelf
// element.
DoTab();
EXPECT_TRUE(test_api_->GetViewAt(1)->HasFocus());
ExpectNotFocused(status_area_);
}
class ShelfViewOverflowFocusTest : public ShelfViewFocusTest { class ShelfViewOverflowFocusTest : public ShelfViewFocusTest {
public: public:
ShelfViewOverflowFocusTest() = default; ShelfViewOverflowFocusTest() = default;
...@@ -3598,16 +3648,13 @@ TEST_F(ShelfViewOverflowFocusTest, ForwardCycling) { ...@@ -3598,16 +3648,13 @@ TEST_F(ShelfViewOverflowFocusTest, ForwardCycling) {
// Focus the overflow button. // Focus the overflow button.
DoTab(); DoTab();
EXPECT_TRUE(test_api_->overflow_button()->HasFocus()); EXPECT_TRUE(test_api_->overflow_button()->HasFocus());
DoTab();
EXPECT_TRUE(test_api_->GetViewAt(1)->HasFocus());
} }
// Tests that when cycling through the items with shift tab, the items in the // Tests that when cycling through the items with shift tab, the items in the
// overflow shelf are ignored because it is not visible. // overflow shelf are ignored because it is not visible.
TEST_F(ShelfViewOverflowFocusTest, BackwardCycling) { TEST_F(ShelfViewOverflowFocusTest, BackwardCycling) {
DoShiftTab(); while (!test_api_->overflow_button()->HasFocus())
EXPECT_TRUE(test_api_->overflow_button()->HasFocus()); DoTab();
DoShiftTab(); DoShiftTab();
EXPECT_TRUE(test_api_->GetViewAt(last_item_on_main_shelf_index_)->HasFocus()); EXPECT_TRUE(test_api_->GetViewAt(last_item_on_main_shelf_index_)->HasFocus());
...@@ -3634,20 +3681,6 @@ TEST_F(ShelfViewOverflowFocusTest, ForwardCyclingWithBubbleOpen) { ...@@ -3634,20 +3681,6 @@ TEST_F(ShelfViewOverflowFocusTest, ForwardCyclingWithBubbleOpen) {
const int first_index_overflow_shelf = last_item_on_main_shelf_index_ + 1; const int first_index_overflow_shelf = last_item_on_main_shelf_index_ + 1;
EXPECT_TRUE(overflow_shelf_test_api_->GetViewAt(first_index_overflow_shelf) EXPECT_TRUE(overflow_shelf_test_api_->GetViewAt(first_index_overflow_shelf)
->HasFocus()); ->HasFocus());
// Focus the last item on the overflow shelf.
test_api_->overflow_bubble()
->bubble_view()
->GetWidget()
->GetFocusManager()
->SetFocusedView(overflow_shelf_test_api_->GetViewAt(
overflow_shelf_test_api_->GetLastVisibleIndex()));
// Tests that after pressing tab once more, the main shelf widget now is
// active, and the first item on the main shelf has focus.
DoTab();
EXPECT_TRUE(shelf_view_->shelf_widget()->IsActive());
EXPECT_TRUE(test_api_->GetViewAt(1)->HasFocus());
} }
// Tests that backwards cycling through elements with shift tab works as // Tests that backwards cycling through elements with shift tab works as
...@@ -3655,23 +3688,11 @@ TEST_F(ShelfViewOverflowFocusTest, ForwardCyclingWithBubbleOpen) { ...@@ -3655,23 +3688,11 @@ TEST_F(ShelfViewOverflowFocusTest, ForwardCyclingWithBubbleOpen) {
TEST_F(ShelfViewOverflowFocusTest, BackwardCyclingWithBubbleOpen) { TEST_F(ShelfViewOverflowFocusTest, BackwardCyclingWithBubbleOpen) {
OpenOverflow(); OpenOverflow();
// Tests that after pressing shift tab once, the overflow shelf bubble is
// active and the last item on the overflow shelf has focus.
DoShiftTab();
EXPECT_TRUE(
test_api_->overflow_bubble()->bubble_view()->GetWidget()->IsActive());
const int first_index_overflow_shelf = last_item_on_main_shelf_index_ + 1;
EXPECT_TRUE(overflow_shelf_test_api_
->GetViewAt(overflow_shelf_test_api_->GetLastVisibleIndex())
->HasFocus());
// Focus the first item on the overflow shelf. // Focus the first item on the overflow shelf.
test_api_->overflow_bubble() while (!test_api_->overflow_bubble()->bubble_view()->GetWidget()->IsActive())
->bubble_view() DoTab();
->GetWidget() EXPECT_FALSE(shelf_view_->shelf_widget()->IsActive());
->GetFocusManager() EXPECT_FALSE(test_api_->overflow_button()->HasFocus());
->SetFocusedView(
overflow_shelf_test_api_->GetViewAt(first_index_overflow_shelf));
// Tests that after pressing shift tab once, the main shelf is active and // Tests that after pressing shift tab once, the main shelf is active and
// the overflow button has focus. // the overflow button has focus.
...@@ -3684,4 +3705,60 @@ TEST_F(ShelfViewOverflowFocusTest, BackwardCyclingWithBubbleOpen) { ...@@ -3684,4 +3705,60 @@ TEST_F(ShelfViewOverflowFocusTest, BackwardCyclingWithBubbleOpen) {
EXPECT_TRUE(test_api_->GetViewAt(last_item_on_main_shelf_index_)->HasFocus()); EXPECT_TRUE(test_api_->GetViewAt(last_item_on_main_shelf_index_)->HasFocus());
} }
// Verifies that focus moves as expected between the shelf and the status area
// when the overflow bubble is showing.
TEST_F(ShelfViewOverflowFocusTest, FocusCyclingBetweenShelfAndStatusWidget) {
OpenOverflow();
const int first_index_overflow_shelf = last_item_on_main_shelf_index_ + 1;
// We start with the first shelf item focused. Shift-tab should focus the
// status area.
DoShiftTab();
ExpectNotFocused(shelf_view_);
ExpectFocused(status_area_);
// Focus the shelf again.
DoTab();
ExpectFocused(shelf_view_);
EXPECT_TRUE(test_api_->GetViewAt(1)->HasFocus());
ExpectNotFocused(status_area_);
// Now advance to the last item on the main shelf.
while (!test_api_->GetViewAt(last_item_on_main_shelf_index_)->HasFocus())
DoTab();
ExpectNotFocused(status_area_);
// Focus the overflow button
DoTab();
EXPECT_TRUE(test_api_->overflow_button()->HasFocus());
// Tab into the overflow bubble.
DoTab();
EXPECT_TRUE(overflow_shelf_test_api_->GetViewAt(first_index_overflow_shelf)
->HasFocus());
// Back onto the overflow button itself.
DoShiftTab();
EXPECT_TRUE(test_api_->overflow_button()->HasFocus());
// Now advance until we get to the status area.
while (!status_area_->GetWidget()->IsActive())
DoTab();
// Go back once, we should be in the overflow bubble again.
DoShiftTab();
ExpectNotFocused(status_area_);
ExpectFocused(test_api_->overflow_bubble()->bubble_view());
// Go into the status area again.
DoTab();
ExpectFocused(status_area_);
// Now advance until the status area isn't focused anymore.
while (status_area_->GetWidget()->IsActive())
DoTab();
// This should have brought focus to the first element on the shelf.
EXPECT_TRUE(test_api_->GetViewAt(1)->HasFocus());
}
} // namespace ash } // namespace ash
...@@ -483,15 +483,24 @@ void ShelfWidget::set_default_last_focusable_child( ...@@ -483,15 +483,24 @@ void ShelfWidget::set_default_last_focusable_child(
default_last_focusable_child); default_last_focusable_child);
} }
void ShelfWidget::FocusFirstOrLastFocusableChild(bool last) {
// This is only ever called during an active session.
if (!shelf_view_->visible())
return;
views::View* to_focus = shelf_view_->FindFirstOrLastFocusableChild(last);
Shell::Get()->focus_cycler()->FocusWidget(to_focus->GetWidget());
to_focus->GetFocusManager()->SetFocusedView(to_focus);
}
void ShelfWidget::OnWidgetActivationChanged(views::Widget* widget, void ShelfWidget::OnWidgetActivationChanged(views::Widget* widget,
bool active) { bool active) {
if (active) { if (active) {
// Do not focus the default element if the widget activation came from the // Do not focus the default element if the widget activation came from the
// overflow bubble focus cycling. The setter of // another widget's focus cycling. The setter of
// |activated_from_overflow_bubble_| should handle focusing the correct // |activated_from_other_widget_| should handle focusing the correct view.
// view. if (activated_from_other_widget_) {
if (activated_from_overflow_bubble_) { activated_from_other_widget_ = false;
activated_from_overflow_bubble_ = false;
return; return;
} }
delegate_view_->SetPaneFocusAndFocusDefault(); delegate_view_->SetPaneFocusAndFocusDefault();
......
...@@ -103,6 +103,10 @@ class ASH_EXPORT ShelfWidget : public views::Widget, ...@@ -103,6 +103,10 @@ class ASH_EXPORT ShelfWidget : public views::Widget,
void set_default_last_focusable_child(bool default_last_focusable_child); void set_default_last_focusable_child(bool default_last_focusable_child);
// Finds the first or last focusable child of the set (main shelf + overflow)
// and focuses it.
void FocusFirstOrLastFocusableChild(bool last);
// Overridden from views::WidgetObserver: // Overridden from views::WidgetObserver:
void OnWidgetActivationChanged(views::Widget* widget, bool active) override; void OnWidgetActivationChanged(views::Widget* widget, bool active) override;
...@@ -127,8 +131,8 @@ class ASH_EXPORT ShelfWidget : public views::Widget, ...@@ -127,8 +131,8 @@ class ASH_EXPORT ShelfWidget : public views::Widget,
return &background_animator_; return &background_animator_;
} }
void set_activated_from_overflow_bubble(bool val) { void set_activated_from_other_widget(bool val) {
activated_from_overflow_bubble_ = val; activated_from_other_widget_ = val;
} }
private: private:
...@@ -166,10 +170,10 @@ class ASH_EXPORT ShelfWidget : public views::Widget, ...@@ -166,10 +170,10 @@ class ASH_EXPORT ShelfWidget : public views::Widget,
// Owned by the views hierarchy. // Owned by the views hierarchy.
LoginShelfView* const login_shelf_view_; LoginShelfView* const login_shelf_view_;
// Set to true when the widget is activated from the shelf overflow bubble. // Set to true when the widget is activated from another widget. Do not
// Do not focus the default element in this case. This should be set when // focus the default element in this case. This should be set when
// cycling focus from the overflow bubble to the main shelf. // cycling focus from another widget to the shelf.
bool activated_from_overflow_bubble_ = false; bool activated_from_other_widget_ = false;
ScopedSessionObserver scoped_session_observer_; ScopedSessionObserver scoped_session_observer_;
......
...@@ -270,21 +270,34 @@ void TrayBackgroundView::AboutToRequestFocusFromTabTraversal(bool reverse) { ...@@ -270,21 +270,34 @@ void TrayBackgroundView::AboutToRequestFocusFromTabTraversal(bool reverse) {
if (!delegate || !delegate->ShouldFocusOut(reverse)) if (!delegate || !delegate->ShouldFocusOut(reverse))
return; return;
// At this point, we know we should focus out of the status widget. // At this point, we know we should focus out of the status widget. It
// If we're not using a views-based shelf, delegate to system tray focus // remains to be determined whether we should bring focus to the shelf, or
// observers to decide where the focus goes next. // whether we should delegate to system tray focus observers to decide
// where the focus goes next.
bool should_focus_shelf = true;
if (!ShelfWidget::IsUsingViewsShelf()) { if (!ShelfWidget::IsUsingViewsShelf()) {
Shell::Get()->system_tray_notifier()->NotifyFocusOut(reverse); // Never bring the focus to the shelf if it's not a views-based shelf as
// it is visually not on par with the status widget.
return; return;
} }
// If we are using a views-based shelf: // If we are using a views-based shelf:
// * If we're going in reverse, always focus the shelf. // * If we're in an active session, always bring focus to the shelf whether
// * If we're going forward, focus the shelf in an active session, and let // we are going in reverse or not.
// the system tray focus observers focus the lock/login view otherwise. // * Otherwise (login/lock screen, OOBE), bring focus to the shelf only
if (reverse) { // if we're going in reverse; if we're going forward, let the system tray
// focus observers focus the lock/login view.
if (shelf->shelf_widget()->login_shelf_view()->visible()) {
// Login/lock screen or OOBE.
should_focus_shelf = reverse;
}
if (should_focus_shelf) {
shelf->shelf_widget()->set_default_last_focusable_child(reverse); shelf->shelf_widget()->set_default_last_focusable_child(reverse);
shelf->shelf_widget()->set_activated_from_other_widget(true);
Shell::Get()->focus_cycler()->FocusWidget(shelf->shelf_widget()); Shell::Get()->focus_cycler()->FocusWidget(shelf->shelf_widget());
shelf->shelf_widget()->FocusFirstOrLastFocusableChild(reverse);
} else { } else {
Shell::Get()->system_tray_notifier()->NotifyFocusOut(reverse); Shell::Get()->system_tray_notifier()->NotifyFocusOut(reverse);
} }
......
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