0

Reland "ash: Add channel indicator UI to quick settings"

This is a reland of commit 72312ed235

To fix crbug.com/1345916, ash::FeedbackButton was renamed
ash::SubmitFeedbackButton. It turns out that ash::FeedbackButton
already exists here
    https://source.chromium.org/chromium/chromium/src/+/main:ash/wm/desks/templates/saved_desk_feedback_button.h;l=13

Because of this, construction and destruction of a (what is now called)
ash::SubmitFeedbackButton were actually invoking methods for (already
existing) ash::FeedbackButton. This caused a heap-buffer-overflow
that was (fortunately!) detected by AddressSanitizer.

Original change's description:
> ash: Add channel indicator UI to quick settings
>
> If a device is on a release track that's "beta," "dev," or "canary"
> then UnifiedSystemInfoView will show two extra buttons:
>
> - "version," displays the channel name and OS version, and takes the
> user to the "additional details" section of ChromeOS settings
>
> - "feedback," displays a word-bubble icon and opens the "submit
> feedback" dialog
>
> Bug: 1342673
> Change-Id: Ifde9e7d40599e7a9fbccb3fd606fc824e6a0e95e
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3751711
> Commit-Queue: Roger Tinkoff <rtinkoff@google.com>
> Reviewed-by: Alex Newcomer <newcomer@chromium.org>
> Reviewed-by: Ahmed Mehfooz <amehfooz@chromium.org>
> Reviewed-by: James Cook <jamescook@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#1025915}

Bug: 1342673, 1345916
Change-Id: Id81e3c31acefeb0414f2d86e95f6d7dcb1fa9b96
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3775005
Reviewed-by: Alex Newcomer <newcomer@chromium.org>
Commit-Queue: Roger Tinkoff <rtinkoff@google.com>
Reviewed-by: Roger Tinkoff <rtinkoff@google.com>
Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1027480}
This commit is contained in:
Roger Tinkoff
2022-07-22 23:58:27 +00:00
committed by Chromium LUCI CQ
parent 6b1c8c420b
commit bc55d76935
33 changed files with 888 additions and 138 deletions

@ -1110,6 +1110,10 @@ component("ash") {
"system/cast/unified_cast_detailed_view_controller.h",
"system/channel_indicator/channel_indicator.cc",
"system/channel_indicator/channel_indicator.h",
"system/channel_indicator/channel_indicator_quick_settings_view.cc",
"system/channel_indicator/channel_indicator_quick_settings_view.h",
"system/channel_indicator/channel_indicator_utils.cc",
"system/channel_indicator/channel_indicator_utils.h",
"system/dark_mode/dark_mode_feature_pod_controller.cc",
"system/dark_mode/dark_mode_feature_pod_controller.h",
"system/diagnostics/async_log.cc",
@ -2744,7 +2748,9 @@ test("ash_unittests") {
"system/bluetooth/tray_bluetooth_helper_legacy_unittest.cc",
"system/bluetooth/unified_bluetooth_detailed_view_controller_unittest.cc",
"system/caps_lock_notification_controller_unittest.cc",
"system/channel_indicator/channel_indicator_quick_settings_view_unittest.cc",
"system/channel_indicator/channel_indicator_unittest.cc",
"system/channel_indicator/channel_indicator_utils_unittest.cc",
"system/dark_mode/dark_mode_feature_pod_controller_unittest.cc",
"system/diagnostics/async_log_unittest.cc",
"system/diagnostics/diagnostics_log_controller_unittest.cc",

@ -2118,13 +2118,25 @@ Connect your device to power.
''' - '''
</message>
<!-- Status tray channel indicator strings -->
<message name="IDS_ASH_STATUS_TRAY_CHANNEL_BETA" desc="The string used to indicate that this device is on the beta release track">
<message name="IDS_ASH_STATUS_TRAY_REPORT_FEEDBACK" desc="The string used for the tooltip and speakable name of the 'report feedback' button">
Report feedback
</message>
<message name="IDS_ASH_STATUS_TRAY_CHANNEL_BETA" desc="The string used to show the name of beta release track, by itself">
Beta
</message>
<message name="IDS_ASH_STATUS_TRAY_CHANNEL_DEV" desc="The string used to show the name of dev release track, by itself">
Dev
</message>
<message name="IDS_ASH_STATUS_TRAY_CHANNEL_CANARY" desc="The string used to show the name of canary release track, by itself">
Canary
</message>
<message name="IDS_ASH_STATUS_TRAY_CHANNEL_BETA_CHANNEL" desc="The string used to indicate that this device is on the beta release track">
Beta Channel
</message>
<message name="IDS_ASH_STATUS_TRAY_CHANNEL_DEV" desc="The string used to indicate that this device is on the development release track">
<message name="IDS_ASH_STATUS_TRAY_CHANNEL_DEV_CHANNEL" desc="The string used to indicate that this device is on the development release track">
Dev Channel
</message>
<message name="IDS_ASH_STATUS_TRAY_CHANNEL_CANARY" desc="The string used to indicate that this device is on the canary release track">
<message name="IDS_ASH_STATUS_TRAY_CHANNEL_CANARY_CHANNEL" desc="The string used to indicate that this device is on the canary release track">
Canary Channel
</message>
<!-- Status Tray Network strings -->

@ -1 +1 @@
a23e8925d97be40954790401e84089e09af5a456
9089cfd7cee8fb5053295c5639a4a9e99055d090

@ -0,0 +1 @@
9089cfd7cee8fb5053295c5639a4a9e99055d090

@ -1 +1 @@
11b35d936ec8e0b18154281d9cf2392ad822bf62
8041c4627127d19acb3ba3a34b59a8bd4ebd10ce

@ -0,0 +1 @@
8041c4627127d19acb3ba3a34b59a8bd4ebd10ce

@ -1 +1 @@
b7a6ff57d02323da11175ecca7c8473ceed32487
68a5f4e9505763877bfdd169cdcee7a27ccb7913

@ -0,0 +1 @@
68a5f4e9505763877bfdd169cdcee7a27ccb7913

@ -0,0 +1 @@
54c61a6a20b846a2270c4bee736c419afb70697c

@ -159,6 +159,14 @@ class ASH_PUBLIC_EXPORT SystemTrayClient {
bool& opened_pwa,
GURL& finalized_event_url) = 0;
// Shown when the device is on a non-stable release track and the user clicks
// the channel/version button from quick settings.
virtual void ShowChannelInfoAdditionalDetails() = 0;
// Shown when the device is on a non-stable release track and the user clicks
// the "send feedback" button.
virtual void ShowChannelInfoGiveFeedback() = 0;
protected:
SystemTrayClient() {}
};

@ -120,4 +120,8 @@ void TestSystemTrayClient::ShowCalendarEvent(
bool& opened_pwa,
GURL& final_event_url) {}
void TestSystemTrayClient::ShowChannelInfoAdditionalDetails() {}
void TestSystemTrayClient::ShowChannelInfoGiveFeedback() {}
} // namespace ash

