blob: 75c3975c9e708fa0d0142bd1e81ec737111b0a14 [file] [log] [blame]
// 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 "ash/system/user/tray_user.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/session/session_controller.h"
#include "ash/shelf/shelf.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/tray/system_tray.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray/tray_item_view.h"
#include "ash/system/tray/tray_utils.h"
#include "ash/system/user/rounded_image_view.h"
#include "ash/system/user/user_view.h"
#include "base/logging.h"
#include "base/strings/string16.h"
#include "components/signin/core/account_id/account_id.h"
#include "components/user_manager/user_info.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/paint_vector_icon.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/view.h"
#include "ui/views/widget/widget.h"
namespace {
const int kUserLabelToIconPadding = 5;
views::ImageView* CreateIcon() {
gfx::ImageSkia icon_image =
gfx::CreateVectorIcon(ash::kSystemMenuChildUserIcon, ash::kTrayIconColor);
auto* image = new views::ImageView;
image->SetImage(icon_image);
return image;
}
} // namespace
namespace ash {
TrayUser::TrayUser(SystemTray* system_tray)
: SystemTrayItem(system_tray, UMA_USER), scoped_session_observer_(this) {}
TrayUser::~TrayUser() = default;
TrayUser::TestState TrayUser::GetStateForTest() const {
if (!user_)
return HIDDEN;
return user_->GetStateForTest();
}
gfx::Size TrayUser::GetLayoutSizeForTest() const {
return layout_view_ ? layout_view_->size() : gfx::Size();
}
gfx::Rect TrayUser::GetUserPanelBoundsInScreenForTest() const {
return user_->GetBoundsInScreenOfUserButtonForTest();
}
void TrayUser::UpdateAfterLoginStatusChangeForTest(LoginStatus status) {
UpdateAfterLoginStatusChange(status);
}
views::View* TrayUser::CreateTrayView(LoginStatus status) {
DCHECK(!layout_view_);
layout_view_ = new views::View;
UpdateAfterLoginStatusChange(status);
return layout_view_;
}
views::View* TrayUser::CreateDefaultView(LoginStatus status) {
if (status == LoginStatus::NOT_LOGGED_IN)
return nullptr;
DCHECK(!user_);
user_ = new tray::UserView(this, status);
return user_;
}
void TrayUser::OnTrayViewDestroyed() {
layout_view_ = nullptr;
avatar_ = nullptr;
label_ = nullptr;
}
void TrayUser::OnDefaultViewDestroyed() {
user_ = nullptr;
}
void TrayUser::UpdateAfterLoginStatusChange(LoginStatus status) {
SessionController* session = Shell::Get()->session_controller();
bool need_label = session->IsUserSupervised();
bool need_avatar = false;
bool need_icon = false;
switch (status) {
case LoginStatus::LOCKED:
case LoginStatus::USER:
case LoginStatus::OWNER:
case LoginStatus::PUBLIC:
need_avatar = true;
break;
case LoginStatus::SUPERVISED:
need_avatar = true;
if (session->IsUserChild()) {
need_label = false;
need_icon = true;
} else {
need_label = true;
}
break;
case LoginStatus::GUEST:
need_label = true;
break;
case LoginStatus::KIOSK_APP:
case LoginStatus::ARC_KIOSK_APP:
case LoginStatus::NOT_LOGGED_IN:
break;
}
if ((need_avatar != (avatar_ != nullptr)) ||
(need_label != (label_ != nullptr)) ||
(need_icon != (icon_ != nullptr))) {
delete label_;
delete avatar_;
delete icon_;
label_ = nullptr;
avatar_ = nullptr;
icon_ = nullptr;
if (need_icon) {
icon_ = CreateIcon();
layout_view_->AddChildView(icon_);
}
if (need_label) {
label_ = new views::Label;
SetupLabelForTray(label_);
layout_view_->AddChildView(label_);
}
if (need_avatar) {
avatar_ = new tray::RoundedImageView(kTrayRoundedBorderRadius);
avatar_->SetPaintToLayer();
avatar_->layer()->SetFillsBoundsOpaquely(false);
layout_view_->AddChildView(avatar_);
}
}
if (label_ && session->IsUserSupervised()) {
label_->SetText(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SUPERVISED_LABEL));
} else if (status == LoginStatus::GUEST) {
label_->SetText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_GUEST_LABEL));
}
UpdateAvatarImage(status);
// Update layout after setting label_, icon_ and avatar_ with new login
// status.
UpdateLayoutOfItem();
}
void TrayUser::UpdateAfterShelfAlignmentChange() {
if (system_tray()->shelf()->IsHorizontalAlignment()) {
if (avatar_) {
avatar_->SetCornerRadii(0, kTrayRoundedBorderRadius,
kTrayRoundedBorderRadius, 0);
}
if (label_) {
// If label_ hasn't figured out its size yet, do that first.
if (label_->GetContentsBounds().height() == 0)
label_->SizeToPreferredSize();
int height = label_->GetContentsBounds().height();
int vertical_pad = (kTrayItemSize - height) / 2;
int remainder = height % 2;
label_->SetBorder(views::CreateEmptyBorder(
vertical_pad + remainder,
kTrayLabelItemHorizontalPaddingBottomAlignment, vertical_pad,
kTrayLabelItemHorizontalPaddingBottomAlignment));
}
layout_view_->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::kHorizontal, gfx::Insets(), kUserLabelToIconPadding));
} else {
if (avatar_) {
avatar_->SetCornerRadii(0, 0, kTrayRoundedBorderRadius,
kTrayRoundedBorderRadius);
}
if (label_) {
label_->SetBorder(views::CreateEmptyBorder(
kTrayLabelItemVerticalPaddingVerticalAlignment,
kTrayLabelItemHorizontalPaddingBottomAlignment,
kTrayLabelItemVerticalPaddingVerticalAlignment,
kTrayLabelItemHorizontalPaddingBottomAlignment));
}
layout_view_->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::kVertical, gfx::Insets(), kUserLabelToIconPadding));
}
}
void TrayUser::OnActiveUserSessionChanged(const AccountId& account_id) {
OnUserSessionUpdated(account_id);
}
void TrayUser::OnUserSessionAdded(const AccountId& account_id) {
// Enforce a layout change that newly added items become visible.
UpdateLayoutOfItem();
// Update the user item.
UpdateAvatarImage(Shell::Get()->session_controller()->login_status());
}
void TrayUser::OnUserSessionUpdated(const AccountId& account_id) {
UpdateAvatarImage(Shell::Get()->session_controller()->login_status());
}
void TrayUser::UpdateAvatarImage(LoginStatus status) {
const SessionController* session_controller =
Shell::Get()->session_controller();
if (!avatar_ || session_controller->NumberOfLoggedInUsers() == 0)
return;
const mojom::UserSession* const user_session =
session_controller->GetUserSession(0);
avatar_->SetImage(user_session->user_info->avatar,
gfx::Size(kTrayItemSize, kTrayItemSize));
// Unit tests might come here with no images for some users.
if (avatar_->size().IsEmpty())
avatar_->SetSize(gfx::Size(kTrayItemSize, kTrayItemSize));
}
void TrayUser::UpdateLayoutOfItem() {
UpdateAfterShelfAlignmentChange();
}
} // namespace ash