blob: e505e0c133cfe6c6974f5f8252ee7dee6f1d195c [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/exclusive_access_bubble_views.h"
#include <string>
#include "base/strings/string_util.h"
#include "build/buildflag.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/ui/accelerator_utils.h"
#include "chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/test_with_browser_view.h"
#include "components/fullscreen_control/subtle_notification_view.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/accessibility/view_accessibility.h"
namespace {
enum UserGoal {
kExitFullscreen = 0,
kExitPointerLock = 1,
kExitFullscreenAndSeeDownload = 2,
kSeeDownload = 3,
};
enum Shortcut {
kPressEsc = 0,
kPressAndHoldEsc = 1,
kAccelerator = 2,
};
struct InstructionTextTestCase {
std::string test_name;
ExclusiveAccessBubbleType type;
UserGoal goal;
Shortcut shortcut;
bool enable_feature = false;
};
std::u16string GetUserGoalText(UserGoal goal) {
switch (goal) {
case kExitFullscreen:
return u"To exit full screen";
case kExitPointerLock:
return u"To show your cursor";
case kExitFullscreenAndSeeDownload:
return u"To exit full screen and see download";
case kSeeDownload:
return u"Download started. To see it";
default:
return u"";
}
}
std::u16string GetEscShortcutString(bool press_and_hold) {
std::u16string esc = u"Esc";
#if BUILDFLAG(IS_MAC)
esc = u"esc";
#endif
return (press_and_hold ? u"press and hold |" : u"press |") + esc + u"|";
}
} // namespace
class ExclusiveAccessBubbleViewsTest : public TestWithBrowserView {
public:
ExclusiveAccessBubbleViewsTest() = default;
void SetUp() override {
TestWithBrowserView::SetUp();
ExclusiveAccessBubbleParams params{
.type = EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_EXIT_INSTRUCTION};
bubble_view_ = std::make_unique<ExclusiveAccessBubbleViews>(
browser_view(), params, base::NullCallback());
}
void TearDown() override {
bubble_view_.reset();
TestWithBrowserView::TearDown();
}
void UpdateExclusiveAccessBubbleType(ExclusiveAccessBubbleType type,
bool has_download) {
ExclusiveAccessBubbleParams params{
.type = type, .has_download = has_download, .force_update = true};
bubble_view_->Update(params, base::NullCallback());
}
std::u16string GetFullscreenAcceleratorString() {
#if BUILDFLAG(IS_CHROMEOS)
return u"Fullscreen";
#else
ui::Accelerator accelerator;
chrome::AcceleratorProviderForBrowser(browser_view()->browser())
->GetAcceleratorForCommandId(IDC_FULLSCREEN, &accelerator);
return accelerator.GetShortcutText();
#endif
}
std::u16string GetShortcutText(Shortcut shortcut) {
switch (shortcut) {
case kPressEsc:
return GetEscShortcutString(false);
case kPressAndHoldEsc:
return GetEscShortcutString(true);
case kAccelerator:
return u"press |" + GetFullscreenAcceleratorString() + u"|";
default:
return u"";
}
}
std::u16string CreateInstructionText(UserGoal goal, Shortcut shortcut) {
return GetUserGoalText(goal) + u", " + GetShortcutText(shortcut);
}
std::u16string GetInstructionViewText() {
return static_cast<SubtleNotificationView*>(bubble_view_->GetView())
->GetInstructionTextForTest();
}
SubtleNotificationView* GetSubtleNotificationView() {
return static_cast<SubtleNotificationView*>(bubble_view_->GetView());
}
protected:
std::unique_ptr<ExclusiveAccessBubbleViews> bubble_view_;
};
class ExclusiveAccessBubbleViewsInstructionTextTest
: public ExclusiveAccessBubbleViewsTest,
public testing::WithParamInterface<InstructionTextTestCase> {
public:
ExclusiveAccessBubbleViewsInstructionTextTest() {
if (GetParam().enable_feature) {
scoped_feature_list_.InitAndEnableFeature(
features::kPressAndHoldEscToExitBrowserFullscreen);
} else {
scoped_feature_list_.InitAndDisableFeature(
features::kPressAndHoldEscToExitBrowserFullscreen);
}
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_P(ExclusiveAccessBubbleViewsInstructionTextTest, UpdateViewContent) {
const InstructionTextTestCase& test_case = GetParam();
UpdateExclusiveAccessBubbleType(test_case.type, /*has_download=*/false);
EXPECT_EQ(GetInstructionViewText(),
CreateInstructionText(test_case.goal, test_case.shortcut));
}
TEST_F(ExclusiveAccessBubbleViewsTest,
SubtleNotificationViewAccessibleProperties) {
ui::AXNodeData data;
GetSubtleNotificationView()->GetViewAccessibility().GetAccessibleNodeData(
&data);
EXPECT_EQ(data.role, ax::mojom::Role::kAlert);
EXPECT_EQ(GetSubtleNotificationView()->GetViewAccessibility().GetCachedRole(),
ax::mojom::Role::kAlert);
GetSubtleNotificationView()->UpdateContent(u"Sample |Accessible| Text");
data = ui::AXNodeData();
GetSubtleNotificationView()->GetViewAccessibility().GetAccessibleNodeData(
&data);
EXPECT_EQ(data.GetString16Attribute(ax::mojom::StringAttribute::kName),
u"Sample Accessible Text");
}
// Tests where the bubble is updated once with the specified type.
INSTANTIATE_TEST_SUITE_P(
/* no label */,
ExclusiveAccessBubbleViewsInstructionTextTest,
testing::ValuesIn<InstructionTextTestCase>({
{"tabFullscreen",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_EXIT_INSTRUCTION,
UserGoal::kExitFullscreen, Shortcut::kPressEsc, false},
{"tabFullscreenAndPointerLock",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_POINTERLOCK_EXIT_INSTRUCTION,
UserGoal::kExitFullscreen, Shortcut::kPressEsc, false},
{"pointerLock",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_POINTERLOCK_EXIT_INSTRUCTION,
UserGoal::kExitPointerLock, Shortcut::kPressEsc, false},
{"tabFullscreenAndKeyboardLock",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_KEYBOARD_LOCK_EXIT_INSTRUCTION,
UserGoal::kExitFullscreen, Shortcut::kPressAndHoldEsc, false},
{"browserFullscreen",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION,
UserGoal::kExitFullscreen, Shortcut::kAccelerator, false},
{"extensionInitiatedBrowserFullscreen",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_EXTENSION_FULLSCREEN_EXIT_INSTRUCTION,
UserGoal::kExitFullscreen, Shortcut::kAccelerator, false},
{"tabFullscreen_EnablePressAndHoldEsc",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_EXIT_INSTRUCTION,
UserGoal::kExitFullscreen, Shortcut::kPressEsc, true},
{"tabFullscreenAndPointerLock_EnablePressAndHoldEsc",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_POINTERLOCK_EXIT_INSTRUCTION,
UserGoal::kExitFullscreen, Shortcut::kPressEsc, true},
{"pointerLock_EnablePressAndHoldEsc",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_POINTERLOCK_EXIT_INSTRUCTION,
UserGoal::kExitPointerLock, Shortcut::kPressEsc, true},
{"tabFullscreenAndKeyboardLock_EnablePressAndHoldEsc",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_KEYBOARD_LOCK_EXIT_INSTRUCTION,
UserGoal::kExitFullscreen, Shortcut::kPressAndHoldEsc, true},
{"browserFullscreen_EnablePressAndHoldEsc",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION,
UserGoal::kExitFullscreen, Shortcut::kPressAndHoldEsc, true},
{"extensionInitiatedBrowserFullscreen_EnablePressAndHoldEsc",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_EXTENSION_FULLSCREEN_EXIT_INSTRUCTION,
UserGoal::kExitFullscreen, Shortcut::kPressAndHoldEsc, true},
}),
[](const testing::TestParamInfo<
ExclusiveAccessBubbleViewsInstructionTextTest::ParamType>& info) {
return info.param.test_name;
});
// Tests the creation of a has_download, non-overriding notification.
TEST_F(ExclusiveAccessBubbleViewsTest, CreateForDownload) {
ExclusiveAccessBubbleParams params{.type = EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE,
.has_download = true};
bubble_view_ = std::make_unique<ExclusiveAccessBubbleViews>(
browser_view(), params, base::NullCallback());
EXPECT_TRUE(base::StartsWith(
GetInstructionViewText(),
CreateInstructionText(UserGoal::kSeeDownload, Shortcut::kPressEsc)));
}
// Tests the updating of a has_download, non-overriding notification with a
// second one of the same.
TEST_F(ExclusiveAccessBubbleViewsTest, CreateForDownloadUpdateForDownload) {
ExclusiveAccessBubbleParams params{.type = EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE,
.has_download = true};
bubble_view_ = std::make_unique<ExclusiveAccessBubbleViews>(
browser_view(), params, base::NullCallback());
UpdateExclusiveAccessBubbleType(EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE,
/*has_download=*/true);
EXPECT_TRUE(base::StartsWith(
GetInstructionViewText(),
CreateInstructionText(UserGoal::kSeeDownload, Shortcut::kPressEsc)));
}
// Tests updating the bubble first with the type, then a second time for a
// download notification.
using ExclusiveAccessBubbleViewsTestWithDownload =
ExclusiveAccessBubbleViewsInstructionTextTest;
TEST_P(ExclusiveAccessBubbleViewsTestWithDownload,
UpdateViewContentThenDownload) {
const InstructionTextTestCase& test_case = GetParam();
UpdateExclusiveAccessBubbleType(test_case.type, /*has_download=*/false);
// Download notifications pass the type NONE.
UpdateExclusiveAccessBubbleType(EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE,
/*has_download=*/true);
EXPECT_EQ(GetInstructionViewText(),
CreateInstructionText(test_case.goal, test_case.shortcut));
}
// Tests the above but with the Update() calls coming in the other order.
TEST_P(ExclusiveAccessBubbleViewsTestWithDownload,
UpdateViewContentAfterDownload) {
const InstructionTextTestCase& test_case = GetParam();
// Update it for a download.
UpdateExclusiveAccessBubbleType(EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE,
/*has_download=*/true);
// A subsequent Update() call with the test-specified type.
UpdateExclusiveAccessBubbleType(test_case.type, /*has_download=*/false);
EXPECT_EQ(GetInstructionViewText(),
CreateInstructionText(test_case.goal, test_case.shortcut));
}
INSTANTIATE_TEST_SUITE_P(
/* no label */,
ExclusiveAccessBubbleViewsTestWithDownload,
testing::ValuesIn<InstructionTextTestCase>({
{"tabFullscreenSeeDownload",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_EXIT_INSTRUCTION,
UserGoal::kExitFullscreenAndSeeDownload, Shortcut::kPressEsc, false},
{"browserFullscreenSeeDownload",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION,
UserGoal::kExitFullscreenAndSeeDownload, Shortcut::kAccelerator,
false},
{"extensionInitiatedFullscreenSeeDownload",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_EXTENSION_FULLSCREEN_EXIT_INSTRUCTION,
UserGoal::kExitFullscreenAndSeeDownload, Shortcut::kAccelerator,
false},
{"tabFullscreenSeeDownload_EnablePressAndHoldEsc",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_EXIT_INSTRUCTION,
UserGoal::kExitFullscreenAndSeeDownload, Shortcut::kPressEsc, true},
{"browserFullscreenSeeDownload_EnablePressAndHoldEsc",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION,
UserGoal::kExitFullscreenAndSeeDownload, Shortcut::kPressAndHoldEsc,
true},
{"extensionInitiatedFullscreenSeeDownload_EnablePressAndHoldEsc",
EXCLUSIVE_ACCESS_BUBBLE_TYPE_EXTENSION_FULLSCREEN_EXIT_INSTRUCTION,
UserGoal::kExitFullscreenAndSeeDownload, Shortcut::kPressAndHoldEsc,
true},
}),
[](const testing::TestParamInfo<
ExclusiveAccessBubbleViewsTestWithDownload::ParamType>& info) {
return info.param.test_name;
});