@ -66,6 +66,8 @@ class ASH_PUBLIC_EXPORT TestSystemTrayClient : public SystemTrayClient {
const base::Time& date,
bool& opened_pwa,
GURL& final_event_url) override;
void ShowChannelInfoAdditionalDetails() override;
void ShowChannelInfoGiveFeedback() override;
int show_bluetooth_settings_count() const {
return show_bluetooth_settings_count_;

@ -250,6 +250,7 @@ aggregate_vector_icons("ash_vector_icons") {
"reorder_nudge_dark_tablet.icon",
"reorder_nudge_light_clamshell.icon",
"reorder_nudge_light_tablet.icon",
"request_feedback.icon",
"resume.icon",
"save_desk_as_template.icon",
"save_desk_for_later.icon",

@ -0,0 +1,35 @@
// Copyright 2022 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.
CANVAS_DIMENSIONS, 20,
MOVE_TO, 9, 5,
H_LINE_TO, 11,
V_LINE_TO, 9,
H_LINE_TO, 9,
V_LINE_TO, 5,
CLOSE,
NEW_PATH,
MOVE_TO, 9, 10,
H_LINE_TO, 11,
V_LINE_TO, 12,
H_LINE_TO, 9,
V_LINE_TO, 10,
CLOSE,
NEW_PATH,
MOVE_TO, 3.67f, 2,
H_LINE_TO, 16,
CUBIC_TO, 16.92f, 2, 18, 2.58f, 18, 3.5f,
V_LINE_TO, 13.5f,
CUBIC_TO, 18, 14.42f, 16.92f, 15, 16, 15,
H_LINE_TO, 5,
LINE_TO, 2, 17.5f,
LINE_TO, 2.01f, 3.67f,
CUBIC_TO, 2.01f, 2.75f, 2.75f, 2, 3.67f, 2,
CLOSE,
MOVE_TO, 4, 13,
H_LINE_TO, 16,
V_LINE_TO, 4,
H_LINE_TO, 4,
V_LINE_TO, 13,
CLOSE

@ -149,6 +149,9 @@ class ASH_EXPORT ShellDelegate {
// window when that window is closed.
virtual void ForceSkipWarningUserOnClose(
const std::vector<aura::Window*>& windows) = 0;
// Retrieves the official Chrome version string e.g. 105.0.5178.0.
virtual std::string GetVersionString() = 0;
};
} // namespace ash

@ -4,26 +4,16 @@
#include "ash/system/channel_indicator/channel_indicator.h"
#include <string>
#include <utility>
#include "ash/public/cpp/shelf_config.h"
#include "ash/public/cpp/style/dark_light_mode_controller.h"
#include "ash/public/cpp/system_tray_client.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/model/system_tray_model.h"
#include "ash/shelf/shelf.h"
#include "ash/system/channel_indicator/channel_indicator_utils.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray/tray_item_view.h"
#include "components/session_manager/session_manager_types.h"
#include "components/version_info/channel.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/view.h"
namespace ash {
@ -31,64 +21,6 @@ namespace {
constexpr int kIndicatorBgCornerRadius = 50;
bool IsDisplayableChannel(version_info::Channel channel) {
switch (channel) {
case version_info::Channel::BETA:
case version_info::Channel::DEV:
case version_info::Channel::CANARY:
return true;
default:
return false;
}
}
SkColor GetFgColor(version_info::Channel channel) {
bool is_dark_mode_enabled =
DarkLightModeController::Get()->IsDarkModeEnabled();
switch (channel) {
case version_info::Channel::BETA:
return is_dark_mode_enabled ? gfx::kGoogleBlue200 : gfx::kGoogleBlue900;
case version_info::Channel::DEV:
return is_dark_mode_enabled ? gfx::kGoogleGreen200 : gfx::kGoogleGreen900;
case version_info::Channel::CANARY:
return is_dark_mode_enabled ? gfx::kGoogleYellow200 : gfx::kGoogleGrey900;
default:
return 0;
}
}
SkColor GetBgColor(version_info::Channel channel) {
bool is_dark_mode_enabled =
DarkLightModeController::Get()->IsDarkModeEnabled();
switch (channel) {
case version_info::Channel::BETA:
return is_dark_mode_enabled ? SkColorSetA(gfx::kGoogleBlue300, 0x55)
: gfx::kGoogleBlue200;
case version_info::Channel::DEV:
return is_dark_mode_enabled ? SkColorSetA(gfx::kGoogleGreen300, 0x55)
: gfx::kGoogleGreen200;
case version_info::Channel::CANARY:
return is_dark_mode_enabled ? SkColorSetA(gfx::kGoogleYellow300, 0x55)
: gfx::kGoogleYellow200;
default:
return 0;
}
}
int GetStringResource(version_info::Channel channel) {
DCHECK(IsDisplayableChannel(channel));
switch (channel) {
case version_info::Channel::BETA:
return IDS_ASH_STATUS_TRAY_CHANNEL_BETA;
case version_info::Channel::DEV:
return IDS_ASH_STATUS_TRAY_CHANNEL_DEV;
case version_info::Channel::CANARY:
return IDS_ASH_STATUS_TRAY_CHANNEL_CANARY;
default:
return -1;
}
}
} // namespace
ChannelIndicatorView::ChannelIndicatorView(Shelf* shelf,
@ -133,7 +65,7 @@ void ChannelIndicatorView::HandleLocaleChange() {
}
void ChannelIndicatorView::Update(version_info::Channel channel) {
if (!IsDisplayableChannel(channel))
if (!channel_indicator_utils::IsDisplayableChannel(channel))
return;
SetVisible(true);
@ -143,28 +75,28 @@ void ChannelIndicatorView::Update(version_info::Channel channel) {
}
void ChannelIndicatorView::SetImage(version_info::Channel channel) {
DCHECK(IsDisplayableChannel(channel));
DCHECK(channel_indicator_utils::IsDisplayableChannel(channel));
SetBorder(views::CreateEmptyBorder(
gfx::Insets::VH(kUnifiedTrayChannelIndicatorDimension / 2, 0)));
image_view()->SetBackground(views::CreateRoundedRectBackground(
GetBgColor(channel), kIndicatorBgCornerRadius));
channel_indicator_utils::GetBgColor(channel), kIndicatorBgCornerRadius));
switch (channel) {
case version_info::Channel::BETA:
image_view()->SetImage(gfx::CreateVectorIcon(
kChannelBetaIcon, kUnifiedTrayChannelIndicatorDimension,
GetFgColor(channel)));
channel_indicator_utils::GetFgColor(channel)));
break;
case version_info::Channel::DEV:
image_view()->SetImage(gfx::CreateVectorIcon(
kChannelDevIcon, kUnifiedTrayChannelIndicatorDimension,
GetFgColor(channel)));
channel_indicator_utils::GetFgColor(channel)));
break;
case version_info::Channel::CANARY:
image_view()->SetImage(gfx::CreateVectorIcon(
kChannelCanaryIcon, kUnifiedTrayChannelIndicatorDimension,
GetFgColor(channel)));
channel_indicator_utils::GetFgColor(channel)));
break;
default:
break;
@ -172,14 +104,16 @@ void ChannelIndicatorView::SetImage(version_info::Channel channel) {
}
void ChannelIndicatorView::SetAccessibleName(version_info::Channel channel) {
DCHECK(IsDisplayableChannel(channel));
accessible_name_ = l10n_util::GetStringUTF16(GetStringResource(channel));
DCHECK(channel_indicator_utils::IsDisplayableChannel(channel));
accessible_name_ = l10n_util::GetStringUTF16(
channel_indicator_utils::GetChannelNameStringResourceID(channel, true));
image_view()->SetAccessibleName(accessible_name_);
}
void ChannelIndicatorView::SetTooltip(version_info::Channel channel) {
DCHECK(IsDisplayableChannel(channel));
tooltip_ = l10n_util::GetStringUTF16(GetStringResource(channel));
DCHECK(channel_indicator_utils::IsDisplayableChannel(channel));
tooltip_ = l10n_util::GetStringUTF16(
channel_indicator_utils::GetChannelNameStringResourceID(channel, true));
}
} // namespace ash

