[go: nahoru, domu]

blob: e3e6fbec1bc4addcf60eddd3cd0a45c3a2450860 [file] [log] [blame]
// Copyright 2018 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 "ash/login/ui/login_expanded_public_account_view.h"
#include <memory>
#include <utility>
#include <vector>
#include "ash/constants/ash_pref_names.h"
#include "ash/login/login_screen_controller.h"
#include "ash/login/ui/arrow_button_view.h"
#include "ash/login/ui/login_button.h"
#include "ash/login/ui/login_user_view.h"
#include "ash/login/ui/public_account_monitoring_info_dialog.h"
#include "ash/login/ui/views_utils.h"
#include "ash/public/cpp/login_types.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "chromeos/strings/grit/chromeos_strings.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/animation/ink_drop.h"
#include "ui/views/border.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/mouse_constants.h"
namespace ash {
namespace {
constexpr const char kLoginExpandedPublicAccountViewClassName[] =
"LoginExpandedPublicAccountView";
constexpr int kExpandedViewWidthDp = 628;
constexpr int kExpandedViewHeightDp = 324;
constexpr int kTextLineHeightDp = 16;
constexpr int kRoundRectCornerRadiusDp = 2;
constexpr int kBorderThicknessDp = 1;
constexpr int kHorizontalMarginPaneDp = 28;
constexpr int kLabelMarginDp = 20;
constexpr int kDropDownIconSizeDp = 16;
constexpr int kArrowButtonSizeDp = 48;
constexpr int kAdvancedViewButtonWidthDp = 190;
constexpr int kAdvancedViewButtonHeightDp = 16;
constexpr int kTopSpacingForLabelInAdvancedViewDp = 7;
constexpr int kTopSpacingForLabelInRegularViewDp = 65;
constexpr int kSpacingBetweenLabelsDp = 17;
constexpr int kSpacingBetweenSelectionMenusDp = 7;
constexpr int kSpacingBetweenSelectionTitleAndButtonDp = 3;
constexpr int kSpacingBetweenLanguageMenuAndAdvancedViewButtonDp = 4;
constexpr int kSpacingBetweenAdvancedViewButtonAndLabelDp = 32;
constexpr int kTopSpacingForUserViewDp = 62;
constexpr int kArrowButtonMarginDp = kSpacingBetweenLabelsDp;
constexpr int kNonEmptyWidth = 1;
constexpr int kNonEmptyHeight = 1;
constexpr char kMonitoringWarningClassName[] = "MonitoringWarning";
constexpr int kSpacingBetweenMonitoringWarningIconAndLabelDp = 8;
constexpr int kMonitoringWarningIconSizeDp = 20;
constexpr char kRightPaneViewClassName[] = "RightPaneView";
constexpr char kRightPaneLabelsViewClassName[] = "RightPaneLabelsView";
constexpr char kRightPaneAdvancedViewClassName[] = "RightPaneAdvancedView";
views::Label* CreateLabel(const std::u16string& text, SkColor color) {
auto* label = new views::Label(text);
label->SetSubpixelRenderingEnabled(false);
label->SetAutoColorReadabilityEnabled(false);
label->SetFontList(views::Label::GetDefaultFontList().Derive(
0, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL));
label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
label->SetEnabledColor(color);
return label;
}
class LoginExpandedPublicAccountEventHandler : public ui::EventHandler {
public:
explicit LoginExpandedPublicAccountEventHandler(
LoginExpandedPublicAccountView* view)
: view_(view) {
Shell::Get()->AddPreTargetHandler(this);
}
LoginExpandedPublicAccountEventHandler(
const LoginExpandedPublicAccountEventHandler&) = delete;
LoginExpandedPublicAccountEventHandler& operator=(
const LoginExpandedPublicAccountEventHandler&) = delete;
~LoginExpandedPublicAccountEventHandler() override {
Shell::Get()->RemovePreTargetHandler(this);
}
private:
// ui::EventHandler:
void OnMouseEvent(ui::MouseEvent* event) override {
if (event->type() == ui::ET_MOUSE_PRESSED)
view_->ProcessPressedEvent(event->AsLocatedEvent());
}
void OnGestureEvent(ui::GestureEvent* event) override {
if ((event->type() == ui::ET_GESTURE_TAP ||
event->type() == ui::ET_GESTURE_TAP_DOWN)) {
view_->ProcessPressedEvent(event->AsLocatedEvent());
}
}
void OnKeyEvent(ui::KeyEvent* event) override { view_->OnKeyEvent(event); }
LoginExpandedPublicAccountView* view_;
};
} // namespace
// Button with text on the left side and an icon on the right side.
class SelectionButtonView : public LoginButton {
public:
SelectionButtonView(PressedCallback callback, const std::u16string& text)
: LoginButton(std::move(callback)) {
SetAccessibleName(text);
SetPaintToLayer();
layer()->SetFillsBoundsOpaquely(false);
SetFocusBehavior(FocusBehavior::ALWAYS);
SetLayoutManager(std::make_unique<views::FillLayout>());
views::InkDrop::Get(this)->SetMode(views::InkDropHost::InkDropMode::OFF);
auto add_horizontal_margin = [&](int width,
views::View* parent) -> views::View* {
auto* margin = new NonAccessibleView();
margin->SetPreferredSize(gfx::Size(width, kNonEmptyHeight));
parent->AddChildView(margin);
return margin;
};
auto* label_container = new NonAccessibleView();
views::BoxLayout* label_layout =
label_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal));
label_layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kStart);
AddChildView(label_container);
label_ = CreateLabel(
text, AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kTextColorPrimary));
left_margin_view_ = add_horizontal_margin(left_margin_, label_container);
label_container->AddChildView(label_);
auto* icon_container = new NonAccessibleView();
views::BoxLayout* icon_layout =
icon_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal));
icon_layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kEnd);
AddChildView(icon_container);
icon_ = new views::ImageView;
icon_->SetVerticalAlignment(views::ImageView::Alignment::kCenter);
icon_->SetPreferredSize(
gfx::Size(kDropDownIconSizeDp, kDropDownIconSizeDp));
icon_container->AddChildView(icon_);
right_margin_view_ = add_horizontal_margin(right_margin_, icon_container);
}
SelectionButtonView(const SelectionButtonView&) = delete;
SelectionButtonView& operator=(const SelectionButtonView&) = delete;
~SelectionButtonView() override = default;
// Return the preferred height of this view. This overrides the default
// behavior in FillLayout::GetPreferredHeightForWidth which calculates the
// height based on its child height.
int GetHeightForWidth(int w) const override {
return GetPreferredSize().height();
}
void SetMargins(int left, int right) {
if (left_margin_ == left && right_margin_ == right)
return;
left_margin_ = left;
right_margin_ = right;
left_margin_view_->SetPreferredSize(
gfx::Size(left_margin_, kNonEmptyHeight));
right_margin_view_->SetPreferredSize(
gfx::Size(right_margin_, kNonEmptyHeight));
Layout();
}
void SetTextColor(SkColor color) { label_->SetEnabledColor(color); }
void SetText(const std::u16string& text) {
SetAccessibleName(text);
label_->SetText(text);
Layout();
}
void SetIcon(const gfx::VectorIcon& icon, SkColor color) {
icon_->SetImage(gfx::CreateVectorIcon(icon, color));
}
private:
int left_margin_ = 0;
int right_margin_ = 0;
views::Label* label_ = nullptr;
views::ImageView* icon_ = nullptr;
views::View* left_margin_view_ = nullptr;
views::View* right_margin_view_ = nullptr;
};
// Container for the device monitoring warning. Composed of an optional warning
// icon on the left and a label to the right.
class MonitoringWarningView : public NonAccessibleView {
public:
MonitoringWarningView()
: NonAccessibleView(kMonitoringWarningClassName),
warning_type_(WarningType::kNone) {
image_ = new views::ImageView();
image_->SetImage(gfx::CreateVectorIcon(
vector_icons::kWarningIcon, kMonitoringWarningIconSizeDp,
AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kIconColorWarning)));
image_->SetPreferredSize(
gfx::Size(kMonitoringWarningIconSizeDp, kMonitoringWarningIconSizeDp));
image_->SetVisible(false);
AddChildView(image_);
const std::u16string label_text = l10n_util::GetStringUTF16(
IDS_ASH_LOGIN_PUBLIC_ACCOUNT_MONITORING_WARNING);
label_ = CreateLabel(
label_text, AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kTextColorPrimary));
label_->SetMultiLine(true);
label_->SetLineHeight(kTextLineHeightDp);
AddChildView(label_);
}
enum class WarningType { kNone, kSoftWarning, kFullWarning };
void UpdateForUser(const LoginUserInfo& user) {
device_manager_ = user.public_account_info->device_enterprise_manager;
UpdateLabel();
}
void SetWarningType(WarningType warning_type) {
warning_type_ = warning_type;
UpdateLabel();
}
MonitoringWarningView(const MonitoringWarningView&) = delete;
MonitoringWarningView& operator=(const MonitoringWarningView&) = delete;
~MonitoringWarningView() override = default;
// MonitoringWarningview is effectively laid out as BoxLayout with
// kSpacingBetweenMonitoringWarningIconAndLabelDp spacing between its two
// child views. However, horizontal BoxLayout and FlexLayout do not handle
// views that override GetHeightForWidth well, so it's implemented ad-hoc
// here.
int GetHeightForWidth(int w) const override {
int image_height = image_->GetPreferredSize().height();
w -= image_->GetPreferredSize().width();
w -= kSpacingBetweenMonitoringWarningIconAndLabelDp;
int label_height = label_->GetHeightForWidth(w);
return std::max(image_height, label_height);
}
void Layout() override {
const gfx::Rect b = GetContentsBounds();
int x = b.x();
image_->SizeToPreferredSize();
// image_ is vertically centered. Thus its top right coordinate is given by
// moving up half the image height from the left midpoint of the bounding
// rect of `this`.
int image_y = b.y() + (b.height() - image_->size().height()) / 2;
image_->SetPosition(gfx::Point(x, image_y));
x += image_->size().width();
x += kSpacingBetweenMonitoringWarningIconAndLabelDp;
int label_width = b.right() - x;
int label_height = label_->GetHeightForWidth(label_width);
label_->SetBounds(x, b.y(), label_width, label_height);
}
private:
void UpdateLabel() {
// Call sequence of UpdateForUser() and SetWarningType() is not clear.
// In case SetWarningType is called first there is a need to wait for
// device_manager_ is set.
if (warning_type_ == WarningType::kNone || !device_manager_.has_value())
return;
std::u16string label_text;
if (warning_type_ == WarningType::kFullWarning) {
label_text = l10n_util::GetStringFUTF16(
IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_FULL_WARNING,
base::UTF8ToUTF16(device_manager_.value()));
image_->SetVisible(true);
} else {
label_text = l10n_util::GetStringFUTF16(
IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_SOFT_WARNING,
base::UTF8ToUTF16(device_manager_.value()));
image_->SetVisible(false);
}
label_->SetText(label_text);
InvalidateLayout();
Layout();
}
friend class LoginExpandedPublicAccountView::TestApi;
WarningType warning_type_;
absl::optional<std::string> device_manager_;
views::ImageView* image_;
views::Label* label_;
};
// Implements the right part of the expanded public session view.
class RightPaneView : public NonAccessibleView {
public:
explicit RightPaneView(const base::RepeatingClosure& on_learn_more_tapped)
: NonAccessibleView(kRightPaneViewClassName) {
SetPreferredSize(
gfx::Size(kExpandedViewWidthDp / 2, kExpandedViewHeightDp));
SetBorder(views::CreateEmptyBorder(kHorizontalMarginPaneDp));
// Create labels view.
labels_view_ = new NonAccessibleView(kRightPaneLabelsViewClassName);
labels_view_->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical, gfx::Insets(),
kSpacingBetweenLabelsDp));
AddChildView(labels_view_);
const bool enable_warning = Shell::Get()->local_state()->GetBoolean(
prefs::kManagedGuestSessionPrivacyWarningsEnabled);
if (enable_warning) {
monitoring_warning_view_ = new MonitoringWarningView();
labels_view_->AddChildView(monitoring_warning_view_);
}
const std::u16string link = l10n_util::GetStringUTF16(IDS_ASH_LEARN_MORE);
size_t offset;
const std::u16string text = l10n_util::GetStringFUTF16(
IDS_ASH_LOGIN_PUBLIC_ACCOUNT_SIGNOUT_REMINDER, link, &offset);
learn_more_label_ =
labels_view_->AddChildView(std::make_unique<views::StyledLabel>());
learn_more_label_->SetText(text);
views::StyledLabel::RangeStyleInfo style;
style.custom_font = learn_more_label_->GetFontList().Derive(
0, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::NORMAL);
style.override_color = AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kTextColorPrimary);
learn_more_label_->AddStyleRange(gfx::Range(0, offset), style);
views::StyledLabel::RangeStyleInfo link_style =
views::StyledLabel::RangeStyleInfo::CreateForLink(on_learn_more_tapped);
const SkColor blue = AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kButtonLabelColorBlue);
link_style.override_color = blue;
learn_more_label_->AddStyleRange(gfx::Range(offset, offset + link.length()),
link_style);
learn_more_label_->SetAutoColorReadabilityEnabled(false);
// Create button to show/hide advanced view.
advanced_view_button_ = new SelectionButtonView(
base::BindRepeating(&RightPaneView::AdvancedViewButtonPressed,
base::Unretained(this)),
l10n_util::GetStringUTF16(
IDS_ASH_LOGIN_PUBLIC_SESSION_LANGUAGE_AND_INPUT));
advanced_view_button_->SetTextColor(blue);
advanced_view_button_->SetIcon(kLoginScreenButtonDropdownIcon, blue);
advanced_view_button_->SetPreferredSize(
gfx::Size(kAdvancedViewButtonWidthDp, kAdvancedViewButtonHeightDp));
AddChildView(advanced_view_button_);
// Create advanced view.
advanced_view_ = new NonAccessibleView(kRightPaneAdvancedViewClassName);
advanced_view_->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical));
AddChildView(advanced_view_);
const SkColor selection_menu_title_color =
AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kTextColorSecondary);
auto create_padding = [](int amount) -> views::View* {
auto* padding = new NonAccessibleView();
padding->SetPreferredSize(gfx::Size(kNonEmptyWidth, amount));
return padding;
};
language_title_ = CreateLabel(
l10n_util::GetStringUTF16(IDS_ASH_LOGIN_LANGUAGE_SELECTION_SELECT),
selection_menu_title_color);
keyboard_title_ = CreateLabel(
l10n_util::GetStringUTF16(IDS_ASH_LOGIN_KEYBOARD_SELECTION_SELECT),
selection_menu_title_color);
advanced_view_->AddChildView(language_title_);
advanced_view_->AddChildView(
create_padding(kSpacingBetweenSelectionTitleAndButtonDp));
advanced_view_->AddChildView(
create_padding(kSpacingBetweenSelectionMenusDp));
advanced_view_->AddChildView(keyboard_title_);
advanced_view_->AddChildView(
create_padding(kSpacingBetweenSelectionTitleAndButtonDp));
submit_button_ = new ArrowButtonView(
base::BindRepeating(&RightPaneView::SubmitButtonPressed,
base::Unretained(this)),
kArrowButtonSizeDp);
submit_button_->SetAccessibleName(l10n_util::GetStringUTF16(
IDS_ASH_LOGIN_PUBLIC_ACCOUNT_LOG_IN_BUTTON_ACCESSIBLE_NAME));
AddChildView(submit_button_);
}
RightPaneView(const RightPaneView&) = delete;
RightPaneView& operator=(const RightPaneView&) = delete;
~RightPaneView() override = default;
int GetHeightForWidth(int w) const override {
if (w >= GetPreferredSize().width()) {
// We're not shrunk horizontally, so take preferred height.
return GetPreferredSize().height();
}
int result = 0;
// Remove left and right margins from width.
w -= 2 * kHorizontalMarginPaneDp;
// Top and bottom margins.
// TODO(crbug.com/1305982): The name suggests that this is meant only for
// horizontal padding, but it's really applied on all sides. Is it
// intentional?
result += 2 * kHorizontalMarginPaneDp;
// Additional top spacing.
result += show_advanced_view_ ? kTopSpacingForLabelInAdvancedViewDp
: kTopSpacingForLabelInRegularViewDp;
// TODO(crbug.com/1305982): Why is there a further right margin for the
// labels view in addition to the general padding of RightPane?
// Intentional?
const int label_width = w - kLabelMarginDp;
result += labels_view_->GetHeightForWidth(label_width);
// Spacing above advanced view button.
result += show_advanced_view_ ? kSpacingBetweenLabelsDp
: kSpacingBetweenAdvancedViewButtonAndLabelDp;
// Advanced view button is always rendered at preferred size.
result += advanced_view_button_->GetPreferredSize().height();
if (show_advanced_view_) {
// Spacing above advanced view.
result += kSpacingBetweenLanguageMenuAndAdvancedViewButtonDp;
// Advanced view is always rendered at preferred size.
result += advanced_view_->GetPreferredSize().height();
}
// Add space for submit button in final row.
result += kArrowButtonMarginDp;
result += kArrowButtonSizeDp;
// We shouldn't end up smaller than preferred height.
result = std::max(result, GetPreferredSize().height());
return result;
}
void Layout() override {
const gfx::Rect bounds = GetContentsBounds();
// Place the labels.
const int label_width = bounds.width() - kLabelMarginDp;
labels_view_->SetBounds(
bounds.x(),
show_advanced_view_ ? kTopSpacingForLabelInAdvancedViewDp + bounds.y()
: kTopSpacingForLabelInRegularViewDp + bounds.y(),
label_width, labels_view_->GetHeightForWidth(label_width));
// Place the advanced_view_button_.
advanced_view_button_->SizeToPreferredSize();
advanced_view_button_->SetPosition(gfx::Point(
bounds.x(),
show_advanced_view_
? labels_view_->bounds().bottom() + kSpacingBetweenLabelsDp
: labels_view_->bounds().bottom() +
kSpacingBetweenAdvancedViewButtonAndLabelDp));
// Place the advanced view.
advanced_view_->SetVisible(show_advanced_view_);
if (show_advanced_view_) {
advanced_view_->SizeToPreferredSize();
advanced_view_->SetPosition(gfx::Point(
bounds.x(), advanced_view_button_->bounds().bottom() +
kSpacingBetweenLanguageMenuAndAdvancedViewButtonDp));
}
// Place the submit button.
submit_button_->SizeToPreferredSize();
submit_button_->SetPosition(
gfx::Point(bounds.right() - kArrowButtonSizeDp,
bounds.bottom() - kArrowButtonSizeDp));
}
void UpdateForUser(const LoginUserInfo& user) {
DCHECK_EQ(user.basic_user_info.type,
user_manager::USER_TYPE_PUBLIC_ACCOUNT);
if (monitoring_warning_view_)
monitoring_warning_view_->UpdateForUser(user);
current_user_ = user;
if (!language_changed_by_user_)
selected_language_item_value_ = user.public_account_info->default_locale;
PopulateLanguageItems(user.public_account_info->available_locales);
if (user.public_account_info->default_locale ==
selected_language_item_value_)
PopulateKeyboardItems(user.public_account_info->keyboard_layouts);
if (!show_advanced_changed_by_user_)
show_advanced_view_ = user.public_account_info->show_advanced_view;
InvalidateLayout();
Layout();
}
void SetShowFullManagementDisclosure(bool show_full_management_disclosure) {
if (monitoring_warning_view_)
monitoring_warning_view_->SetWarningType(
show_full_management_disclosure
? MonitoringWarningView::WarningType::kFullWarning
: MonitoringWarningView::WarningType::kSoftWarning);
}
void OnLanguageSelected(const std::string& value) {
language_changed_by_user_ = true;
selected_language_item_value_ = value;
current_user_.public_account_info->default_locale = value;
// User changed the preferred locale, request to get corresponding keyboard
// layouts.
Shell::Get()
->login_screen_controller()
->RequestPublicSessionKeyboardLayouts(
current_user_.basic_user_info.account_id, value);
}
void OnKeyboardSelected(const std::string& value) {
selected_keyboard_item_value_ = value;
}
void PopulateLanguageItems(const std::vector<LocaleItem>& locales) {
language_items_.clear();
int selected_language_index = 0;
for (const auto& locale : locales) {
PublicAccountMenuView::Item item;
if (locale.group_name) {
item.title = locale.group_name.value();
item.is_group = true;
} else {
item.title = locale.title;
item.value = locale.language_code;
item.is_group = false;
item.selected = selected_language_item_value_ == locale.language_code;
}
if (selected_language_item_value_ == locale.language_code)
selected_language_index = language_items_.size();
language_items_.push_back(item);
}
if (language_menu_view_) {
advanced_view_->RemoveChildViewT(language_menu_view_);
language_menu_view_ = nullptr;
}
auto language_menu_view = std::make_unique<PublicAccountMenuView>(
language_items_, selected_language_index,
base::BindRepeating(&RightPaneView::OnLanguageSelected,
weak_factory_.GetWeakPtr()));
language_menu_view->SetTooltipTextAndAccessibleName(
l10n_util::GetStringUTF16(
IDS_ASH_LOGIN_PUBLIC_ACCOUNT_LANGUAGE_MENU_ACCESSIBLE_NAME));
int after_title_after_padding_index =
advanced_view_->GetIndexOf(language_title_) + 2;
language_menu_view_ = advanced_view_->AddChildViewAt(
std::move(language_menu_view), after_title_after_padding_index);
}
void PopulateKeyboardItems(
const std::vector<InputMethodItem>& keyboard_layouts) {
keyboard_items_.clear();
int selected_keyboard_index = 0;
for (const auto& keyboard : keyboard_layouts) {
PublicAccountMenuView::Item item;
item.title = keyboard.title;
item.value = keyboard.ime_id;
item.is_group = false;
item.selected = keyboard.selected;
if (keyboard.selected) {
selected_keyboard_index = keyboard_items_.size();
selected_keyboard_item_value_ = item.value;
}
keyboard_items_.push_back(item);
}
if (keyboard_menu_view_) {
advanced_view_->RemoveChildViewT(keyboard_menu_view_);
keyboard_menu_view_ = nullptr;
}
auto keyboard_menu_view = std::make_unique<PublicAccountMenuView>(
keyboard_items_, selected_keyboard_index,
base::BindRepeating(&RightPaneView::OnKeyboardSelected,
weak_factory_.GetWeakPtr()));
keyboard_menu_view->SetTooltipTextAndAccessibleName(
l10n_util::GetStringUTF16(
IDS_ASH_LOGIN_PUBLIC_ACCOUNT_KEYBOARD_MENU_ACCESSIBLE_NAME));
int after_title_after_padding_index =
advanced_view_->GetIndexOf(keyboard_title_) + 2;
keyboard_menu_view_ = advanced_view_->AddChildViewAt(
std::move(keyboard_menu_view), after_title_after_padding_index);
}
PublicAccountMenuView* GetLanguageMenuView() { return language_menu_view_; }
PublicAccountMenuView* GetKeyboardMenuView() { return keyboard_menu_view_; }
// Reset local states.
void Reset() {
show_advanced_changed_by_user_ = false;
language_changed_by_user_ = false;
}
private:
friend class LoginExpandedPublicAccountView::TestApi;
void AdvancedViewButtonPressed() {
show_advanced_view_ = !show_advanced_view_;
show_advanced_changed_by_user_ = true;
InvalidateLayout();
Layout();
}
void SubmitButtonPressed() {
// TODO(crbug.com/984021) change to LaunchSamlPublicSession which would
// take |selected_language_item_value_| and |selected_keyboard_item_value_|
// too.
if (current_user_.public_account_info->using_saml) {
Shell::Get()->login_screen_controller()->ShowGaiaSignin(
current_user_.basic_user_info.account_id);
} else {
Shell::Get()->login_screen_controller()->LaunchPublicSession(
current_user_.basic_user_info.account_id,
selected_language_item_value_, selected_keyboard_item_value_);
}
}
bool show_advanced_view_ = false;
LoginUserInfo current_user_;
views::View* labels_view_ = nullptr;
SelectionButtonView* advanced_view_button_ = nullptr;
views::View* advanced_view_ = nullptr;
views::View* language_title_ = nullptr;
views::View* keyboard_title_ = nullptr;
ArrowButtonView* submit_button_ = nullptr;
views::StyledLabel* learn_more_label_ = nullptr;
MonitoringWarningView* monitoring_warning_view_ = nullptr;
PublicAccountMenuView* language_menu_view_ = nullptr;
PublicAccountMenuView* keyboard_menu_view_ = nullptr;
std::string selected_language_item_value_;
std::string selected_keyboard_item_value_;
std::vector<PublicAccountMenuView::Item> language_items_;
std::vector<PublicAccountMenuView::Item> keyboard_items_;
// Local states to check if the locale and whether to show advanced view
// has been changed by the user. This ensures user action won't be overridden
// by the default settings and it will be reset after this view is hidden.
// Keyboard selection is not tracked here because it's depending on which
// locale user selects, so the previously selected keyboard might not be
// applicable for the current locale.
bool show_advanced_changed_by_user_ = false;
bool language_changed_by_user_ = false;
base::WeakPtrFactory<RightPaneView> weak_factory_{this};
};
LoginExpandedPublicAccountView::TestApi::TestApi(
LoginExpandedPublicAccountView* view)
: view_(view) {}
LoginExpandedPublicAccountView::TestApi::~TestApi() = default;
LoginUserView* LoginExpandedPublicAccountView::TestApi::user_view() {
return view_->user_view_;
}
views::View* LoginExpandedPublicAccountView::TestApi::advanced_view_button() {
return view_->right_pane_->advanced_view_button_;
}
ArrowButtonView* LoginExpandedPublicAccountView::TestApi::submit_button() {
return view_->right_pane_->submit_button_;
}
views::View* LoginExpandedPublicAccountView::TestApi::advanced_view() {
return view_->right_pane_->advanced_view_;
}
PublicAccountMonitoringInfoDialog*
LoginExpandedPublicAccountView::TestApi::learn_more_dialog() {
return view_->learn_more_dialog_;
}
views::StyledLabel*
LoginExpandedPublicAccountView::TestApi::learn_more_label() {
return view_->right_pane_->learn_more_label_;
}
PublicAccountMenuView*
LoginExpandedPublicAccountView::TestApi::language_menu_view() {
return view_->right_pane_->language_menu_view_;
}
PublicAccountMenuView*
LoginExpandedPublicAccountView::TestApi::keyboard_menu_view() {
return view_->right_pane_->keyboard_menu_view_;
}
std::string
LoginExpandedPublicAccountView::TestApi::selected_language_item_value() {
return view_->right_pane_->selected_language_item_value_;
}
std::string
LoginExpandedPublicAccountView::TestApi::selected_keyboard_item_value() {
return view_->right_pane_->selected_keyboard_item_value_;
}
views::ImageView*
LoginExpandedPublicAccountView::TestApi::monitoring_warning_icon() {
if (view_->right_pane_->monitoring_warning_view_)
return view_->right_pane_->monitoring_warning_view_->image_;
return nullptr;
}
views::Label*
LoginExpandedPublicAccountView::TestApi::monitoring_warning_label() {
if (view_->right_pane_->monitoring_warning_view_)
return view_->right_pane_->monitoring_warning_view_->label_;
return nullptr;
}
void LoginExpandedPublicAccountView::TestApi::ResetUserForTest() {
if (view_->right_pane_->monitoring_warning_view_)
view_->right_pane_->monitoring_warning_view_->device_manager_.reset();
}
bool LoginExpandedPublicAccountView::TestApi::SelectLanguage(
const std::string& language_code) {
for (PublicAccountMenuView::Item item : view_->right_pane_->language_items_) {
if (item.value == language_code) {
view_->right_pane_->OnLanguageSelected(item.value);
return true;
}
}
return false;
}
bool LoginExpandedPublicAccountView::TestApi::SelectKeyboard(
const std::string& ime_id) {
for (PublicAccountMenuView::Item item : view_->right_pane_->keyboard_items_) {
if (item.value == ime_id) {
view_->right_pane_->OnKeyboardSelected(item.value);
return true;
}
}
return false;
}
std::vector<LocaleItem> LoginExpandedPublicAccountView::TestApi::GetLocales() {
std::vector<LocaleItem> locales;
for (PublicAccountMenuView::Item item : view_->right_pane_->language_items_) {
LocaleItem locale;
locale.title = item.title;
locale.language_code = item.value;
locales.push_back(locale);
}
return locales;
}
LoginExpandedPublicAccountView::LoginExpandedPublicAccountView(
const OnPublicSessionViewDismissed& on_dismissed)
: NonAccessibleView(kLoginExpandedPublicAccountViewClassName),
on_dismissed_(on_dismissed),
event_handler_(
std::make_unique<LoginExpandedPublicAccountEventHandler>(this)) {
auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal));
layout->SetDefaultFlex(1);
SetPreferredSize(gfx::Size(kExpandedViewWidthDp, kExpandedViewHeightDp));
user_view_ = new LoginUserView(
LoginDisplayStyle::kLarge, false /*show_dropdown*/, base::DoNothing(),
base::RepeatingClosure(), base::RepeatingClosure());
user_view_->SetForceOpaque(true);
user_view_->SetTapEnabled(false);
left_pane_ = new NonAccessibleView();
AddChildView(left_pane_);
left_pane_->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical));
left_pane_->SetPreferredSize(
gfx::Size(kExpandedViewWidthDp / 2, kExpandedViewHeightDp));
auto* top_spacing = new NonAccessibleView();
top_spacing->SetPreferredSize(
gfx::Size(kNonEmptyWidth, kTopSpacingForUserViewDp));
left_pane_->AddChildView(top_spacing);
left_pane_->AddChildView(user_view_);
left_pane_->SetBorder(views::CreateSolidSidedBorder(
gfx::Insets::TLBR(0, 0, 0, kBorderThicknessDp),
AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kSeparatorColor)));
right_pane_ = new RightPaneView(
base::BindRepeating(&LoginExpandedPublicAccountView::ShowWarningDialog,
base::Unretained(this)));
AddChildView(right_pane_);
}
LoginExpandedPublicAccountView::~LoginExpandedPublicAccountView() = default;
// static
void LoginExpandedPublicAccountView::RegisterLocalStatePrefs(
PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(
prefs::kManagedGuestSessionPrivacyWarningsEnabled, true);
}
void LoginExpandedPublicAccountView::ProcessPressedEvent(
const ui::LocatedEvent* event) {
if (!GetVisible())
return;
// Keep this view to be visible until learn more dialog is dismissed.
if (learn_more_dialog_ && learn_more_dialog_->IsVisible())
return;
if (GetBoundsInScreen().Contains(event->root_location()))
return;
// Ignore press event if the language or keyboard menu is still running,
// or if it had just been closed. Note that when we checked closed time,
// if the menu has never been closed, closed time will be set to time 0 and
// the time delta between now and then will be more than 100 ms.
PublicAccountMenuView* language_menu_view =
right_pane_->GetLanguageMenuView();
if (language_menu_view &&
(language_menu_view->IsMenuRunning() ||
(base::TimeTicks::Now() - language_menu_view->GetClosedTime()) <
views::kMinimumTimeBetweenButtonClicks)) {
return;
}
PublicAccountMenuView* keyboard_menu_view =
right_pane_->GetKeyboardMenuView();
if (keyboard_menu_view &&
(keyboard_menu_view->IsMenuRunning() ||
(base::TimeTicks::Now() - language_menu_view->GetClosedTime()) <
views::kMinimumTimeBetweenButtonClicks)) {
return;
}
Hide();
}
void LoginExpandedPublicAccountView::UpdateForUser(const LoginUserInfo& user) {
user_view_->UpdateForUser(user, false /*animate*/);
right_pane_->UpdateForUser(user);
}
const LoginUserInfo& LoginExpandedPublicAccountView::current_user() const {
return user_view_->current_user();
}
void LoginExpandedPublicAccountView::Hide() {
SetVisible(false);
right_pane_->Reset();
on_dismissed_.Run();
}
void LoginExpandedPublicAccountView::ShowWarningDialog() {
DCHECK(!learn_more_dialog_);
learn_more_dialog_ =
new PublicAccountMonitoringInfoDialog(weak_factory_.GetWeakPtr());
learn_more_dialog_->Show();
}
void LoginExpandedPublicAccountView::OnLearnMoreDialogClosed() {
learn_more_dialog_ = nullptr;
}
void LoginExpandedPublicAccountView::SetShowFullManagementDisclosure(
bool show_full_management_disclosure) {
right_pane_->SetShowFullManagementDisclosure(show_full_management_disclosure);
}
void LoginExpandedPublicAccountView::OnPaint(gfx::Canvas* canvas) {
views::View::OnPaint(canvas);
cc::PaintFlags flags;
flags.setStyle(cc::PaintFlags::kFill_Style);
flags.setColor(AshColorProvider::Get()->GetShieldLayerColor(
AshColorProvider::ShieldLayerType::kShield80));
flags.setAntiAlias(true);
canvas->DrawRoundRect(GetContentsBounds(), kRoundRectCornerRadiusDp, flags);
}
int LoginExpandedPublicAccountView::GetHeightForWidth(int w) const {
int left_height = left_pane_->GetHeightForWidth(w / 2);
int right_height = right_pane_->GetHeightForWidth(w / 2);
return std::max(left_height, right_height);
}
void LoginExpandedPublicAccountView::OnKeyEvent(ui::KeyEvent* event) {
if (!GetVisible() || event->type() != ui::ET_KEY_PRESSED)
return;
// Give learn more dialog a chance to handle key event.
if (learn_more_dialog_ && learn_more_dialog_->IsVisible())
return;
if (event->key_code() == ui::KeyboardCode::VKEY_ESCAPE) {
Hide();
}
}
} // namespace ash