capture-game: Implement the game capture mode notification view
This CL implements the notification view for the game dashboard initiated capture mode session which includes the 'Share to YouTube' and 'Delete' buttons. Demo: http://b/276982457#comment4 Fixed: b/276982457 Test: Added unit test + manual Change-Id: I0efaabd483323ca14379f5a05f7995bda2f785e6 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4548580 Reviewed-by: Ahmed Fakhry <afakhry@chromium.org> Commit-Queue: Michele Fan <michelefan@chromium.org> Cr-Commit-Position: refs/heads/main@{#1148128}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
d2b814cdcf
commit
836a63fa26
ash
@ -5571,6 +5571,9 @@ Here are some things you can try to get started.
|
||||
<message name="IDS_ASH_SCREEN_CAPTURE_SAVE_TO_DIALOG_TITLE" desc="The title of the folder selection dialog, where users can select a location to save their captured images and screen recordings.">
|
||||
Select a folder to save to
|
||||
</message>
|
||||
<message name="IDS_ASH_SCREEN_CAPTURE_SHARE_TO_YOUTUBE" desc="The share to YouTube button label for the screen capture notification.">
|
||||
Share to YouTube
|
||||
</message>
|
||||
<message name="IDS_ASH_SCREEN_CAPTURE_SHOW_CAMERA_USER_NUDGE" desc="The message shown in a toast widget to nudge the user and alert them to check out the new settings that allow them to show camera during video recording.">
|
||||
You can now record yourself and your screen at the same time
|
||||
</message>
|
||||
|
@ -0,0 +1 @@
|
||||
5e03816d5e97ed75908cffc0075b106c2e2415c4
|
@ -21,6 +21,7 @@
|
||||
#include "ash/shelf/shelf.h"
|
||||
#include "ash/shelf/shelf_layout_manager.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/strings/grit/ash_strings.h"
|
||||
#include "ash/wm/mru_window_tracker.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/functional/bind.h"
|
||||
@ -29,6 +30,8 @@
|
||||
#include "base/notreached.h"
|
||||
#include "base/task/single_thread_task_runner.h"
|
||||
#include "ui/aura/window_observer.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/message_center/public/cpp/notification.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
@ -239,6 +242,16 @@ class GameDashboardBehavior : public CaptureModeBehavior,
|
||||
pre_selected_window_->AddObserver(this);
|
||||
}
|
||||
|
||||
std::vector<message_center::ButtonInfo> GetNotificationButtonsInfo(
|
||||
bool for_video) const override {
|
||||
CHECK(for_video);
|
||||
|
||||
return {message_center::ButtonInfo{l10n_util::GetStringUTF16(
|
||||
IDS_ASH_SCREEN_CAPTURE_SHARE_TO_YOUTUBE)},
|
||||
message_center::ButtonInfo{l10n_util::GetStringUTF16(
|
||||
IDS_ASH_SCREEN_CAPTURE_BUTTON_DELETE)}};
|
||||
}
|
||||
|
||||
// aura::WindowObserver:
|
||||
void OnWindowDestroying(aura::Window* window) override {
|
||||
CHECK_EQ(window, pre_selected_window_);
|
||||
@ -384,6 +397,23 @@ const char* CaptureModeBehavior::GetClientMetricComponent() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::vector<message_center::ButtonInfo>
|
||||
CaptureModeBehavior::GetNotificationButtonsInfo(bool for_video) const {
|
||||
std::vector<message_center::ButtonInfo> buttons_info;
|
||||
|
||||
if (!for_video &&
|
||||
!Shell::Get()->session_controller()->IsUserSessionBlocked()) {
|
||||
message_center::ButtonInfo edit_button(
|
||||
l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_BUTTON_EDIT));
|
||||
buttons_info.push_back(edit_button);
|
||||
}
|
||||
message_center::ButtonInfo delete_button(
|
||||
l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_BUTTON_DELETE));
|
||||
buttons_info.push_back(delete_button);
|
||||
|
||||
return buttons_info;
|
||||
}
|
||||
|
||||
std::unique_ptr<CaptureModeBarView>
|
||||
CaptureModeBehavior::CreateCaptureModeBarView() {
|
||||
return std::make_unique<NormalCaptureBarView>(this);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "base/functional/callback_forward.h"
|
||||
#include "base/functional/callback_helpers.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
#include "ui/message_center/public/cpp/notification.h"
|
||||
|
||||
namespace aura {
|
||||
class Window;
|
||||
@ -92,6 +93,12 @@ class CaptureModeBehavior {
|
||||
// indicate the histogram is for a projector-initiated capture mode session.
|
||||
virtual const char* GetClientMetricComponent() const;
|
||||
|
||||
// Returns the client specific buttons info to be shown in the notification
|
||||
// view. The buttons info list may differ based on whether `for_video` is true
|
||||
// or not.
|
||||
virtual std::vector<message_center::ButtonInfo> GetNotificationButtonsInfo(
|
||||
bool for_video) const;
|
||||
|
||||
// Creates the capture mode bar view, which might look different depending on
|
||||
// the actual type of the behavior.
|
||||
virtual std::unique_ptr<CaptureModeBarView> CreateCaptureModeBarView();
|
||||
|
@ -132,7 +132,8 @@ enum ScreenshotNotificationButtonIndex {
|
||||
|
||||
// The video notification button index.
|
||||
enum VideoNotificationButtonIndex {
|
||||
BUTTON_DELETE_VIDEO = 0,
|
||||
BUTTON_SHARE_TO_YOUTUBE = 0,
|
||||
BUTTON_DELETE_VIDEO,
|
||||
};
|
||||
|
||||
// Returns the file extension for the given `recording_type` and the current
|
||||
@ -1399,7 +1400,10 @@ void CaptureModeController::OnImageFileSaved(
|
||||
DCHECK(png_bytes && png_bytes->size());
|
||||
const auto image = gfx::Image::CreateFrom1xPNGBytes(png_bytes);
|
||||
CopyImageToClipboard(image);
|
||||
ShowPreviewNotification(file_saved_path, image, CaptureModeType::kImage);
|
||||
// TODO(michelefan): Do not hard-code `BehaviorType::kDefault`. Screenshot
|
||||
// notification should be separated among different behaviors.
|
||||
ShowPreviewNotification(file_saved_path, image, CaptureModeType::kImage,
|
||||
GetBehavior(BehaviorType::kDefault));
|
||||
if (Shell::Get()->session_controller()->IsActiveUserSessionStarted())
|
||||
RecordSaveToLocation(GetSaveToOption(file_saved_path));
|
||||
// NOTE: Holding space `client` may be `nullptr` in tests.
|
||||
@ -1422,7 +1426,7 @@ void CaptureModeController::OnVideoFileSaved(
|
||||
if (behavior->ShouldShowPreviewNotification()) {
|
||||
ShowPreviewNotification(saved_video_file_path,
|
||||
gfx::Image(video_thumbnail),
|
||||
CaptureModeType::kVideo);
|
||||
CaptureModeType::kVideo, behavior);
|
||||
// NOTE: Holding space `client` may be `nullptr` in tests.
|
||||
if (auto* client = HoldingSpaceController::Get()->client()) {
|
||||
client->AddItemOfType(is_gif
|
||||
@ -1451,7 +1455,8 @@ void CaptureModeController::OnVideoFileSaved(
|
||||
void CaptureModeController::ShowPreviewNotification(
|
||||
const base::FilePath& screen_capture_path,
|
||||
const gfx::Image& preview_image,
|
||||
const CaptureModeType type) {
|
||||
const CaptureModeType type,
|
||||
const CaptureModeBehavior* behavior) {
|
||||
const bool for_video = type == CaptureModeType::kVideo;
|
||||
const int title_id = GetNotificationTitleIdForFile(screen_capture_path);
|
||||
const int message_id = for_video && low_disk_space_threshold_reached_
|
||||
@ -1459,13 +1464,7 @@ void CaptureModeController::ShowPreviewNotification(
|
||||
: IDS_ASH_SCREEN_CAPTURE_MESSAGE;
|
||||
|
||||
message_center::RichNotificationData optional_fields;
|
||||
message_center::ButtonInfo edit_button(
|
||||
l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_BUTTON_EDIT));
|
||||
if (!for_video && !Shell::Get()->session_controller()->IsUserSessionBlocked())
|
||||
optional_fields.buttons.push_back(edit_button);
|
||||
message_center::ButtonInfo delete_button(
|
||||
l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_BUTTON_DELETE));
|
||||
optional_fields.buttons.push_back(delete_button);
|
||||
optional_fields.buttons = behavior->GetNotificationButtonsInfo(for_video);
|
||||
|
||||
optional_fields.image = preview_image;
|
||||
optional_fields.image_path = screen_capture_path;
|
||||
@ -1491,12 +1490,20 @@ void CaptureModeController::HandleNotificationClicked(
|
||||
} else {
|
||||
const int button_index_value = button_index.value();
|
||||
if (type == CaptureModeType::kVideo) {
|
||||
DCHECK_EQ(button_index_value,
|
||||
VideoNotificationButtonIndex::BUTTON_DELETE_VIDEO);
|
||||
DeleteFileAsync(blocking_task_runner_, screen_capture_path,
|
||||
std::move(on_file_deleted_callback_for_test_));
|
||||
switch (button_index_value) {
|
||||
case VideoNotificationButtonIndex::BUTTON_SHARE_TO_YOUTUBE:
|
||||
OnShareToYouTubeButtonPressed();
|
||||
break;
|
||||
case VideoNotificationButtonIndex::BUTTON_DELETE_VIDEO:
|
||||
DeleteFileAsync(blocking_task_runner_, screen_capture_path,
|
||||
std::move(on_file_deleted_callback_for_test_));
|
||||
break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
DCHECK_EQ(type, CaptureModeType::kImage);
|
||||
CHECK_EQ(type, CaptureModeType::kImage);
|
||||
switch (button_index_value) {
|
||||
case ScreenshotNotificationButtonIndex::BUTTON_EDIT:
|
||||
delegate_->OpenScreenshotInImageEditor(screen_capture_path);
|
||||
|
@ -437,10 +437,12 @@ class ASH_EXPORT CaptureModeController
|
||||
const CaptureModeBehavior* behavior);
|
||||
|
||||
// Shows a preview notification of the newly taken screenshot or screen
|
||||
// recording.
|
||||
// recording. Customized notification view will be decided based on the
|
||||
// `behavior`.
|
||||
void ShowPreviewNotification(const base::FilePath& screen_capture_path,
|
||||
const gfx::Image& preview_image,
|
||||
const CaptureModeType type);
|
||||
const CaptureModeType type,
|
||||
const CaptureModeBehavior* behavior);
|
||||
void HandleNotificationClicked(const base::FilePath& screen_capture_path,
|
||||
const CaptureModeType type,
|
||||
absl::optional<int> button_index);
|
||||
|
@ -9,16 +9,31 @@
|
||||
#include "ash/capture_mode/capture_mode_session_focus_cycler.h"
|
||||
#include "ash/capture_mode/capture_mode_session_test_api.h"
|
||||
#include "ash/capture_mode/capture_mode_test_util.h"
|
||||
#include "ash/capture_mode/test_capture_mode_delegate.h"
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/public/cpp/capture_mode/capture_mode_test_api.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/strings/grit/ash_strings.h"
|
||||
#include "ash/style/pill_button.h"
|
||||
#include "ash/test/ash_test_base.h"
|
||||
#include "base/system/sys_info.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "chromeos/ui/base/window_properties.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
|
||||
namespace message_center {
|
||||
|
||||
bool operator==(const ButtonInfo& lhs, const ButtonInfo& rhs) {
|
||||
return std::tie(lhs.title, lhs.icon, lhs.placeholder, lhs.type) ==
|
||||
std::tie(rhs.title, rhs.icon, rhs.placeholder, rhs.type);
|
||||
}
|
||||
|
||||
} // namespace message_center
|
||||
|
||||
namespace ash {
|
||||
|
||||
using ButtonInfo = message_center::ButtonInfo;
|
||||
|
||||
class GameDashboardCaptureModeTest : public AshTestBase {
|
||||
public:
|
||||
GameDashboardCaptureModeTest()
|
||||
@ -153,4 +168,47 @@ TEST_F(GameDashboardCaptureModeTest, CaptureBarPosition) {
|
||||
window_bounds.bottom());
|
||||
}
|
||||
|
||||
// Tests that the game dashboard-initiated capture mode session shows the
|
||||
// notification view with 'Share to YouTube' button and 'delete' buttons.
|
||||
TEST_F(GameDashboardCaptureModeTest, NotificationView) {
|
||||
CaptureModeController* controller = StartGameCaptureModeSession();
|
||||
CaptureModeSession* session = controller->capture_mode_session();
|
||||
CaptureModeBehavior* active_behavior = session->active_behavior();
|
||||
ASSERT_TRUE(active_behavior);
|
||||
StartVideoRecordingImmediately();
|
||||
CaptureModeTestApi().FlushRecordingServiceForTesting();
|
||||
|
||||
auto* test_delegate =
|
||||
static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
|
||||
|
||||
// Request and wait for a video frame so that the recording service can use it
|
||||
// to create a video thumbnail.
|
||||
test_delegate->RequestAndWaitForVideoFrame();
|
||||
SkBitmap service_thumbnail =
|
||||
gfx::Image(test_delegate->GetVideoThumbnail()).AsBitmap();
|
||||
EXPECT_FALSE(service_thumbnail.drawsNothing());
|
||||
|
||||
controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
|
||||
EXPECT_FALSE(controller->is_recording_in_progress());
|
||||
CaptureNotificationWaiter().Wait();
|
||||
|
||||
const message_center::Notification* notification = GetPreviewNotification();
|
||||
EXPECT_TRUE(notification);
|
||||
EXPECT_FALSE(notification->image().IsEmpty());
|
||||
|
||||
std::vector<ButtonInfo> expected_buttons_info = {
|
||||
ButtonInfo(
|
||||
l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_SHARE_TO_YOUTUBE)),
|
||||
ButtonInfo(
|
||||
l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_BUTTON_DELETE))};
|
||||
auto actual_buttons_info =
|
||||
active_behavior->GetNotificationButtonsInfo(/*for_video=*/true);
|
||||
EXPECT_EQ(actual_buttons_info.size(), 2u);
|
||||
EXPECT_TRUE(actual_buttons_info == expected_buttons_info);
|
||||
|
||||
const int share_to_youtube_button = 0;
|
||||
ClickOnNotification(share_to_youtube_button);
|
||||
EXPECT_FALSE(GetPreviewNotification());
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
@ -46,6 +46,8 @@ namespace ash {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr char kScreenCaptureNotificationId[] = "capture_mode_notification";
|
||||
|
||||
// Dispatch the simulated virtual key event to the WindowEventDispatcher.
|
||||
void DispatchVKEvent(ui::test::EventGenerator* event_generator,
|
||||
bool is_press,
|
||||
@ -337,6 +339,23 @@ IconButton* GetCloseButton() {
|
||||
return GetCaptureModeBarView()->close_button();
|
||||
}
|
||||
|
||||
const message_center::Notification* GetPreviewNotification() {
|
||||
const message_center::NotificationList::Notifications notifications =
|
||||
message_center::MessageCenter::Get()->GetVisibleNotifications();
|
||||
for (const auto* notification : notifications) {
|
||||
if (notification->id() == kScreenCaptureNotificationId) {
|
||||
return notification;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ClickOnNotification(absl::optional<int> button_index) {
|
||||
const message_center::Notification* notification = GetPreviewNotification();
|
||||
CHECK(notification);
|
||||
notification->delegate()->Click(button_index, absl::nullopt);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// ProjectorCaptureModeIntegrationHelper:
|
||||
|
||||
@ -404,4 +423,26 @@ void ViewVisibilityChangeWaiter::OnViewVisibilityChanged(
|
||||
wait_loop_.Quit();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// CaptureNotificationWaiter:
|
||||
|
||||
CaptureNotificationWaiter::CaptureNotificationWaiter() {
|
||||
message_center::MessageCenter::Get()->AddObserver(this);
|
||||
}
|
||||
|
||||
CaptureNotificationWaiter::~CaptureNotificationWaiter() {
|
||||
message_center::MessageCenter::Get()->RemoveObserver(this);
|
||||
}
|
||||
|
||||
void CaptureNotificationWaiter::Wait() {
|
||||
run_loop_.Run();
|
||||
}
|
||||
|
||||
void CaptureNotificationWaiter::OnNotificationAdded(
|
||||
const std::string& notification_id) {
|
||||
if (notification_id == kScreenCaptureNotificationId) {
|
||||
run_loop_.Quit();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
@ -15,6 +15,9 @@
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "ui/events/event_constants.h"
|
||||
#include "ui/events/keycodes/keyboard_codes_posix.h"
|
||||
#include "ui/message_center/message_center.h"
|
||||
#include "ui/message_center/message_center_observer.h"
|
||||
#include "ui/message_center/public/cpp/notification.h"
|
||||
#include "ui/views/view.h"
|
||||
#include "ui/views/view_observer.h"
|
||||
|
||||
@ -143,6 +146,12 @@ PillButton* GetStartRecordingButton();
|
||||
IconButton* GetSettingsButton();
|
||||
IconButton* GetCloseButton();
|
||||
|
||||
// Returns the capture mode related notifications from the message center.
|
||||
const message_center::Notification* GetPreviewNotification();
|
||||
|
||||
// Clicks on the area in the notification specified by the `button_index`.
|
||||
void ClickOnNotification(absl::optional<int> button_index);
|
||||
|
||||
// Defines a helper class to allow setting up and testing the Projector feature
|
||||
// in multiple test fixtures. Note that this helper initializes the Projector-
|
||||
// related features in its constructor, so test fixtures that use this should
|
||||
@ -194,6 +203,21 @@ class ViewVisibilityChangeWaiter : public views::ViewObserver {
|
||||
base::RunLoop wait_loop_;
|
||||
};
|
||||
|
||||
// Defines a waiter to observe the notification changes.
|
||||
class CaptureNotificationWaiter : public message_center::MessageCenterObserver {
|
||||
public:
|
||||
CaptureNotificationWaiter();
|
||||
~CaptureNotificationWaiter() override;
|
||||
|
||||
void Wait();
|
||||
|
||||
// message_center::MessageCenterObserver:
|
||||
void OnNotificationAdded(const std::string& notification_id) override;
|
||||
|
||||
private:
|
||||
base::RunLoop run_loop_;
|
||||
};
|
||||
|
||||
} // namespace ash
|
||||
|
||||
#endif // ASH_CAPTURE_MODE_CAPTURE_MODE_TEST_UTIL_H_
|
||||
|
@ -131,7 +131,6 @@ using ::ui::mojom::CursorType;
|
||||
|
||||
constexpr char kEndRecordingReasonInClamshellHistogramName[] =
|
||||
"Ash.CaptureModeController.EndRecordingReason.ClamshellMode";
|
||||
constexpr char kScreenCaptureNotificationId[] = "capture_mode_notification";
|
||||
|
||||
// Returns true if the software-composited cursor is enabled.
|
||||
bool IsCursorCompositingEnabled() {
|
||||
@ -141,23 +140,6 @@ bool IsCursorCompositingEnabled() {
|
||||
->is_cursor_compositing_enabled();
|
||||
}
|
||||
|
||||
const message_center::Notification* GetPreviewNotification() {
|
||||
const message_center::NotificationList::Notifications notifications =
|
||||
message_center::MessageCenter::Get()->GetVisibleNotifications();
|
||||
for (const auto* notification : notifications) {
|
||||
if (notification->id() == kScreenCaptureNotificationId) {
|
||||
return notification;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ClickNotification(absl::optional<int> button_index) {
|
||||
const message_center::Notification* notification = GetPreviewNotification();
|
||||
DCHECK(notification);
|
||||
notification->delegate()->Click(button_index, absl::nullopt);
|
||||
}
|
||||
|
||||
// Sets up a callback that will be triggered when a capture file (image or
|
||||
// video) is deleted as a result of a user action. The callback will verify the
|
||||
// successful deletion of the file, and will quit the given `loop`.
|
||||
@ -411,28 +393,6 @@ class CaptureSessionWidgetClosed {
|
||||
base::WeakPtr<views::Widget> widget_;
|
||||
};
|
||||
|
||||
class CaptureNotificationWaiter : public message_center::MessageCenterObserver {
|
||||
public:
|
||||
CaptureNotificationWaiter() {
|
||||
message_center::MessageCenter::Get()->AddObserver(this);
|
||||
}
|
||||
~CaptureNotificationWaiter() override {
|
||||
message_center::MessageCenter::Get()->RemoveObserver(this);
|
||||
}
|
||||
|
||||
void Wait() { run_loop_.Run(); }
|
||||
|
||||
// message_center::MessageCenterObserver:
|
||||
void OnNotificationAdded(const std::string& notification_id) override {
|
||||
if (notification_id == kScreenCaptureNotificationId) {
|
||||
run_loop_.Quit();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
base::RunLoop run_loop_;
|
||||
};
|
||||
|
||||
TEST_F(CaptureModeTest, StartStop) {
|
||||
auto* controller = CaptureModeController::Get();
|
||||
controller->Start(CaptureModeEntryType::kQuickSettings);
|
||||
@ -4288,7 +4248,7 @@ TEST_F(CaptureModeTest, QuickActionHistograms) {
|
||||
base::RunLoop loop;
|
||||
SetUpFileDeletionVerifier(&loop);
|
||||
const int delete_button = 1;
|
||||
ClickNotification(delete_button);
|
||||
ClickOnNotification(delete_button);
|
||||
loop.Run();
|
||||
EXPECT_FALSE(GetPreviewNotification());
|
||||
histogram_tester.ExpectBucketCount(kQuickActionHistogramName,
|
||||
@ -4302,7 +4262,7 @@ TEST_F(CaptureModeTest, QuickActionHistograms) {
|
||||
waiter.Wait();
|
||||
}
|
||||
// Click on the notification body. This should take us to the files app.
|
||||
ClickNotification(absl::nullopt);
|
||||
ClickOnNotification(absl::nullopt);
|
||||
EXPECT_FALSE(GetPreviewNotification());
|
||||
histogram_tester.ExpectBucketCount(kQuickActionHistogramName,
|
||||
CaptureQuickAction::kFiles, 1);
|
||||
@ -4317,7 +4277,7 @@ TEST_F(CaptureModeTest, QuickActionHistograms) {
|
||||
}
|
||||
const int edit_button = 0;
|
||||
// Verify clicking edit on screenshot notification.
|
||||
ClickNotification(edit_button);
|
||||
ClickOnNotification(edit_button);
|
||||
EXPECT_FALSE(GetPreviewNotification());
|
||||
histogram_tester.ExpectBucketCount(kQuickActionHistogramName,
|
||||
CaptureQuickAction::kBacklight, 1);
|
||||
|
Reference in New Issue
Block a user