@ -39,9 +39,14 @@ class ChannelIndicatorView : public TrayItemView {
void SetAccessibleName(version_info::Channel channel);
void SetTooltip(version_info::Channel channel);
// The localized string used to announce this view in accessibility mode.
std::u16string accessible_name_;
// The localized string displayed when this view is hovered-over.
std::u16string tooltip_;
version_info::Channel channel_;
// The release track on which this devices resides.
const version_info::Channel channel_;
};
} // namespace ash

@ -0,0 +1,180 @@
// Copyright 2022 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/channel_indicator/channel_indicator_quick_settings_view.h"
#include "ash/public/cpp/system_tray_client.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/icon_button.h"
#include "ash/system/channel_indicator/channel_indicator_utils.h"
#include "ash/system/model/system_tray_model.h"
#include "ash/system/tray/tray_constants.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/highlight_path_generator.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/view.h"
namespace ash {
namespace {
constexpr int kVersionButtonHeight = 32;
constexpr int kVersionButtonBorderRadius = 4;
constexpr int kVersionButtonImageLabelSpacing = 8;
constexpr int kVersionButtonMarginVertical = 6;
constexpr int kVersionButtonMarginHorizontal = 16;
constexpr int kVersionButtonLargeCornerRadius = 16;
constexpr int kVersionButtonSmallCornerRadius = 4;
constexpr SkScalar kVersionButtonCorners[] = {
kVersionButtonLargeCornerRadius, kVersionButtonLargeCornerRadius,
kVersionButtonSmallCornerRadius, kVersionButtonSmallCornerRadius,
kVersionButtonSmallCornerRadius, kVersionButtonSmallCornerRadius,
kVersionButtonLargeCornerRadius, kVersionButtonLargeCornerRadius};
constexpr int kSubmitFeedbackButtonMarginVertical = 6;
constexpr int kSubmitFeedbackButtonMarginHorizontal = 16;
constexpr int kSubmitFeedbackButtonLargeCornerRadius = 16;
constexpr int kSubmitFeedbackButtonSmallCornerRadius = 4;
constexpr SkScalar kSubmitFeedbackButtonCorners[] = {
kSubmitFeedbackButtonSmallCornerRadius,
kSubmitFeedbackButtonSmallCornerRadius,
kSubmitFeedbackButtonLargeCornerRadius,
kSubmitFeedbackButtonLargeCornerRadius,
kSubmitFeedbackButtonLargeCornerRadius,
kSubmitFeedbackButtonLargeCornerRadius,
kSubmitFeedbackButtonSmallCornerRadius,
kSubmitFeedbackButtonSmallCornerRadius};
constexpr int kButtonSpacing = 2;
} // namespace
// VersionButton provides a styled button, for devices on a
// non-stable release track, that has a label for the channel and ChromeOS
// version.
class ASH_EXPORT VersionButton : public views::LabelButton {
public:
explicit VersionButton(version_info::Channel channel)
: LabelButton(
base::BindRepeating([] {
Shell::Get()
->system_tray_model()
->client()
->ShowChannelInfoAdditionalDetails();
}),
channel_indicator_utils::GetFullReleaseTrackString(channel)),
channel_(channel) {
SetBorder(views::CreateEmptyBorder(gfx::Insets::VH(
kVersionButtonMarginVertical, kVersionButtonMarginHorizontal)));
SetImageLabelSpacing(kVersionButtonImageLabelSpacing);
SetMinSize(gfx::Size(0, kVersionButtonHeight));
SetFocusBehavior(FocusBehavior::ALWAYS);
SetInstallFocusRingOnFocus(true);
views::FocusRing::Get(this)->SetColorId(ui::kColorAshFocusRing);
views::InstallRoundRectHighlightPathGenerator(this, gfx::Insets(),
kVersionButtonBorderRadius);
}
VersionButton(const VersionButton&) = delete;
VersionButton& operator=(const VersionButton&) = delete;
~VersionButton() override = default;
// views::LabelButton:
void PaintButtonContents(gfx::Canvas* canvas) override {
cc::PaintFlags flags;
flags.setColor(channel_indicator_utils::GetBgColor(channel_));
flags.setStyle(cc::PaintFlags::kFill_Style);
canvas->DrawPath(
SkPath().addRoundRect(gfx::RectToSkRect(GetLocalBounds()),
kVersionButtonCorners, SkPathDirection::kCW),
flags);
}
void OnThemeChanged() override {
views::LabelButton::OnThemeChanged();
SetBackgroundAndFont();
}
private:
void SetBackgroundAndFont() {
label()->SetFontList(
gfx::FontList().DeriveWithWeight(gfx::Font::Weight::MEDIUM));
SetEnabledTextColors(channel_indicator_utils::GetFgColor(channel_));
}
const version_info::Channel channel_;
};
// SubmitFeedbackButton provides a styled button, for devices on a
// non-stable release track, that allows the user to submit feedback.
class ASH_EXPORT SubmitFeedbackButton : public IconButton {
public:
explicit SubmitFeedbackButton(version_info::Channel channel)
: IconButton(base::BindRepeating([] {
Shell::Get()
->system_tray_model()
->client()
->ShowChannelInfoGiveFeedback();
}),
IconButton::Type::kSmall,
&kRequestFeedbackIcon,
IDS_ASH_STATUS_TRAY_REPORT_FEEDBACK),
channel_(channel) {
SetBorder(views::CreateEmptyBorder(
gfx::Insets::VH(kSubmitFeedbackButtonMarginVertical,
kSubmitFeedbackButtonMarginHorizontal)));
SetIconColor(channel_indicator_utils::GetFgColor(channel_));
}
SubmitFeedbackButton(const SubmitFeedbackButton&) = delete;
SubmitFeedbackButton& operator=(const SubmitFeedbackButton&) = delete;
~SubmitFeedbackButton() override = default;
// views::LabelButton:
void PaintButtonContents(gfx::Canvas* canvas) override {
cc::PaintFlags flags;
flags.setColor(channel_indicator_utils::GetBgColor(channel_));
flags.setStyle(cc::PaintFlags::kFill_Style);
canvas->DrawPath(SkPath().addRoundRect(gfx::RectToSkRect(GetLocalBounds()),
kSubmitFeedbackButtonCorners,
SkPathDirection::kCW),
flags);
IconButton::PaintButtonContents(canvas);
}
private:
const version_info::Channel channel_;
};
ChannelIndicatorQuickSettingsView::ChannelIndicatorQuickSettingsView(
version_info::Channel channel) {
auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, kUnifiedSystemInfoViewPadding,
kUnifiedSystemInfoSpacing));
layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
layout->set_between_child_spacing(kButtonSpacing);
version_button_ = AddChildView(std::make_unique<VersionButton>(channel));
feedback_button_ =
AddChildView(std::make_unique<SubmitFeedbackButton>(channel));
}
bool ChannelIndicatorQuickSettingsView::IsVersionButtonVisibleForTesting() {
return version_button_->GetVisible();
}
bool ChannelIndicatorQuickSettingsView::
IsSubmitFeedbackButtonVisibleForTesting() {
return feedback_button_->GetVisible();
}
} // namespace ash

