blob: 5ac7ea15b8c6c2f34b5b6b9e7a53729f7c19139a [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/system/unified/unified_system_info_view.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/ash_view_ids.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/session/session_controller_impl.h"
#include "ash/session/session_observer.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h"
#include "ash/style/default_color_constants.h"
#include "ash/system/enterprise/enterprise_domain_observer.h"
#include "ash/system/model/clock_model.h"
#include "ash/system/model/clock_observer.h"
#include "ash/system/model/enterprise_domain_model.h"
#include "ash/system/model/system_tray_model.h"
#include "ash/system/power/power_status.h"
#include "ash/system/supervised/supervised_icon_string.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "ash/system/tray/tray_popup_utils.h"
#include "base/i18n/time_formatting.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "chromeos/strings/grit/chromeos_strings.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/animation/ink_drop_highlight.h"
#include "ui/views/animation/ink_drop_impl.h"
#include "ui/views/animation/ink_drop_ripple.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/separator.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
namespace ash {
using ContentLayerType = AshColorProvider::ContentLayerType;
using AshColorMode = AshColorProvider::AshColorMode;
namespace {
base::string16 FormatDate(const base::Time& time) {
// Use 'short' month format (e.g., "Oct") followed by non-padded day of
// month (e.g., "2", "10").
return base::TimeFormatWithPattern(time, "LLLd");
}
base::string16 FormatDayOfWeek(const base::Time& time) {
// Use 'short' day of week format (e.g., "Wed").
return base::TimeFormatWithPattern(time, "EEE");
}
// A view that shows current date in short format e.g. "Mon, Mar 12". It updates
// by observing ClockObserver.
class DateView : public views::Button,
public views::ButtonListener,
public ClockObserver {
public:
explicit DateView(UnifiedSystemTrayController* controller);
~DateView() override;
// views::Button:
const char* GetClassName() const override { return "DateView"; }
private:
void Update();
// views::Button:
gfx::Insets GetInsets() const override;
// views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
// ClockObserver:
void OnDateFormatChanged() override;
void OnSystemClockTimeUpdated() override;
void OnSystemClockCanSetTimeChanged(bool can_set_time) override;
void Refresh() override;
UnifiedSystemTrayController* const controller_;
views::Label* label_;
DISALLOW_COPY_AND_ASSIGN(DateView);
};
DateView::DateView(UnifiedSystemTrayController* controller)
: Button(this), controller_(controller), label_(new views::Label) {
SetLayoutManager(std::make_unique<views::FillLayout>());
AddChildView(label_);
label_->SetAutoColorReadabilityEnabled(false);
label_->SetSubpixelRenderingEnabled(false);
label_->SetEnabledColor(
AshColorProvider::Get()->DeprecatedGetContentLayerColor(
ContentLayerType::kTextPrimary, kUnifiedMenuTextColor));
Update();
Shell::Get()->system_tray_model()->clock()->AddObserver(this);
SetEnabled(Shell::Get()->system_tray_model()->clock()->IsSettingsAvailable());
SetInstallFocusRingOnFocus(true);
SetFocusForPlatform();
SetInkDropMode(views::InkDropHostView::InkDropMode::OFF);
}
DateView::~DateView() {
Shell::Get()->system_tray_model()->clock()->RemoveObserver(this);
}
void DateView::ButtonPressed(views::Button* sender, const ui::Event& event) {
controller_->HandleOpenDateTimeSettingsAction();
}
void DateView::Update() {
base::Time now = base::Time::Now();
label_->SetText(l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DATE, FormatDayOfWeek(now), FormatDate(now)));
SetAccessibleName(TimeFormatFriendlyDateAndTime(now));
label_->NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true);
NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true);
}
gfx::Insets DateView::GetInsets() const {
// This padding provides room to render the focus ring around this button.
return kUnifiedSystemInfoDateViewPadding;
}
void DateView::OnDateFormatChanged() {}
void DateView::OnSystemClockTimeUpdated() {
Update();
}
void DateView::OnSystemClockCanSetTimeChanged(bool can_set_time) {}
void DateView::Refresh() {
Update();
}
// A view that shows battery status. It updates by observing PowerStatus.
class BatteryView : public views::View, public PowerStatus::Observer {
public:
BatteryView();
~BatteryView() override;
// views::View:
void ChildPreferredSizeChanged(views::View* child) override;
void ChildVisibilityChanged(views::View* child) override;
const char* GetClassName() const override { return "BatteryView"; }
// PowerStatus::Observer:
void OnPowerStatusChanged() override;
private:
void Update();
void ConfigureLabel(views::Label* label);
views::Label* percentage_;
views::Label* separator_;
views::Label* status_;
DISALLOW_COPY_AND_ASSIGN(BatteryView);
};
BatteryView::BatteryView()
: percentage_(new views::Label),
separator_(new views::Label),
status_(new views::Label) {
PowerStatus::Get()->AddObserver(this);
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal));
separator_->SetText(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_STATUS_SEPARATOR));
ConfigureLabel(percentage_);
ConfigureLabel(separator_);
ConfigureLabel(status_);
AddChildView(percentage_);
AddChildView(separator_);
AddChildView(status_);
Update();
}
BatteryView::~BatteryView() {
PowerStatus::Get()->RemoveObserver(this);
}
void BatteryView::ChildPreferredSizeChanged(views::View* child) {
PreferredSizeChanged();
}
void BatteryView::ChildVisibilityChanged(views::View* child) {
PreferredSizeChanged();
}
void BatteryView::OnPowerStatusChanged() {
Update();
}
void BatteryView::Update() {
base::string16 percentage_text;
base::string16 status_text;
std::tie(percentage_text, status_text) =
PowerStatus::Get()->GetStatusStrings();
percentage_->SetText(percentage_text);
status_->SetText(status_text);
percentage_->SetVisible(!percentage_text.empty());
separator_->SetVisible(!percentage_text.empty() && !status_text.empty());
status_->SetVisible(!status_text.empty());
percentage_->NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true);
status_->NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true);
}
void BatteryView::ConfigureLabel(views::Label* label) {
label->SetAutoColorReadabilityEnabled(false);
label->SetSubpixelRenderingEnabled(false);
label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
ContentLayerType::kTextSecondary, AshColorMode::kDark));
}
// A base class of the views showing device management state.
class ManagedStateView : public views::Button {
public:
~ManagedStateView() override = default;
// views::Button:
const char* GetClassName() const override { return "ManagedStateView"; }
protected:
ManagedStateView(views::ButtonListener* listener,
int label_id,
const gfx::VectorIcon& icon);
private:
DISALLOW_COPY_AND_ASSIGN(ManagedStateView);
};
ManagedStateView::ManagedStateView(views::ButtonListener* listener,
int label_id,
const gfx::VectorIcon& icon)
: Button(listener) {
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
kUnifiedSystemInfoSpacing));
auto* label = new views::Label;
label->SetAutoColorReadabilityEnabled(false);
label->SetSubpixelRenderingEnabled(false);
label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
ContentLayerType::kTextSecondary, AshColorMode::kDark));
label->SetText(l10n_util::GetStringUTF16(label_id));
AddChildView(label);
auto* image = new views::ImageView;
image->SetImage(gfx::CreateVectorIcon(
icon, AshColorProvider::Get()->GetContentLayerColor(
ContentLayerType::kIconSecondary, AshColorMode::kDark)));
image->SetPreferredSize(
gfx::Size(kUnifiedSystemInfoHeight, kUnifiedSystemInfoHeight));
AddChildView(image);
SetInstallFocusRingOnFocus(true);
SetFocusForPlatform();
SetInkDropMode(views::InkDropHostView::InkDropMode::OFF);
}
// A view that shows whether the device is enterprise managed or not. It updates
// by observing EnterpriseDomainModel.
class EnterpriseManagedView : public ManagedStateView,
public views::ButtonListener,
public EnterpriseDomainObserver,
public SessionObserver {
public:
explicit EnterpriseManagedView(UnifiedSystemTrayController* controller);
~EnterpriseManagedView() override;
// views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
// EnterpriseDomainObserver:
void OnEnterpriseDomainChanged() override;
// SessionObserver:
void OnLoginStatusChanged(LoginStatus status) override;
// views::Button:
const char* GetClassName() const override { return "EnterpriseManagedView"; }
private:
void Update();
UnifiedSystemTrayController* const controller_;
DISALLOW_COPY_AND_ASSIGN(EnterpriseManagedView);
};
EnterpriseManagedView::EnterpriseManagedView(
UnifiedSystemTrayController* controller)
: ManagedStateView(this,
IDS_ASH_ENTERPRISE_DEVICE_MANAGED_SHORT,
kUnifiedMenuManagedIcon),
controller_(controller) {
DCHECK(Shell::Get());
SetID(VIEW_ID_TRAY_ENTERPRISE);
Shell::Get()->system_tray_model()->enterprise_domain()->AddObserver(this);
Shell::Get()->session_controller()->AddObserver(this);
Update();
}
EnterpriseManagedView::~EnterpriseManagedView() {
Shell::Get()->system_tray_model()->enterprise_domain()->RemoveObserver(this);
Shell::Get()->session_controller()->RemoveObserver(this);
}
void EnterpriseManagedView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
controller_->HandleEnterpriseInfoAction();
}
void EnterpriseManagedView::OnEnterpriseDomainChanged() {
Update();
}
void EnterpriseManagedView::OnLoginStatusChanged(LoginStatus status) {
Update();
}
void EnterpriseManagedView::Update() {
EnterpriseDomainModel* model =
Shell::Get()->system_tray_model()->enterprise_domain();
SessionControllerImpl* session_controller =
Shell::Get()->session_controller();
SetVisible(session_controller->ShouldDisplayManagedUI() ||
model->active_directory_managed() ||
!model->enterprise_display_domain().empty());
if (model->active_directory_managed()) {
SetTooltipText(
l10n_util::GetStringUTF16(IDS_ASH_ENTERPRISE_DEVICE_MANAGED));
} else if (!model->enterprise_display_domain().empty()) {
SetTooltipText(l10n_util::GetStringFUTF16(
IDS_ASH_ENTERPRISE_DEVICE_MANAGED_BY,
base::UTF8ToUTF16(model->enterprise_display_domain())));
}
}
// A view that shows whether the user is supervised or a child.
class SupervisedUserView : public ManagedStateView {
public:
SupervisedUserView();
~SupervisedUserView() override = default;
// views::Button:
const char* GetClassName() const override { return "SupervisedUserView"; }
private:
DISALLOW_COPY_AND_ASSIGN(SupervisedUserView);
};
SupervisedUserView::SupervisedUserView()
: ManagedStateView(nullptr,
IDS_ASH_STATUS_TRAY_SUPERVISED_LABEL,
GetSupervisedUserIcon()) {
SetVisible(Shell::Get()->session_controller()->IsUserSupervised());
if (Shell::Get()->session_controller()->IsUserSupervised())
SetTooltipText(GetSupervisedUserMessage());
}
} // namespace
UnifiedSystemInfoView::UnifiedSystemInfoView(
UnifiedSystemTrayController* controller) {
auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, kUnifiedSystemInfoViewPadding,
kUnifiedSystemInfoSpacing));
layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
AddChildView(new DateView(controller));
if (PowerStatus::Get()->IsBatteryPresent()) {
auto* separator = new views::Separator();
separator->SetColor(AshColorProvider::Get()->GetContentLayerColor(
ContentLayerType::kSeparator, AshColorMode::kDark));
separator->SetPreferredHeight(kUnifiedSystemInfoHeight);
AddChildView(separator);
AddChildView(new BatteryView());
}
auto* spacing = new views::View;
AddChildView(spacing);
layout->SetFlexForView(spacing, 1);
if (!features::IsManagedDeviceUIRedesignEnabled()) {
// UnifiedManagedDeviceView is shown instead.
enterprise_managed_ = new EnterpriseManagedView(controller);
supervised_ = new SupervisedUserView();
AddChildView(enterprise_managed_);
AddChildView(supervised_);
}
}
UnifiedSystemInfoView::~UnifiedSystemInfoView() = default;
void UnifiedSystemInfoView::ChildVisibilityChanged(views::View* child) {
Layout();
}
void UnifiedSystemInfoView::ChildPreferredSizeChanged(views::View* child) {
Layout();
}
const char* UnifiedSystemInfoView::GetClassName() const {
return "UnifiedSystemInfoView";
}
} // namespace ash