SC Education: Add Arm 3 and fix tests
Add Arm 3 for Screen Capture Education, a system nudge that is anchored to the unified system tray button and does not contain a keyboard shortcut view. Also fixes the behaviour of some unit tests. Bug: b/302368917 Test: manual + unit Change-Id: I8100e9d0254ba620e29dff5d61f37887a4ffa044 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5059882 Commit-Queue: Elijah Hewer <hewer@chromium.org> Reviewed-by: Michele Fan <michelefan@chromium.org> Reviewed-by: Ahmed Fakhry <afakhry@chromium.org> Reviewed-by: Alex Newcomer <newcomer@chromium.org> Cr-Commit-Position: refs/heads/main@{#1230970}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
515a00238e
commit
7e2d446210
ash
ash_strings.grd
ash_strings_grd
capture_mode
capture_mode_controller.cccapture_mode_education_controller.cccapture_mode_education_controller.hcapture_mode_education_controller_unittest.cc
constants
tools/metrics/histograms/metadata/ash
@ -6136,6 +6136,9 @@ Here are some things you can try to get started.
|
||||
<message name="IDS_ASH_SCREEN_CAPTURE_EDUCATION_TUTORIAL_TITLE" desc="The title of the tutorial dialog for Screen Capture Education (Arm 2).">
|
||||
Press the screenshot shortcut
|
||||
</message>
|
||||
<message name="IDS_ASH_SCREEN_CAPTURE_EDUCATION_SETTINGS_NUDGE_LABEL" desc="The label of the Screen Capture Education settings nudge (Arm 3) for using the quick settings menu.">
|
||||
Use the screen capture tool in quick settings to take screenshots
|
||||
</message>
|
||||
|
||||
<!-- Snap Group -->
|
||||
<message name="IDS_ASH_SNAP_GROUP_CLICK_TO_LOCK_WINDOWS" desc="Click to lock the windows.">
|
||||
|
@ -0,0 +1 @@
|
||||
8610c616aa79506fc599fed631f635e5d67ec039
|
@ -1112,6 +1112,10 @@ void CaptureModeController::StartInternal(
|
||||
},
|
||||
weak_ptr_factory_.GetWeakPtr(), std::move(callback), IsActive()));
|
||||
|
||||
if (education_controller_) {
|
||||
education_controller_->CloseAllEducationNudgesAndTutorials();
|
||||
}
|
||||
|
||||
if (capture_mode_session_ || pending_dlp_check_) {
|
||||
return;
|
||||
}
|
||||
|
@ -14,11 +14,15 @@
|
||||
#include "ash/public/cpp/system/anchored_nudge_data.h"
|
||||
#include "ash/public/cpp/system/anchored_nudge_manager.h"
|
||||
#include "ash/resources/vector_icons/vector_icons.h"
|
||||
#include "ash/root_window_controller.h"
|
||||
#include "ash/shelf/shelf.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/strings/grit/ash_strings.h"
|
||||
#include "ash/style/ash_color_id.h"
|
||||
#include "ash/style/keyboard_shortcut_view.h"
|
||||
#include "ash/style/system_dialog_delegate_view.h"
|
||||
#include "ash/system/status_area_widget.h"
|
||||
#include "ash/system/unified/unified_system_tray.h"
|
||||
#include "components/prefs/pref_registry_simple.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
@ -59,6 +63,7 @@ base::Time GetTime() {
|
||||
return g_clock_override ? g_clock_override->Now() : base::Time::Now();
|
||||
}
|
||||
|
||||
// Creates nudge data common to Arms 1 and 2.
|
||||
AnchoredNudgeData CreateBaseNudgeData(NudgeCatalogName catalog_name) {
|
||||
AnchoredNudgeData nudge_data(
|
||||
kCaptureModeNudgeId, catalog_name,
|
||||
@ -171,10 +176,10 @@ bool CaptureModeEducationController::IsArm2ShortcutTutorialEnabled() {
|
||||
}
|
||||
|
||||
// static
|
||||
bool CaptureModeEducationController::IsArm3SettingsNudgeEnabled() {
|
||||
bool CaptureModeEducationController::IsArm3QuickSettingsNudgeEnabled() {
|
||||
return features::IsCaptureModeEducationEnabled() &&
|
||||
features::kCaptureModeEducationParam.Get() ==
|
||||
features::CaptureModeEducationParam::kSettingsNudge;
|
||||
features::CaptureModeEducationParam::kQuickSettingsNudge;
|
||||
}
|
||||
|
||||
void CaptureModeEducationController::MaybeShowEducation() {
|
||||
@ -208,9 +213,7 @@ void CaptureModeEducationController::MaybeShowEducation() {
|
||||
pref_service->SetTime(prefs::kCaptureModeEducationLastShown, now);
|
||||
}
|
||||
|
||||
// Close any existing forms of education.
|
||||
AnchoredNudgeManager::Get()->Cancel(kCaptureModeNudgeId);
|
||||
tutorial_widget_.reset();
|
||||
CloseAllEducationNudgesAndTutorials();
|
||||
|
||||
if (IsArm1ShortcutNudgeEnabled()) {
|
||||
ShowShortcutNudge();
|
||||
@ -219,6 +222,15 @@ void CaptureModeEducationController::MaybeShowEducation() {
|
||||
if (IsArm2ShortcutTutorialEnabled()) {
|
||||
ShowTutorialNudge();
|
||||
}
|
||||
|
||||
if (IsArm3QuickSettingsNudgeEnabled()) {
|
||||
ShowQuickSettingsNudge();
|
||||
}
|
||||
}
|
||||
|
||||
void CaptureModeEducationController::CloseAllEducationNudgesAndTutorials() {
|
||||
AnchoredNudgeManager::Get()->Cancel(kCaptureModeNudgeId);
|
||||
tutorial_widget_.reset();
|
||||
}
|
||||
|
||||
// static
|
||||
@ -228,10 +240,6 @@ void CaptureModeEducationController::SetOverrideClockForTesting(
|
||||
}
|
||||
|
||||
void CaptureModeEducationController::ShowShortcutNudge() {
|
||||
// Close the nudge if it already exists.
|
||||
auto* nudge_manager = AnchoredNudgeManager::Get();
|
||||
nudge_manager->Cancel(kCaptureModeNudgeId);
|
||||
|
||||
AnchoredNudgeData nudge_data =
|
||||
CreateBaseNudgeData(NudgeCatalogName::kCaptureModeEducationShortcutNudge);
|
||||
|
||||
@ -251,6 +259,24 @@ void CaptureModeEducationController::ShowTutorialNudge() {
|
||||
AnchoredNudgeManager::Get()->Show(nudge_data);
|
||||
}
|
||||
|
||||
void CaptureModeEducationController::ShowQuickSettingsNudge() {
|
||||
AnchoredNudgeData nudge_data(
|
||||
kCaptureModeNudgeId,
|
||||
NudgeCatalogName::kCaptureModeEducationQuickSettingsNudge,
|
||||
l10n_util::GetStringUTF16(
|
||||
IDS_ASH_SCREEN_CAPTURE_EDUCATION_SETTINGS_NUDGE_LABEL));
|
||||
|
||||
nudge_data.image_model = ui::ImageModel::FromVectorIcon(
|
||||
kCaptureModeIcon, kColorAshIconColorPrimary, kShortcutIconSize);
|
||||
nudge_data.SetAnchorView(
|
||||
RootWindowController::ForWindow(Shell::GetRootWindowForNewWindows())
|
||||
->shelf()
|
||||
->status_area_widget()
|
||||
->unified_system_tray());
|
||||
|
||||
AnchoredNudgeManager::Get()->Show(nudge_data);
|
||||
}
|
||||
|
||||
void CaptureModeEducationController::CreateAndShowTutorialDialog() {
|
||||
// As we are creating a system modal dialog, it will automatically be parented
|
||||
// to `kShellWindowId_SystemModalContainer`.
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define ASH_CAPTURE_MODE_CAPTURE_MODE_EDUCATION_CONTROLLER_H_
|
||||
|
||||
#include "ash/ash_export.h"
|
||||
#include "base/gtest_prod_util.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/time/clock.h"
|
||||
#include "ui/views/widget/unique_widget_ptr.h"
|
||||
@ -24,7 +23,7 @@ namespace ash {
|
||||
// - Arm 2: Shortcut Tutorial. Similar to Arm 1, but the nudge also appears
|
||||
// with a button that opens a new popup, showing the keyboard layout of where
|
||||
// the shortcut keys are found.
|
||||
// - Arm 3: Settings Nudge. A system nudge anchored to the quick settings
|
||||
// - Arm 3: Quick Settings Nudge. A system nudge anchored to the quick settings
|
||||
// button in the shelf, with text alerting users to the Screen Capture tile
|
||||
// in the quick settings menu.
|
||||
class ASH_EXPORT CaptureModeEducationController {
|
||||
@ -48,14 +47,17 @@ class ASH_EXPORT CaptureModeEducationController {
|
||||
static bool IsArm2ShortcutTutorialEnabled();
|
||||
|
||||
// Returns true if the feature flag 'kCaptureModeEducation' is enabled and
|
||||
// the associated param is 'kSettingsNudge';
|
||||
static bool IsArm3SettingsNudgeEnabled();
|
||||
// the associated param is 'kQuickSettingsNudge';
|
||||
static bool IsArm3QuickSettingsNudgeEnabled();
|
||||
|
||||
// If a form of user education has already been shown 3 times or once in the
|
||||
// past 24 hours, returns. Otherwise, shows the appropriate form of user
|
||||
// education based on the enabled arm/feature param.
|
||||
void MaybeShowEducation();
|
||||
|
||||
// Closes any Screen Capture nudges or tutorials that may be open.
|
||||
void CloseAllEducationNudgesAndTutorials();
|
||||
|
||||
views::Widget* tutorial_widget_for_test() { return tutorial_widget_.get(); }
|
||||
|
||||
private:
|
||||
@ -72,6 +74,11 @@ class ASH_EXPORT CaptureModeEducationController {
|
||||
// take a screenshot, with a button to open a new tutorial widget.
|
||||
void ShowTutorialNudge();
|
||||
|
||||
// Shows Arm 3, a system nudge anchored to the unified system tray button,
|
||||
// indicating the location of the screen capture tool in the quick settings
|
||||
// menu.
|
||||
void ShowQuickSettingsNudge();
|
||||
|
||||
// Creates and shows the system dialog displaying the keyboard shortcut and
|
||||
// illustration for taking a screenshot.
|
||||
void CreateAndShowTutorialDialog();
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "ash/constants/ash_pref_names.h"
|
||||
#include "ash/constants/notifier_catalogs.h"
|
||||
#include "ash/public/cpp/ash_view_ids.h"
|
||||
#include "ash/root_window_controller.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/style/keyboard_shortcut_view.h"
|
||||
#include "ash/system/toast/anchored_nudge.h"
|
||||
@ -37,6 +38,7 @@ constexpr char kNudgeTimeToActionWithinSession[] =
|
||||
"Ash.NotifierFramework.Nudge.TimeToAction.WithinSession";
|
||||
|
||||
constexpr float kKeyboardImageWidth = 448;
|
||||
constexpr int kNudgeWorkAreaSpacing = 8;
|
||||
|
||||
PrefService* GetPrefService() {
|
||||
return Shell::Get()->session_controller()->GetActivePrefService();
|
||||
@ -71,9 +73,13 @@ class CaptureModeEducationControllerTest : public AshTestBase {
|
||||
CaptureModeEducationController::SetOverrideClockForTesting(test_clock);
|
||||
}
|
||||
|
||||
void ActivateNudgeAndCheckVisibility() {
|
||||
// By default, attempts to use the Windows Snipping Tool (capture bar)
|
||||
// shortcut to activate the nudge.
|
||||
void ActivateNudgeAndCheckVisibility(ui::KeyboardCode key_code = ui::VKEY_S,
|
||||
int flags = ui::EF_COMMAND_DOWN |
|
||||
ui::EF_SHIFT_DOWN) {
|
||||
// Attempt to use the Windows Snipping Tool (capture bar) shortcut.
|
||||
PressAndReleaseKey(ui::VKEY_S, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN);
|
||||
PressAndReleaseKey(key_code, flags);
|
||||
|
||||
// Get the list of visible nudges from the nudge manager and make sure our
|
||||
// education nudge is in the list and visible.
|
||||
@ -84,6 +90,32 @@ class CaptureModeEducationControllerTest : public AshTestBase {
|
||||
EXPECT_TRUE(nudge->GetVisible());
|
||||
}
|
||||
|
||||
// Starts a capture session using the screenshort shortcut, and verifies that
|
||||
// the nudge and tutorial are both closed. Stops the session afterwards.
|
||||
void StartSessionAndCheckEducationClosed() {
|
||||
// Use the screenshot shortcut to start a capture session.
|
||||
PressAndReleaseKey(ui::VKEY_MEDIA_LAUNCH_APP1,
|
||||
ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
|
||||
|
||||
auto* capture_mode_controller = CaptureModeController::Get();
|
||||
ASSERT_TRUE(capture_mode_controller->IsActive());
|
||||
|
||||
// Get the list of visible nudges from the nudge manager and make sure our
|
||||
// education nudge is no longer in the list.
|
||||
const AnchoredNudge* nudge =
|
||||
Shell::Get()->anchored_nudge_manager()->GetNudgeIfShown(
|
||||
kCaptureModeNudgeId);
|
||||
EXPECT_FALSE(nudge);
|
||||
|
||||
// The tutorial should also be closed.
|
||||
EXPECT_FALSE(capture_mode_controller->education_controller()
|
||||
->tutorial_widget_for_test());
|
||||
|
||||
// Stop the session in case we start a new one later.
|
||||
capture_mode_controller->Stop();
|
||||
ASSERT_FALSE(capture_mode_controller->IsActive());
|
||||
}
|
||||
|
||||
// Skip the 3 times/24 hours show limit for testing.
|
||||
void SkipNudgePrefs() {
|
||||
CaptureModeController::Get()->education_controller()->skip_prefs_for_test_ =
|
||||
@ -115,7 +147,7 @@ TEST_F(CaptureModeEducationControllerTest, NudgeAppearsOnAcceleratorPressed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ActivateNudgeAndCheckVisibility();
|
||||
ActivateNudgeAndCheckVisibility(tracker_data.key_code, tracker_data.flags);
|
||||
|
||||
// Close nudge to get ready for the next input.
|
||||
CancelNudge(kCaptureModeNudgeId);
|
||||
@ -135,7 +167,7 @@ class CaptureModeEducationShortcutNudgeTest
|
||||
~CaptureModeEducationShortcutNudgeTest() override = default;
|
||||
};
|
||||
|
||||
TEST_F(CaptureModeEducationShortcutNudgeTest, CorrectStyling) {
|
||||
TEST_F(CaptureModeEducationShortcutNudgeTest, KeyboardShortcutVisible) {
|
||||
base::SimpleTestClock test_clock;
|
||||
CaptureModeEducationControllerTest::SetOverrideClock(&test_clock);
|
||||
|
||||
@ -160,6 +192,8 @@ TEST_F(CaptureModeEducationShortcutNudgeTest, CorrectStyling) {
|
||||
ASSERT_TRUE(shortcut_view);
|
||||
EXPECT_TRUE(shortcut_view->GetVisible());
|
||||
|
||||
StartSessionAndCheckEducationClosed();
|
||||
|
||||
CaptureModeEducationControllerTest::SetOverrideClock(nullptr);
|
||||
}
|
||||
|
||||
@ -331,7 +365,7 @@ class CaptureModeEducationShortcutTutorialTest
|
||||
~CaptureModeEducationShortcutTutorialTest() override = default;
|
||||
};
|
||||
|
||||
TEST_F(CaptureModeEducationShortcutTutorialTest, DialogShowsOnButtonPressed) {
|
||||
TEST_F(CaptureModeEducationShortcutTutorialTest, DialogOpensAndCloses) {
|
||||
base::SimpleTestClock test_clock;
|
||||
CaptureModeEducationControllerTest::SetOverrideClock(&test_clock);
|
||||
|
||||
@ -360,6 +394,60 @@ TEST_F(CaptureModeEducationShortcutTutorialTest, DialogShowsOnButtonPressed) {
|
||||
VIEW_ID_SCREEN_CAPTURE_EDUCATION_KEYBOARD_IMAGE);
|
||||
ASSERT_TRUE(image_view);
|
||||
EXPECT_EQ(kKeyboardImageWidth, image_view->width());
|
||||
|
||||
StartSessionAndCheckEducationClosed();
|
||||
}
|
||||
|
||||
// Test fixture to verify the behaviour of Arm 3, the settings nudge.
|
||||
class CaptureModeEducationQuickSettingsNudgeTest
|
||||
: public CaptureModeEducationControllerTest {
|
||||
public:
|
||||
CaptureModeEducationQuickSettingsNudgeTest()
|
||||
: CaptureModeEducationControllerTest("QuickSettingsNudge") {}
|
||||
CaptureModeEducationQuickSettingsNudgeTest(
|
||||
const CaptureModeEducationQuickSettingsNudgeTest&) = delete;
|
||||
CaptureModeEducationQuickSettingsNudgeTest& operator=(
|
||||
const CaptureModeEducationQuickSettingsNudgeTest&) = delete;
|
||||
~CaptureModeEducationQuickSettingsNudgeTest() override = default;
|
||||
};
|
||||
|
||||
TEST_F(CaptureModeEducationQuickSettingsNudgeTest, NudgeLocation) {
|
||||
UpdateDisplay("800x600");
|
||||
base::SimpleTestClock test_clock;
|
||||
CaptureModeEducationControllerTest::SetOverrideClock(&test_clock);
|
||||
|
||||
// Advance clock so we aren't at zero time.
|
||||
test_clock.Advance(base::Hours(25));
|
||||
|
||||
// Attempt to use the Windows Snipping Tool (capture bar) shortcut.
|
||||
PressAndReleaseKey(ui::VKEY_S, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN);
|
||||
|
||||
// Get the list of visible nudges from the nudge manager and make sure our
|
||||
// education nudge is in the list and visible.
|
||||
AnchoredNudge* nudge =
|
||||
Shell::Get()->anchored_nudge_manager()->GetNudgeIfShown(
|
||||
kCaptureModeNudgeId);
|
||||
ASSERT_TRUE(nudge);
|
||||
EXPECT_TRUE(nudge->GetVisible());
|
||||
|
||||
// Test the shelf in horizontal (bottom) alignment.
|
||||
ASSERT_TRUE(Shell::GetPrimaryRootWindowController()
|
||||
->shelf()
|
||||
->IsHorizontalAlignment());
|
||||
|
||||
// The nudge should appear on the bottom right side of the screen. Compare the
|
||||
// positions of the bottom right corners of the nudge and the work area.
|
||||
const auto nudge_corner = nudge->GetBoundsInScreen().bottom_right();
|
||||
auto work_area_corner =
|
||||
nudge->GetWidget()->GetWorkAreaBoundsInScreen().bottom_right();
|
||||
EXPECT_EQ(work_area_corner.x() - kNudgeWorkAreaSpacing, nudge_corner.x());
|
||||
EXPECT_EQ(work_area_corner.y() - kNudgeWorkAreaSpacing, nudge_corner.y());
|
||||
|
||||
StartSessionAndCheckEducationClosed();
|
||||
|
||||
// TODO(hewer): Test shelf in vertical positions.
|
||||
|
||||
CaptureModeEducationControllerTest::SetOverrideClock(nullptr);
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
@ -387,7 +387,7 @@ constexpr base::FeatureParam<CaptureModeEducationParam>::Option
|
||||
capture_mode_education_type_options[] = {
|
||||
{CaptureModeEducationParam::kShortcutNudge, "ShortcutNudge"},
|
||||
{CaptureModeEducationParam::kShortcutTutorial, "ShortcutTutorial"},
|
||||
{CaptureModeEducationParam::kSettingsNudge, "SettingsNudge"}};
|
||||
{CaptureModeEducationParam::kQuickSettingsNudge, "QuickSettingsNudge"}};
|
||||
const base::FeatureParam<CaptureModeEducationParam> kCaptureModeEducationParam{
|
||||
&kCaptureModeEducation, "CaptureModeEducationParam",
|
||||
CaptureModeEducationParam::kShortcutNudge,
|
||||
|
@ -108,7 +108,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kCaptureModeEducation);
|
||||
enum class CaptureModeEducationParam {
|
||||
kShortcutNudge,
|
||||
kShortcutTutorial,
|
||||
kSettingsNudge
|
||||
kQuickSettingsNudge
|
||||
};
|
||||
COMPONENT_EXPORT(ASH_CONSTANTS)
|
||||
extern const base::FeatureParam<CaptureModeEducationParam>
|
||||
|
@ -226,7 +226,8 @@ enum class NudgeCatalogName {
|
||||
kMultitaskMenuTablet = 21,
|
||||
kCaptureModeEducationShortcutNudge = 22,
|
||||
kCaptureModeEducationShortcutTutorial = 23,
|
||||
kMaxValue = kCaptureModeEducationShortcutTutorial
|
||||
kCaptureModeEducationQuickSettingsNudge = 24,
|
||||
kMaxValue = kCaptureModeEducationQuickSettingsNudge
|
||||
};
|
||||
|
||||
// A living catalog that registers toasts.
|
||||
|
@ -1255,6 +1255,7 @@ chromium-metrics-reviews@google.com.
|
||||
<int value="21" label="Multitask Menu Tablet"/>
|
||||
<int value="22" label="Capture Mode Education Shortcut Nudge"/>
|
||||
<int value="23" label="Capture Mode Education Shortcut Tutorial"/>
|
||||
<int value="24" label="Capture Mode Education Quick Settings Nudge"/>
|
||||
</enum>
|
||||
|
||||
<enum name="OnDeviceToServerSpeechRecognitionFallbackReason">
|
||||
|
Reference in New Issue
Block a user