@ -0,0 +1,40 @@
// Copyright 2022 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.
#ifndef ASH_SYSTEM_CHANNEL_INDICATOR_CHANNEL_INDICATOR_QUICK_SETTINGS_VIEW_H_
#define ASH_SYSTEM_CHANNEL_INDICATOR_CHANNEL_INDICATOR_QUICK_SETTINGS_VIEW_H_
#include "ash/ash_export.h"
#include "components/version_info/channel.h"
#include "ui/views/view.h"
namespace ash {
class VersionButton;
class SubmitFeedbackButton;
// ChannelIndicatorQuickSettingsView contains all of the views included in the
// channel indicator UI that resides in UnifiedSystemInfoView.
class ASH_EXPORT ChannelIndicatorQuickSettingsView : public views::View {
public:
explicit ChannelIndicatorQuickSettingsView(version_info::Channel channel);
ChannelIndicatorQuickSettingsView(const ChannelIndicatorQuickSettingsView&) =
delete;
ChannelIndicatorQuickSettingsView& operator=(
const ChannelIndicatorQuickSettingsView&) = delete;
~ChannelIndicatorQuickSettingsView() override = default;
// Introspection methods for unit tests.
bool IsVersionButtonVisibleForTesting();
bool IsSubmitFeedbackButtonVisibleForTesting();
private:
// Refs maintained for unit test introspection methods.
VersionButton* version_button_ = nullptr;
SubmitFeedbackButton* feedback_button_ = nullptr;
};
} // namespace ash
#endif // ASH_SYSTEM_CHANNEL_INDICATOR_CHANNEL_INDICATOR_QUICK_SETTINGS_VIEW_H_

@ -0,0 +1,59 @@
// Copyright 2022 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/channel_indicator/channel_indicator_quick_settings_view.h"
#include "ash/constants/ash_features.h"
#include "ash/test/ash_test_base.h"
#include "components/version_info/channel.h"
namespace ash {
class ChannelIndicatorQuickSettingsViewTest
: public AshTestBase,
public testing::WithParamInterface<bool> {
public:
ChannelIndicatorQuickSettingsViewTest() = default;
ChannelIndicatorQuickSettingsViewTest(
const ChannelIndicatorQuickSettingsViewTest&) = delete;
ChannelIndicatorQuickSettingsViewTest& operator=(
const ChannelIndicatorQuickSettingsViewTest&) = delete;
~ChannelIndicatorQuickSettingsViewTest() override = default;
// AshTestBase:
void SetUp() override {
AshTestBase::SetUp();
// Instantiate members.
view_ = std::make_unique<ChannelIndicatorQuickSettingsView>(
static_cast<version_info::Channel>(GetParam()));
}
// Ignored for now, will come into play with the fix for crbug.com/1344855.
bool IsFeedbackShown() { return GetParam(); }
ChannelIndicatorQuickSettingsView* view() { return view_.get(); }
private:
std::unique_ptr<ChannelIndicatorQuickSettingsView> view_;
};
// Run the `Visible` test below for each value of version_info::Channel.
INSTANTIATE_TEST_SUITE_P(ChannelValues,
ChannelIndicatorQuickSettingsViewTest,
::testing::Bool());
TEST_P(ChannelIndicatorQuickSettingsViewTest, Visible) {
// View exists.
EXPECT_TRUE(view());
// Version button is always visible.
EXPECT_TRUE(view()->IsVersionButtonVisibleForTesting());
// Feedback button is always visible, for now. This will change with the fix
// for crbug.com/1344855.
EXPECT_TRUE(view()->IsSubmitFeedbackButtonVisibleForTesting());
}
} // namespace ash

