[go: nahoru, domu]

blob: bcbd0d3771afc1a8c131b2bf97def71c8c4c5a54 [file] [log] [blame]
Avi Drissman3a215d1e2022-09-07 19:43:091// Copyright 2022 The Chromium Authors
Andrew Xu6eb8ee72022-07-26 00:11:012// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ash/shelf/login_shelf_widget.h"
6
7#include "ash/focus_cycler.h"
8#include "ash/root_window_controller.h"
9#include "ash/shelf/login_shelf_view.h"
10#include "ash/shelf/shelf.h"
11#include "ash/shelf/shelf_layout_manager.h"
12#include "ash/shelf/shelf_widget.h"
13#include "ui/views/accessible_pane_view.h"
14#include "ui/views/focus/focus_search.h"
15#include "ui/views/layout/fill_layout.h"
16
17namespace ash {
18
19// LoginShelfWidget::LoginShelfWidgetDelegate ----------------------------------
20// The delegate of the login shelf widget.
21
22class LoginShelfWidget::LoginShelfWidgetDelegate
23 : public views::AccessiblePaneView,
24 public views::WidgetDelegate {
25 public:
26 explicit LoginShelfWidgetDelegate(Shelf* shelf) : shelf_(shelf) {
27 SetOwnedByWidget(true);
28 set_allow_deactivate_on_esc(true);
29 SetLayoutManager(std::make_unique<views::FillLayout>());
30 }
31
32 LoginShelfWidgetDelegate(const LoginShelfWidgetDelegate&) = delete;
33 LoginShelfWidgetDelegate& operator=(const LoginShelfWidgetDelegate&) = delete;
34
35 ~LoginShelfWidgetDelegate() override = default;
36
37 // views::View:
38 views::View* GetDefaultFocusableChild() override {
39 // `login_shelf_view` is added to the widget delegate as a child when the
40 // login shelf widget is constructed and is removed when the widget is
41 // destructed. Therefore, `login_shelf_view` is not null here.
42 views::View* login_shelf_view = children()[0];
43
44 views::FocusSearch search(login_shelf_view, default_last_focusable_child_,
45 /*accessibility_mode=*/false);
46 views::FocusTraversable* dummy_focus_traversable;
47 views::View* dummy_focus_traversable_view;
48
49 return search.FindNextFocusableView(
50 login_shelf_view,
51 default_last_focusable_child_
52 ? views::FocusSearch::SearchDirection::kBackwards
53 : views::FocusSearch::SearchDirection::kForwards,
54 views::FocusSearch::TraversalDirection::kDown,
55 views::FocusSearch::StartingViewPolicy::kSkipStartingView,
56 views::FocusSearch::AnchoredDialogPolicy::kCanGoIntoAnchoredDialog,
57 &dummy_focus_traversable, &dummy_focus_traversable_view);
58 }
59
60 // views::WidgetDelegate:
61 bool CanActivate() const override {
62 // We don't want mouse clicks to activate us, but we need to allow
63 // activation when the user is using the keyboard (FocusCycler).
64 bool can_active = Shell::Get()->focus_cycler()->widget_activating() ==
65 views::View::GetWidget();
66 return can_active;
67 }
68
69 void ChildPreferredSizeChanged(views::View* child) override {
70 shelf_->shelf_layout_manager()->LayoutShelf(/*animate=*/false);
71 }
72
73 void set_default_last_focusable_child(bool reverse) {
74 default_last_focusable_child_ = reverse;
75 }
76
77 private:
Arthur Sonzogni609ca5e2023-04-26 10:39:2378 const raw_ptr<Shelf> shelf_ = nullptr;
Andrew Xu6eb8ee72022-07-26 00:11:0179
80 // When true, the default focus of the shelf is the last focusable child.
81 bool default_last_focusable_child_ = false;
82};
83
84// LoginShelfWidget ------------------------------------------------------------
85
86LoginShelfWidget::LoginShelfWidget(Shelf* shelf, aura::Window* container)
87 : shelf_(shelf),
88 delegate_(new LoginShelfWidgetDelegate(shelf)),
89 scoped_session_observer_(this) {
90 DCHECK(container);
91 login_shelf_view_ = delegate_->AddChildView(std::make_unique<LoginShelfView>(
92 RootWindowController::ForWindow(container)
93 ->lock_screen_action_background_controller()));
94
95 views::Widget::InitParams params(
96 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
97 params.name = "LoginShelfWidget";
98 params.delegate = delegate_;
99 params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
100 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
101 params.parent = container;
102 Init(std::move(params));
103 SetContentsView(delegate_);
104
105 // Hide the login shelf by default.
106 Hide();
107
108 // TODO(https://crbug.com/1343114): currently, some logics in shelf check the
109 // login shelf view's visibility. Update them to check whether the login shelf
110 // view is drawn or the widget's visibility. Then remove this line.
111 login_shelf_view_->SetVisible(false);
112}
113
114LoginShelfWidget::~LoginShelfWidget() = default;
115
116void LoginShelfWidget::SetDefaultLastFocusableChild(bool reverse) {
117 delegate_->set_default_last_focusable_child(reverse);
118}
119
120void LoginShelfWidget::SetLoginShelfButtonOpacity(float target_opacity) {
121 login_shelf_view_->SetButtonOpacity(target_opacity);
122}
123
124void LoginShelfWidget::HandleLocaleChange() {
125 login_shelf_view_->HandleLocaleChange();
126}
127
128void LoginShelfWidget::CalculateTargetBounds() {
129 const gfx::Point shelf_origin =
130 shelf_->shelf_widget()->GetTargetBounds().origin();
131
132 gfx::Point origin = gfx::Point(shelf_origin.x(), shelf_origin.y());
133 const int target_bounds_width = delegate_->GetPreferredSize().width();
134 if (shelf_->IsHorizontalAlignment() && base::i18n::IsRTL()) {
135 origin.set_x(shelf_->shelf_widget()->GetTargetBounds().size().width() -
136 target_bounds_width);
137 }
138
139 target_bounds_ =
140 gfx::Rect(origin, {target_bounds_width,
141 shelf_->shelf_widget()->GetTargetBounds().height()});
142}
143
144gfx::Rect LoginShelfWidget::GetTargetBounds() const {
145 return target_bounds_;
146}
147
148void LoginShelfWidget::UpdateLayout(bool animate) {
149 if (GetNativeView()->bounds() == target_bounds_)
150 return;
151
152 SetBounds(target_bounds_);
153}
154
155bool LoginShelfWidget::OnNativeWidgetActivationChanged(bool active) {
156 if (!Widget::OnNativeWidgetActivationChanged(active))
157 return false;
158
159 if (active)
160 delegate_->SetPaneFocusAndFocusDefault();
161
162 return true;
163}
164
165void LoginShelfWidget::OnSessionStateChanged(
166 session_manager::SessionState state) {
Andrew Xu9b69e432022-08-09 01:33:51167 // The login shelf should be hidden if:
168 // 1. the user session is active; or
169 // 2. the RMA app is active. The login shelf should be hidden to avoid
170 // blocking the RMA app controls or intercepting UI events.
171 bool hide_for_session_state =
172 (state == session_manager::SessionState::ACTIVE ||
173 state == session_manager::SessionState::RMA);
Andrew Xu6eb8ee72022-07-26 00:11:01174
175 // The visibility of `login_shelf_view_` is accessed in different places.
176 // Therefore, ensure the consistency between the widget's visibility and the
177 // view's visibility.
Andrew Xu9b69e432022-08-09 01:33:51178 if (!hide_for_session_state && !shelf_->ShouldHideOnSecondaryDisplay(state)) {
Andrew Xu6eb8ee72022-07-26 00:11:01179 if (!IsVisible()) {
180 Show();
181 login_shelf_view_->SetVisible(true);
182 }
183 } else if (IsVisible()) {
184 Hide();
185 login_shelf_view_->SetVisible(false);
186 }
187
188 login_shelf_view_->UpdateAfterSessionChange();
189}
190
191void LoginShelfWidget::OnUserSessionAdded(const AccountId& account_id) {
192 login_shelf_view_->UpdateAfterSessionChange();
193}
194
195} // namespace ash