Commit 0a4c7d45 authored by Toni Barzic's avatar Toni Barzic Committed by Commit Bot

Restack shelf widget on session state change

In active user session, shelf container has multiple widgets -
navigation widget, hotseat widget, status area widget, shelf widget.
Of these, shelf widget contains the shelf background, and its bounds
intersect with all other widgets. For this reason, it's expected to be
stacked at the bottom of the container. The shelf widget stacking is
set up during widget creation. This works in active session state, as
the shelf widget itself is not expected to be activated, and thus
stacked at the top of the container.
For login shelf, though, the shelf widget can get activated (it contains
login shelf buttons, which can be focused, e.g. by tab traversal). Shelf
widget being stacked above other windows in the container is not an
issue on login/lock screen (login shelf widget does not interfere with
the only other visible widget - status area widget), but when the
session state changes, the shelf widget should ensure it gets restacked
at the bottom again, so the shelf background does not get painted over
other widgets.

NOTE: This was not an issue before M-82, as shelf widget was in a
separate window container.

BUG=1051823

Change-Id: I65e34fc1347d20976cb5441da91e00efb96b0885
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2058998Reviewed-by: default avatarAhmed Fakhry <afakhry@chromium.org>
Commit-Queue: Toni Baržić <tbarzic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#745719}
parent c66ba8aa
......@@ -109,6 +109,12 @@ class LoginShelfViewTest : public LoginTestBase {
base::RunLoop().RunUntilIdle();
}
void SendKey(ui::KeyboardCode key_code, int flags) {
auto* generator = GetEventGenerator();
generator->PressKey(key_code, flags);
generator->ReleaseKey(key_code, flags);
}
// Checks if the shelf is only showing the buttons in the list. The IDs in
// the specified list must be unique.
bool ShowsShelfButtons(std::vector<LoginShelfView::ButtonId> ids) {
......@@ -520,19 +526,19 @@ TEST_F(LoginShelfViewTest, TabGoesFromShelfToStatusAreaAndBackToShelf) {
login_shelf_view_->GetViewByID(LoginShelfView::kShutdown)->HasFocus());
// Focus from the first button to the second button.
GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_TAB, 0);
SendKey(ui::KeyboardCode::VKEY_TAB, 0);
ExpectFocused(shelf);
ExpectNotFocused(status_area);
EXPECT_TRUE(
login_shelf_view_->GetViewByID(LoginShelfView::kSignOut)->HasFocus());
// Focus from the second button to the status area.
GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_TAB, 0);
SendKey(ui::KeyboardCode::VKEY_TAB, 0);
ExpectNotFocused(shelf);
ExpectFocused(status_area);
// A single shift+tab brings focus back to the second shelf button.
GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_TAB, ui::EF_SHIFT_DOWN);
SendKey(ui::KeyboardCode::VKEY_TAB, ui::EF_SHIFT_DOWN);
ExpectFocused(shelf);
ExpectNotFocused(status_area);
EXPECT_TRUE(
......@@ -590,6 +596,43 @@ TEST_F(LoginShelfViewTest, ShouldNotShowNavigationAndHotseat) {
<< "The hotseat widget should not appear in the login shelf.";
}
TEST_F(LoginShelfViewTest, ShelfWidgetStackedAtBottomInActiveSession) {
gfx::NativeWindow window = login_shelf_view_->GetWidget()->GetNativeWindow();
ShelfWidget* shelf_widget = Shelf::ForWindow(window)->shelf_widget();
// Focus shelf widget (which could happen if user tabs to login shelf
// buttons).
shelf_widget->set_default_last_focusable_child(/*reverse=*/false);
Shell::Get()->focus_cycler()->FocusWidget(shelf_widget);
ExpectFocused(shelf_widget->GetContentsView());
// Verify that shelf widget is no longer focused, and is stacked at the bottom
// of shelf container when the session is activated.
NotifySessionStateChanged(SessionState::ACTIVE);
ExpectNotFocused(shelf_widget->GetContentsView());
EXPECT_EQ(shelf_widget->GetNativeWindow(),
shelf_widget->GetNativeWindow()->parent()->children()[0]);
// Lock screen and focus the shelf again.
NotifySessionStateChanged(SessionState::LOCKED);
Shell::Get()->focus_cycler()->FocusWidget(shelf_widget);
// Move focus away from the shelf, to verify the shelf widget stacking is
// updated even if the widget is not active when the session state changes.
SendKey(ui::KeyboardCode::VKEY_TAB, 0);
SendKey(ui::KeyboardCode::VKEY_TAB, 0);
ExpectNotFocused(shelf_widget->GetContentsView());
// Verify that shelf widget is no longer focused, and is stacked at the bottom
// of shelf container when the session is activated.
NotifySessionStateChanged(SessionState::ACTIVE);
ExpectNotFocused(shelf_widget->GetContentsView());
EXPECT_EQ(shelf_widget->GetNativeWindow(),
shelf_widget->GetNativeWindow()->parent()->children()[0]);
}
TEST_F(LoginShelfViewTest, ParentAccessButtonVisibility) {
// Parent access button should only be visible on lock screen.
Shell::Get()->login_screen_controller()->ShowParentAccessButton(true);
......
......@@ -49,6 +49,7 @@
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/wm/core/coordinate_conversion.h"
#include "ui/wm/core/window_util.h"
namespace ash {
namespace {
......@@ -943,11 +944,29 @@ void ShelfWidget::OnSessionStateChanged(session_manager::SessionState state) {
hotseat_widget()->GetShelfView()->SetVisible(show_hotseat);
hotseat_transition_animator_->SetAnimationsEnabledInSessionState(
show_hotseat);
// Shelf widget should only be active if login shelf view is visible.
aura::Window* const shelf_window = GetNativeWindow();
if (show_hotseat && IsActive())
wm::DeactivateWindow(shelf_window);
login_shelf_view()->SetVisible(!show_hotseat);
if (show_hotseat)
login_shelf_gesture_controller_.reset();
ShowIfHidden();
// The shelf widget can get activated when login shelf view is shown, which
// would stack it above other widgets in the shelf container, which is an
// undesirable state for active session shelf (as the shelf background would
// be painted over the hotseat/navigation buttons/status area). Make sure
// the shelf widget is restacked at the bottom of the shelf container when
// the session state changes.
// TODO(https://crbug.com/1057207): Ideally, the shelf widget position at
// the bottom of window stack would be maintained using a "stacked at
// bottom" window property - switch to that approach once it's ready for
// usage.
if (show_hotseat)
shelf_window->parent()->StackChildAtBottom(shelf_window);
}
shelf_layout_manager_->SetDimmed(false);
// Depending on session state change, the drag handle visibiliy and color
......
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