@ -21,6 +21,12 @@ class ChannelIndicatorViewTest
: public AshTestBase,
public testing::WithParamInterface<version_info::Channel> {
public:
ChannelIndicatorViewTest() = default;
ChannelIndicatorViewTest(const ChannelIndicatorViewTest&) = delete;
ChannelIndicatorViewTest& operator=(const ChannelIndicatorViewTest&) = delete;
~ChannelIndicatorViewTest() override = default;
// AshTestBase:
void SetUp() override {
// Need this feature enabled in order for the `ChannelIndicatorView` to be
// instantiated.

@ -0,0 +1,100 @@
// Copyright 2022 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/channel_indicator/channel_indicator_utils.h"
#include <string>
#include "ash/public/cpp/style/dark_light_mode_controller.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "ash/strings/grit/ash_strings.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/color_palette.h"
namespace ash::channel_indicator_utils {
bool IsDisplayableChannel(version_info::Channel channel) {
switch (channel) {
case version_info::Channel::BETA:
case version_info::Channel::DEV:
case version_info::Channel::CANARY:
return true;
case version_info::Channel::STABLE:
case version_info::Channel::UNKNOWN:
return false;
}
}
int GetChannelNameStringResourceID(version_info::Channel channel,
bool append_channel) {
switch (channel) {
case version_info::Channel::BETA:
return append_channel ? IDS_ASH_STATUS_TRAY_CHANNEL_BETA_CHANNEL
: IDS_ASH_STATUS_TRAY_CHANNEL_BETA;
case version_info::Channel::DEV:
return append_channel ? IDS_ASH_STATUS_TRAY_CHANNEL_DEV_CHANNEL
: IDS_ASH_STATUS_TRAY_CHANNEL_DEV;
case version_info::Channel::CANARY:
return append_channel ? IDS_ASH_STATUS_TRAY_CHANNEL_CANARY_CHANNEL
: IDS_ASH_STATUS_TRAY_CHANNEL_CANARY;
// Handle STABLE/UNKNOWN here to satisfy the compiler without using
// "default," but the DCHECK() above will bark if that value is ever
// actually passed in.
case version_info::Channel::STABLE:
case version_info::Channel::UNKNOWN:
return -1;
}
}
SkColor GetFgColor(version_info::Channel channel) {
bool is_dark_mode_enabled =
DarkLightModeController::Get()->IsDarkModeEnabled();
switch (channel) {
case version_info::Channel::BETA:
return is_dark_mode_enabled ? gfx::kGoogleBlue200 : gfx::kGoogleBlue900;
case version_info::Channel::DEV:
return is_dark_mode_enabled ? gfx::kGoogleGreen200 : gfx::kGoogleGreen900;
case version_info::Channel::CANARY:
return is_dark_mode_enabled ? gfx::kGoogleYellow200 : gfx::kGoogleGrey900;
case version_info::Channel::STABLE:
case version_info::Channel::UNKNOWN:
return SkColorSetRGB(0x00, 0x00, 0x00);
}
}
SkColor GetBgColor(version_info::Channel channel) {
bool is_dark_mode_enabled =
DarkLightModeController::Get()->IsDarkModeEnabled();
switch (channel) {
case version_info::Channel::BETA:
return is_dark_mode_enabled ? SkColorSetA(gfx::kGoogleBlue300, 0x55)
: gfx::kGoogleBlue200;
case version_info::Channel::DEV:
return is_dark_mode_enabled ? SkColorSetA(gfx::kGoogleGreen300, 0x55)
: gfx::kGoogleGreen200;
case version_info::Channel::CANARY:
return is_dark_mode_enabled ? SkColorSetA(gfx::kGoogleYellow300, 0x55)
: gfx::kGoogleYellow200;
case version_info::Channel::STABLE:
case version_info::Channel::UNKNOWN:
return SkColorSetRGB(0x00, 0x00, 0x00);
}
}
std::u16string GetFullReleaseTrackString(version_info::Channel channel) {
if (!IsDisplayableChannel(channel))
return std::u16string();
return base::StrCat(
{l10n_util::GetStringUTF16(
channel_indicator_utils::GetChannelNameStringResourceID(channel,
false)),
u" ",
base::UTF8ToUTF16(Shell::Get()->shell_delegate()->GetVersionString())});
}
} // namespace ash::channel_indicator_utils

@ -0,0 +1,44 @@
// Copyright 2022 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.
#ifndef ASH_SYSTEM_CHANNEL_INDICATOR_CHANNEL_INDICATOR_UTILS_H_
#define ASH_SYSTEM_CHANNEL_INDICATOR_CHANNEL_INDICATOR_UTILS_H_
#include <string>
#include "ash/ash_export.h"
#include "components/version_info/channel.h"
#include "third_party/skia/include/core/SkColor.h"
namespace ash::channel_indicator_utils {
// Returns 'true' if `channel` is a release track name we want to show the user.
ASH_EXPORT bool IsDisplayableChannel(version_info::Channel channel);
// Returns a string resource ID for the release track `channel`. If
// `append_channel` is 'true' then the resource ID returned is for a string that
// has "channel" at the end e.g. "Beta Channel" instead of just "Beta". If
// `channel` is `STABLE` or `UNKNOWN` this function will return -1.
ASH_EXPORT int GetChannelNameStringResourceID(version_info::Channel channel,
bool append_channel);
// Returns the foreground UI color for release track `channel`. If `channel` is
// one of the displayable values then the expected `SkColor` is returned, a
// value of SkColorSetRGB(0x00, 0x00, 0x00) otherwise.
ASH_EXPORT SkColor GetFgColor(version_info::Channel channel);
// Returns the background UI color for release track `channel`. If `channel` is
// one of the displayable values then the expected `SkColor` is returned, a
// value of SkColorSetRGB(0x00, 0x00, 0x00) otherwise.
ASH_EXPORT SkColor GetBgColor(version_info::Channel channel);
// Returns the text for the version button text, for release track `channel`
// e.g. "Beta 105.0.5167.0". If `channel` is not one of the displayable values,
// the function will return an empty std::u16string.
ASH_EXPORT std::u16string GetFullReleaseTrackString(
version_info::Channel channel);
} // namespace ash::channel_indicator_utils
#endif // ASH_SYSTEM_CHANNEL_INDICATOR_CHANNEL_INDICATOR_UTILS_H_

@ -0,0 +1,114 @@
// Copyright 2022 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/channel_indicator/channel_indicator_utils.h"
#include <string>
#include "ash/public/cpp/style/dark_light_mode_controller.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/test/ash_test_base.h"
#include "ash/test_shell_delegate.h"
#include "components/version_info/channel.h"
#include "ui/gfx/color_palette.h"
namespace ash {
namespace {
// OS version that's set, and final button string that's expected.
const char* kTestOsVersion = "123.45.6789.10";
const char16_t* kTestButtonStr = u"Beta 123.45.6789.10";
} // namespace
class ChannelIndicatorUtilsTest : public AshTestBase {
public:
ChannelIndicatorUtilsTest() = default;
ChannelIndicatorUtilsTest(const ChannelIndicatorUtilsTest&) = delete;
ChannelIndicatorUtilsTest& operator=(const ChannelIndicatorUtilsTest&) =
delete;
~ChannelIndicatorUtilsTest() override = default;
// AshTestBase:
void SetUp() override {
// Instantiate a `TestShellDelegate` with the version set to something
// tests can verify.
std::unique_ptr<TestShellDelegate> shell_delegate =
std::make_unique<TestShellDelegate>();
shell_delegate->set_version_string(kTestOsVersion);
AshTestBase::SetUp(std::move(shell_delegate));
}
};
TEST_F(ChannelIndicatorUtilsTest, IsDisplayableChannel) {
EXPECT_FALSE(channel_indicator_utils::IsDisplayableChannel(
version_info::Channel::UNKNOWN));
EXPECT_TRUE(channel_indicator_utils::IsDisplayableChannel(
version_info::Channel::CANARY));
EXPECT_TRUE(channel_indicator_utils::IsDisplayableChannel(
version_info::Channel::DEV));
EXPECT_TRUE(channel_indicator_utils::IsDisplayableChannel(
version_info::Channel::BETA));
EXPECT_FALSE(channel_indicator_utils::IsDisplayableChannel(
version_info::Channel::STABLE));
}
TEST_F(ChannelIndicatorUtilsTest, GetChannelNameStringResourceID) {
// Non-displayable channel should yield a resource_id of -1.
EXPECT_EQ(channel_indicator_utils::GetChannelNameStringResourceID(
version_info::Channel::STABLE, false),
-1);
// Same thing if `append_channel` is `true`.
EXPECT_EQ(channel_indicator_utils::GetChannelNameStringResourceID(
version_info::Channel::STABLE, true),
-1);
// Displayable channel should yield a valid resource_id.
EXPECT_EQ(channel_indicator_utils::GetChannelNameStringResourceID(
version_info::Channel::BETA, false),
IDS_ASH_STATUS_TRAY_CHANNEL_BETA);
// An equally-valid resource_id if `append_channel` is `true`.
EXPECT_EQ(channel_indicator_utils::GetChannelNameStringResourceID(
version_info::Channel::BETA, true),
IDS_ASH_STATUS_TRAY_CHANNEL_BETA_CHANNEL);
}
TEST_F(ChannelIndicatorUtilsTest, GetColors) {
// Non-displayable channel should yield fg/bg colors of 0.
EXPECT_EQ(channel_indicator_utils::GetFgColor(version_info::Channel::STABLE),
SkColorSetRGB(0x00, 0x00, 0x00));
EXPECT_EQ(channel_indicator_utils::GetBgColor(version_info::Channel::STABLE),
SkColorSetRGB(0x00, 0x00, 0x00));
// Displayable channel should yield valid, nonzero fg/bg colors. Check with
// dark mode not enabled first.
DarkLightModeController::Get()->SetDarkModeEnabledForTest(false);
EXPECT_EQ(channel_indicator_utils::GetFgColor(version_info::Channel::BETA),
gfx::kGoogleBlue900);
EXPECT_EQ(channel_indicator_utils::GetBgColor(version_info::Channel::BETA),
gfx::kGoogleBlue200);
// Check with dark mode enabled.
DarkLightModeController::Get()->SetDarkModeEnabledForTest(true);
EXPECT_EQ(channel_indicator_utils::GetFgColor(version_info::Channel::BETA),
gfx::kGoogleBlue200);
EXPECT_EQ(channel_indicator_utils::GetBgColor(version_info::Channel::BETA),
SkColorSetA(gfx::kGoogleBlue300, 0x55));
}
TEST_F(ChannelIndicatorUtilsTest, GetFullReleaseTrackString) {
// Channel is not displayable, no string.
EXPECT_TRUE(channel_indicator_utils::GetFullReleaseTrackString(
version_info::Channel::STABLE)
.empty());
// Channel is displayable, string that's expected.
EXPECT_EQ(channel_indicator_utils::GetFullReleaseTrackString(
version_info::Channel::BETA),
kTestButtonStr);
}
} // namespace ash

@ -10,8 +10,11 @@
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h"
#include "ash/system/channel_indicator/channel_indicator_quick_settings_view.h"
#include "ash/system/channel_indicator/channel_indicator_utils.h"
#include "ash/system/enterprise/enterprise_domain_observer.h"
#include "ash/system/model/clock_model.h"
#include "ash/system/model/clock_observer.h"
@ -24,6 +27,7 @@
#include "ash/system/tray/system_tray_notifier.h"
#include "ash/system/tray/tray_popup_utils.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/i18n/time_formatting.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
@ -260,7 +264,7 @@ class BatteryLabelView : public BatteryInfoViewBase {
auto seperator = std::make_unique<views::Label>();
seperator->SetText(l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_BATTERY_STATUS_SEPARATOR));
separator_ = AddChildView(std::move(seperator));
separator_view_ = AddChildView(std::move(seperator));
status_ = AddChildView(std::make_unique<views::Label>());
Update();
}
@ -275,7 +279,7 @@ class BatteryLabelView : public BatteryInfoViewBase {
const auto color =
GetContentLayerColor(ContentLayerType::kTextColorSecondary);
ConfigureLabel(percentage_, color);
ConfigureLabel(separator_, color);
ConfigureLabel(separator_view_, color);
ConfigureLabel(status_, color);
}
@ -291,8 +295,9 @@ class BatteryLabelView : public BatteryInfoViewBase {
percentage_->SetVisible(!percentage_text.empty() &&
!use_smart_charging_ui_);
separator_->SetVisible(!percentage_text.empty() &&
!use_smart_charging_ui_ && !status_text.empty());
separator_view_->SetVisible(!percentage_text.empty() &&
!use_smart_charging_ui_ &&
!status_text.empty());
status_->SetVisible(!status_text.empty());
percentage_->NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true);
@ -300,7 +305,7 @@ class BatteryLabelView : public BatteryInfoViewBase {
}
views::Label* percentage_ = nullptr;
views::Label* separator_ = nullptr;
views::Label* separator_view_ = nullptr;
views::Label* status_ = nullptr;
const bool use_smart_charging_ui_;
@ -585,34 +590,88 @@ SupervisedUserView::SupervisedUserView()
} // namespace
// A view that contains date, battery status, and whether the device
// is enterprise managed.
class ManagementPowerDateComboView : public views::View {
public:
explicit ManagementPowerDateComboView(
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(std::make_unique<DateView>(controller));
if (PowerStatus::Get()->IsBatteryPresent()) {
separator_view_ = AddChildView(std::make_unique<views::Separator>());
separator_view_->SetColorId(ui::kColorAshSystemUIMenuSeparator);
separator_view_->SetPreferredLength(kUnifiedSystemInfoHeight);
const bool use_smart_charging_ui = UseSmartChargingUI();
if (use_smart_charging_ui)
AddChildView(std::make_unique<BatteryIconView>(controller));
AddChildView(std::make_unique<BatteryLabelView>(controller,
use_smart_charging_ui));
}
auto* spacing = AddChildView(std::make_unique<views::View>());
layout->SetFlexForView(spacing, 1);
enterprise_managed_view_ =
AddChildView(std::make_unique<EnterpriseManagedView>(controller));
supervised_view_ = AddChildView(std::make_unique<SupervisedUserView>());
}
ManagementPowerDateComboView(const ManagementPowerDateComboView&) = delete;
ManagementPowerDateComboView& operator=(const ManagementPowerDateComboView&) =
delete;
~ManagementPowerDateComboView() override = default;
// Introspection methods for unit tests, that call into individual views.
bool IsEnterpriseManagedVisibleForTesting() {
return enterprise_managed_view_->GetVisible();
}
bool IsSupervisedVisibleForTesting() {
return supervised_view_->GetVisible();
}
private:
// Pointer to the actual child view is maintained for unit testing, owned by
// `ManagementPowerDateComboView`.
EnterpriseManagedView* enterprise_managed_view_ = nullptr;
// Pointer to the actual child view is maintained for unit testing, owned by
// `ManagementPowerDateComboView`.
SupervisedUserView* supervised_view_ = nullptr;
// Separator between date and battery views, owned by
// `ManagementPowerDateComboView`.
views::Separator* separator_view_ = nullptr;
};
UnifiedSystemInfoView::UnifiedSystemInfoView(
UnifiedSystemTrayController* controller) {
// Layout for the overall UnifiedSystemInfoView.
auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, kUnifiedSystemInfoViewPadding,
views::BoxLayout::Orientation::kVertical, kUnifiedSystemInfoViewPadding,
kUnifiedSystemInfoSpacing));
layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
AddChildView(std::make_unique<DateView>(controller));
// Construct a ManagementPowerDateComboView and save off a raw pointer, to
// facilitate introspection needed for unit tests.
combo_view_ =
AddChildView(std::make_unique<ManagementPowerDateComboView>(controller));
if (PowerStatus::Get()->IsBatteryPresent()) {
separator_ = AddChildView(std::make_unique<views::Separator>());
separator_->SetColorId(ui::kColorAshSystemUIMenuSeparator);
separator_->SetPreferredLength(kUnifiedSystemInfoHeight);
const bool use_smart_charging_ui = UseSmartChargingUI();
if (use_smart_charging_ui)
AddChildView(std::make_unique<BatteryIconView>(controller));
AddChildView(
std::make_unique<BatteryLabelView>(controller, use_smart_charging_ui));
// If the release track is not "stable" then channel indicator UI for quick
// settings is put up.
auto channel = Shell::Get()->shell_delegate()->GetChannel();
if (features::IsReleaseTrackUiEnabled() &&
channel_indicator_utils::IsDisplayableChannel(channel)) {
channel_view_ = AddChildView(
std::make_unique<ChannelIndicatorQuickSettingsView>(channel));
}
auto* spacing = AddChildView(std::make_unique<views::View>());
layout->SetFlexForView(spacing, 1);
enterprise_managed_ =
AddChildView(std::make_unique<EnterpriseManagedView>(controller));
supervised_ = AddChildView(std::make_unique<SupervisedUserView>());
}
UnifiedSystemInfoView::~UnifiedSystemInfoView() = default;
@ -625,6 +684,18 @@ void UnifiedSystemInfoView::ChildPreferredSizeChanged(views::View* child) {
Layout();
}
bool UnifiedSystemInfoView::IsEnterpriseManagedVisibleForTesting() {
return combo_view_->IsEnterpriseManagedVisibleForTesting(); // IN-TEST
}
bool UnifiedSystemInfoView::IsSupervisedVisibleForTesting() {
return combo_view_->IsSupervisedVisibleForTesting(); // IN-TEST
}
bool UnifiedSystemInfoView::IsChannelIndicatorQuickSettingsVisibleForTesting() {
return channel_view_ && channel_view_->GetVisible(); // IN-TEST
}
BEGIN_METADATA(UnifiedSystemInfoView, views::View)
END_METADATA

@ -11,15 +11,13 @@
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/views/view.h"
namespace views {
class Separator;
} // namespace views
namespace ash {
class ManagementPowerDateComboView;
class ChannelIndicatorQuickSettingsView;
// A view at the bottom of UnifiedSystemTray bubble that shows system
// information. The view contains date, battery status, and whether the device
// is enterprise managed or not.
// information.
class ASH_EXPORT UnifiedSystemInfoView : public views::View {
public:
METADATA_HEADER(UnifiedSystemInfoView);
@ -34,6 +32,11 @@ class ASH_EXPORT UnifiedSystemInfoView : public views::View {
void ChildPreferredSizeChanged(views::View* child) override;
void ChildVisibilityChanged(views::View* child) override;
// Introspection methods needed for unit tests.
bool IsEnterpriseManagedVisibleForTesting();
bool IsSupervisedVisibleForTesting();
bool IsChannelIndicatorQuickSettingsVisibleForTesting();
private:
FRIEND_TEST_ALL_PREFIXES(UnifiedSystemInfoViewTest, EnterpriseManagedVisible);
FRIEND_TEST_ALL_PREFIXES(UnifiedSystemInfoViewTest,
@ -42,14 +45,14 @@ class ASH_EXPORT UnifiedSystemInfoView : public views::View {
EnterpriseUserManagedVisible);
FRIEND_TEST_ALL_PREFIXES(UnifiedSystemInfoViewNoSessionTest, ChildVisible);
// EnterpriseManagedView for unit testing. Owned by this view. Null if
// kManagedDeviceUIRedesign is enabled.
views::View* enterprise_managed_ = nullptr;
// SupervisedUserView for unit testing. Owned by this view . Null if
// kManagedDeviceUIRedesign is enabled.
views::View* supervised_ = nullptr;
// Raw pointer to the combo view (owned by `UnifiedSystemInfoView`) that
// facilitates introspection needed for unit tests.
ManagementPowerDateComboView* combo_view_ = nullptr;
views::Separator* separator_ = nullptr;
// Raw pointer to the channel indicator quick settings view (owned by
// `UnifiedSystemInfoView`) that facilitates introspection needed for unit
// tests.
ChannelIndicatorQuickSettingsView* channel_view_ = nullptr;
};
} // namespace ash

@ -14,13 +14,47 @@
#include "ash/system/unified/unified_system_tray_controller.h"
#include "ash/system/unified/unified_system_tray_model.h"
#include "ash/test/ash_test_base.h"
#include "ash/test_shell_delegate.h"
#include "base/memory/scoped_refptr.h"
#include "base/test/scoped_feature_list.h"
#include "components/version_info/channel.h"
namespace ash {
class UnifiedSystemInfoViewTest : public AshTestBase,
public testing::WithParamInterface<bool> {
// `UnifiedSystemInfoView` contains a set of "baseline" UI elements that are
// always visible, but some elements are visible only under certain conditions.
// To verify that these "conditional" UI elements are visible or not-visible
// only when expected, each `UnifiedSystemInfoViewTest` test case is executed
// with every possible combination of the following flags, passed as a
// parameter.
enum class TestFlags : uint8_t {
// No conditional UI flags are set.
kNone = 0b00000000,
// Enterprise/management status display is enabled.
kManagedDeviceUi = 0b00000001,
// Release track UI is visible if two conditions are met: (1) the feature that
// guards its display is enabled (kReleaseTrackUi) and (2) the release track
// itself is a value other than "stable" (kReleaseTrackNotStable). Each
// combination of one, none, or both of these conditions is a valid scenario.
kReleaseTrackUi = 0b00000010,
kReleaseTrackNotStable = 0b00000100,
};
TestFlags operator&(TestFlags a, TestFlags b) {
return static_cast<TestFlags>(static_cast<uint8_t>(a) &
static_cast<uint8_t>(b));
}
TestFlags operator|(TestFlags a, TestFlags b) {
return static_cast<TestFlags>(static_cast<uint8_t>(a) |
static_cast<uint8_t>(b));
}
class UnifiedSystemInfoViewTest
: public AshTestBase,
public testing::WithParamInterface<TestFlags> {
public:
UnifiedSystemInfoViewTest() = default;
UnifiedSystemInfoViewTest(const UnifiedSystemInfoViewTest&) = delete;
@ -29,18 +63,45 @@ class UnifiedSystemInfoViewTest : public AshTestBase,
~UnifiedSystemInfoViewTest() override = default;
void SetUp() override {
AshTestBase::SetUp();
// Provide our own `TestShellDelegate`, with a non-stable channel set if
// the passed-in parameter dictates.
std::unique_ptr<TestShellDelegate> shell_delegate =
std::make_unique<TestShellDelegate>();
if (IsReleaseTrackNotStable())
shell_delegate->set_channel(version_info::Channel::BETA);
AshTestBase::SetUp(std::move(shell_delegate));
// Enable/disable of the two features we care about is conditional on the
// passed-in parameter.
scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
scoped_feature_list_->InitWithFeatureState(
features::kManagedDeviceUIRedesign, IsManagedDeviceUIRedesignEnabled());
std::vector<base::Feature> enabled_features, disabled_features;
if (IsManagedDeviceUIRedesignEnabled())
enabled_features.push_back(features::kManagedDeviceUIRedesign);
else
disabled_features.push_back(features::kManagedDeviceUIRedesign);
if (IsReleaseTrackUiEnabled())
enabled_features.push_back(features::kReleaseTrackUi);
else
disabled_features.push_back(features::kReleaseTrackUi);
scoped_feature_list_->InitWithFeatures(enabled_features, disabled_features);
// Instantiate members.
model_ = base::MakeRefCounted<UnifiedSystemTrayModel>(nullptr);
controller_ = std::make_unique<UnifiedSystemTrayController>(model_.get());
info_view_ = std::make_unique<UnifiedSystemInfoView>(controller_.get());
}
bool IsManagedDeviceUIRedesignEnabled() const { return GetParam(); }
bool IsManagedDeviceUIRedesignEnabled() const {
return (GetParam() & TestFlags::kManagedDeviceUi) != TestFlags::kNone;
}
bool IsReleaseTrackUiEnabled() const {
return (GetParam() & TestFlags::kReleaseTrackUi) != TestFlags::kNone;
}
bool IsReleaseTrackNotStable() const {
return (GetParam() & TestFlags::kReleaseTrackNotStable) != TestFlags::kNone;
}
void TearDown() override {
info_view_.reset();
@ -63,14 +124,25 @@ class UnifiedSystemInfoViewTest : public AshTestBase,
std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
};
// Execute each test case with every possible combination of `TestFlags`.
INSTANTIATE_TEST_SUITE_P(
All,
UnifiedSystemInfoViewTest,
testing::Bool() /* IsManagedDeviceUIRedesignEnabled() */);
testing::Values(TestFlags::kNone,
TestFlags::kManagedDeviceUi,
TestFlags::kReleaseTrackUi,
TestFlags::kManagedDeviceUi | TestFlags::kReleaseTrackUi,
TestFlags::kReleaseTrackNotStable,
TestFlags::kManagedDeviceUi |
TestFlags::kReleaseTrackNotStable,
TestFlags::kReleaseTrackUi |
TestFlags::kReleaseTrackNotStable,
TestFlags::kManagedDeviceUi | TestFlags::kReleaseTrackUi |
TestFlags::kReleaseTrackNotStable));
TEST_P(UnifiedSystemInfoViewTest, EnterpriseManagedVisible) {
// By default, EnterpriseManagedView is not shown.
EXPECT_FALSE(info_view()->enterprise_managed_->GetVisible());
EXPECT_FALSE(info_view()->IsEnterpriseManagedVisibleForTesting());
// Simulate enterprise information becoming available.
enterprise_domain()->SetDeviceEnterpriseInfo(
@ -78,7 +150,12 @@ TEST_P(UnifiedSystemInfoViewTest, EnterpriseManagedVisible) {
ManagementDeviceMode::kChromeEnterprise});
// EnterpriseManagedView should be shown.
EXPECT_TRUE(info_view()->enterprise_managed_->GetVisible());
EXPECT_TRUE(info_view()->IsEnterpriseManagedVisibleForTesting());
// If the release track UI is enabled AND the release track is non-stable, the
// ChannelIndicatorQuickSettingsView is shown.
EXPECT_EQ(IsReleaseTrackUiEnabled() && IsReleaseTrackNotStable(),
info_view()->IsChannelIndicatorQuickSettingsVisibleForTesting());
}
TEST_P(UnifiedSystemInfoViewTest, EnterpriseManagedVisibleForActiveDirectory) {
@ -89,19 +166,29 @@ TEST_P(UnifiedSystemInfoViewTest, EnterpriseManagedVisibleForActiveDirectory) {
ManagementDeviceMode::kChromeEnterprise});
// EnterpriseManagedView should be shown.
EXPECT_TRUE(info_view()->enterprise_managed_->GetVisible());
EXPECT_TRUE(info_view()->IsEnterpriseManagedVisibleForTesting());
// If the release track UI is enabled AND the release track is non-stable, the
// ChannelIndicatorQuickSettingsView is shown.
EXPECT_EQ(IsReleaseTrackUiEnabled() && IsReleaseTrackNotStable(),
info_view()->IsChannelIndicatorQuickSettingsVisibleForTesting());
}
TEST_P(UnifiedSystemInfoViewTest, EnterpriseUserManagedVisible) {
// By default, EnterpriseManagedView is not shown.
EXPECT_FALSE(info_view()->enterprise_managed_->GetVisible());
EXPECT_FALSE(info_view()->IsEnterpriseManagedVisibleForTesting());
// Simulate enterprise information becoming available.
enterprise_domain()->SetEnterpriseAccountDomainInfo("example.com");
// EnterpriseManagedView should be shown if the feature is enabled.
EXPECT_EQ(IsManagedDeviceUIRedesignEnabled(),
info_view()->enterprise_managed_->GetVisible());
info_view()->IsEnterpriseManagedVisibleForTesting());
// If the release track UI is enabled AND the release track is non-stable, the
// ChannelIndicatorQuickSettingsView is shown.
EXPECT_EQ(IsReleaseTrackUiEnabled() && IsReleaseTrackNotStable(),
info_view()->IsChannelIndicatorQuickSettingsVisibleForTesting());
}
using UnifiedSystemInfoViewNoSessionTest = NoSessionAshTestBase;
@ -118,7 +205,7 @@ TEST_F(UnifiedSystemInfoViewNoSessionTest, ChildVisible) {
// Before login the supervised user view is invisible.
{
auto info_view = std::make_unique<UnifiedSystemInfoView>(controller.get());
EXPECT_FALSE(info_view->supervised_->GetVisible());
EXPECT_FALSE(info_view->IsSupervisedVisibleForTesting());
}
// Simulate a supervised user logging in.
@ -133,7 +220,7 @@ TEST_F(UnifiedSystemInfoViewNoSessionTest, ChildVisible) {
// Now the supervised user view is visible.
{
auto info_view = std::make_unique<UnifiedSystemInfoView>(controller.get());
EXPECT_TRUE(info_view->supervised_->GetVisible());
EXPECT_TRUE(info_view->IsSupervisedVisibleForTesting());
}
}

@ -5,6 +5,7 @@
#include "ash/test_shell_delegate.h"
#include <memory>
#include <string>
#include "ash/accessibility/default_accessibility_delegate.h"
#include "ash/capture_mode/test_capture_mode_delegate.h"
@ -119,4 +120,8 @@ version_info::Channel TestShellDelegate::GetChannel() {
return channel_;
}
std::string TestShellDelegate::GetVersionString() {
return version_string_;
}
} // namespace ash

@ -6,6 +6,7 @@
#define ASH_TEST_SHELL_DELEGATE_H_
#include <memory>
#include <string>
#include "ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
#include "ash/shell_delegate.h"
@ -67,9 +68,14 @@ class TestShellDelegate : public ShellDelegate {
void OpenFeedbackPageForPersistentDesksBar() override {}
void SetLastCommittedURLForWindow(const GURL& url);
version_info::Channel GetChannel() override;
std::string GetVersionString() override;
void set_channel(version_info::Channel channel) { channel_ = channel; }
void set_version_string(const std::string& string) {
version_string_ = string;
}
private:
// True if the current top window can go back.
bool can_go_back_ = true;
@ -91,6 +97,8 @@ class TestShellDelegate : public ShellDelegate {
GURL last_committed_url_ = GURL::EmptyGURL();
version_info::Channel channel_ = version_info::Channel::UNKNOWN;
std::string version_string_;
};
} // namespace ash

@ -53,6 +53,8 @@
#include "chrome/common/chrome_switches.h"
#include "components/ui_devtools/devtools_server.h"
#include "components/user_manager/user_manager.h"
#include "components/version_info/channel.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/device_service.h"
#include "content/public/browser/media_session_service.h"
#include "content/public/browser/render_widget_host.h"
@ -352,3 +354,7 @@ void ChromeShellDelegate::ForceSkipWarningUserOnClose(
}
}
}
std::string ChromeShellDelegate::GetVersionString() {
return version_info::GetVersionNumber();
}

@ -6,6 +6,7 @@
#define CHROME_BROWSER_UI_ASH_CHROME_SHELL_DELEGATE_H_
#include <memory>
#include <string>
#include "ash/shell_delegate.h"
#include "base/callback_forward.h"
@ -65,6 +66,7 @@ class ChromeShellDelegate : public ash::ShellDelegate {
version_info::Channel GetChannel() override;
void ForceSkipWarningUserOnClose(
const std::vector<aura::Window*>& windows) override;
std::string GetVersionString() override;
};
#endif // CHROME_BROWSER_UI_ASH_CHROME_SHELL_DELEGATE_H_

@ -757,6 +757,15 @@ void SystemTrayClientImpl::ShowCalendarEvent(
opened_pwa = true;
}
void SystemTrayClientImpl::ShowChannelInfoAdditionalDetails() {
ShowSettingsSubPageForActiveUser(
std::string(chromeos::settings::mojom::kDetailedBuildInfoSubpagePath));
}
void SystemTrayClientImpl::ShowChannelInfoGiveFeedback() {
ash::NewWindowDelegate::GetInstance()->OpenFeedbackPage();
}
SystemTrayClientImpl::SystemTrayClientImpl(SystemTrayClientImpl* mock_instance)
: system_tray_(nullptr) {
DCHECK(!g_system_tray_client_instance);

@ -104,6 +104,8 @@ class SystemTrayClientImpl : public ash::SystemTrayClient,
const base::Time& date,
bool& opened_pwa,
GURL& finalized_event_url) override;
void ShowChannelInfoAdditionalDetails() override;
void ShowChannelInfoGiveFeedback() override;
protected:
// Used by mocks in tests.