Commit 4312a7a8 authored by Andrew Xu's avatar Andrew Xu Committed by Chromium LUCI CQ

[Multipaste] Select Item asynchronously after the menu shows

After showing the multipaste menu, the first menu item should be
selected. Now the item is selected in the synchronous way. However,
the synthesized mouse event may cancel the selection. It can happen
when launching the multipaste menu from a context menu. To solve
this problem, this CL selects the item asynchronously after the menu
shows. In addition, it also adapts the test code to this change.

Bug: 1164604
Change-Id: I59e141462c2968e0a4271b33f5a4107ee01f6298
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2619079Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarDavid Black <dmblack@google.com>
Commit-Queue: Andrew Xu <andrewxu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#842244}
parent cecc091b
...@@ -260,9 +260,25 @@ void ClipboardHistoryControllerImpl::ShowMenu( ...@@ -260,9 +260,25 @@ void ClipboardHistoryControllerImpl::ShowMenu(
accelerator_target_->OnMenuShown(); accelerator_target_->OnMenuShown();
// The first menu item should be selected as default after the clipboard // The first menu item should be selected as default after the clipboard
// history menu shows. // history menu shows. Note that the menu item is selected asynchronously
context_menu_->SelectMenuItemWithCommandId( // to avoid the interference from synthesized mouse events.
menu_task_timer_.Start(
FROM_HERE, base::TimeDelta(),
base::BindOnce(
[](const base::WeakPtr<ClipboardHistoryControllerImpl>&
controller_weak_ptr) {
if (!controller_weak_ptr)
return;
controller_weak_ptr->context_menu_->SelectMenuItemWithCommandId(
ClipboardHistoryUtil::kFirstItemCommandId); ClipboardHistoryUtil::kFirstItemCommandId);
if (controller_weak_ptr->initial_item_selected_callback_for_test_) {
controller_weak_ptr->initial_item_selected_callback_for_test_
.Run();
}
},
weak_ptr_factory_.GetWeakPtr()));
for (auto& observer : observers_) for (auto& observer : observers_)
observer.OnClipboardHistoryMenuShown(); observer.OnClipboardHistoryMenuShown();
} }
...@@ -567,8 +583,9 @@ void ClipboardHistoryControllerImpl::OnMenuClosed() { ...@@ -567,8 +583,9 @@ void ClipboardHistoryControllerImpl::OnMenuClosed() {
// Reset `context_menu_` in the asynchronous way. Because the menu may be // Reset `context_menu_` in the asynchronous way. Because the menu may be
// accessed after `OnMenuClosed()` is called. // accessed after `OnMenuClosed()` is called.
base::SequencedTaskRunnerHandle::Get()->PostTask( menu_task_timer_.Start(
FROM_HERE, base::BindOnce( FROM_HERE, base::TimeDelta(),
base::BindOnce(
[](const base::WeakPtr<ClipboardHistoryControllerImpl>& [](const base::WeakPtr<ClipboardHistoryControllerImpl>&
controller_weak_ptr) { controller_weak_ptr) {
if (controller_weak_ptr) if (controller_weak_ptr)
......
...@@ -12,9 +12,11 @@ ...@@ -12,9 +12,11 @@
#include "ash/clipboard/clipboard_history.h" #include "ash/clipboard/clipboard_history.h"
#include "ash/clipboard/clipboard_history_item.h" #include "ash/clipboard/clipboard_history_item.h"
#include "ash/public/cpp/clipboard_history_controller.h" #include "ash/public/cpp/clipboard_history_controller.h"
#include "base/callback.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/timer/timer.h"
namespace gfx { namespace gfx {
class Rect; class Rect;
...@@ -71,6 +73,11 @@ class ASH_EXPORT ClipboardHistoryControllerImpl ...@@ -71,6 +73,11 @@ class ASH_EXPORT ClipboardHistoryControllerImpl
return context_menu_.get(); return context_menu_.get();
} }
void set_initial_item_selected_callback_for_test(
base::RepeatingClosure new_callback) {
initial_item_selected_callback_for_test_ = new_callback;
}
private: private:
class AcceleratorTarget; class AcceleratorTarget;
class MenuDelegate; class MenuDelegate;
...@@ -141,6 +148,15 @@ class ASH_EXPORT ClipboardHistoryControllerImpl ...@@ -141,6 +148,15 @@ class ASH_EXPORT ClipboardHistoryControllerImpl
// Whether a paste is currently being performed. // Whether a paste is currently being performed.
bool currently_pasting_ = false; bool currently_pasting_ = false;
// Used to post asynchronous tasks when opening or closing the clipboard
// history menu. Note that those tasks have data races between each other.
// The timer can guarantee that at most one task is alive.
base::OneShotTimer menu_task_timer_;
// Called when the first item view is selected after the clipboard history
// menu opens.
base::RepeatingClosure initial_item_selected_callback_for_test_;
base::WeakPtrFactory<ClipboardHistoryControllerImpl> weak_ptr_factory_{this}; base::WeakPtrFactory<ClipboardHistoryControllerImpl> weak_ptr_factory_{this};
}; };
......
...@@ -158,8 +158,15 @@ class ClipboardHistoryWithMultiProfileBrowserTest ...@@ -158,8 +158,15 @@ class ClipboardHistoryWithMultiProfileBrowserTest
run_loop.Run(); run_loop.Run();
} }
void ShowContextMenuViaAccelerator() { void ShowContextMenuViaAccelerator(bool wait_for_selection) {
PressAndRelease(ui::KeyboardCode::VKEY_V, ui::EF_COMMAND_DOWN); PressAndRelease(ui::KeyboardCode::VKEY_V, ui::EF_COMMAND_DOWN);
if (!wait_for_selection)
return;
base::RunLoop run_loop;
GetClipboardHistoryController()
->set_initial_item_selected_callback_for_test(run_loop.QuitClosure());
run_loop.Run();
} }
const views::MenuItemView* GetMenuItemViewForIndex(int index) const { const views::MenuItemView* GetMenuItemViewForIndex(int index) const {
...@@ -268,7 +275,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMultiProfileBrowserTest, ...@@ -268,7 +275,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMultiProfileBrowserTest,
SetClipboardText("B"); SetClipboardText("B");
SetClipboardText("C"); SetClipboardText("C");
ShowContextMenuViaAccelerator(); ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
ASSERT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); ASSERT_TRUE(GetClipboardHistoryController()->IsMenuShowing());
ASSERT_EQ(3, GetContextMenu()->GetMenuItemsCount()); ASSERT_EQ(3, GetContextMenu()->GetMenuItemsCount());
...@@ -319,7 +326,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMultiProfileBrowserTest, ...@@ -319,7 +326,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMultiProfileBrowserTest,
SetClipboardText("A"); SetClipboardText("A");
SetClipboardText("B"); SetClipboardText("B");
ShowContextMenuViaAccelerator(); ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
// Verify the default state right after the menu shows. // Verify the default state right after the menu shows.
ASSERT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); ASSERT_TRUE(GetClipboardHistoryController()->IsMenuShowing());
...@@ -393,7 +400,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMultiProfileBrowserTest, ...@@ -393,7 +400,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMultiProfileBrowserTest,
LoginUser(account_id1_); LoginUser(account_id1_);
SetClipboardText("A"); SetClipboardText("A");
ShowContextMenuViaAccelerator(); ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
// Verify the default state right after the menu shows. // Verify the default state right after the menu shows.
ASSERT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); ASSERT_TRUE(GetClipboardHistoryController()->IsMenuShowing());
...@@ -427,7 +434,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMultiProfileBrowserTest, ...@@ -427,7 +434,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMultiProfileBrowserTest,
// No clipboard data. So the clipboard history menu should not show. // No clipboard data. So the clipboard history menu should not show.
ASSERT_TRUE(GetClipboardItems().empty()); ASSERT_TRUE(GetClipboardItems().empty());
ShowContextMenuViaAccelerator(); ShowContextMenuViaAccelerator(/*wait_for_selection=*/false);
EXPECT_FALSE(GetClipboardHistoryController()->IsMenuShowing()); EXPECT_FALSE(GetClipboardHistoryController()->IsMenuShowing());
SetClipboardText("test"); SetClipboardText("test");
...@@ -435,7 +442,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMultiProfileBrowserTest, ...@@ -435,7 +442,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMultiProfileBrowserTest,
const gfx::Point mouse_location = const gfx::Point mouse_location =
ash::Shell::Get()->GetPrimaryRootWindow()->bounds().CenterPoint(); ash::Shell::Get()->GetPrimaryRootWindow()->bounds().CenterPoint();
GetEventGenerator()->MoveMouseTo(mouse_location); GetEventGenerator()->MoveMouseTo(mouse_location);
ShowContextMenuViaAccelerator(); ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
// Verifies that the menu is anchored at the cursor's location. // Verifies that the menu is anchored at the cursor's location.
ASSERT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); ASSERT_TRUE(GetClipboardHistoryController()->IsMenuShowing());
...@@ -459,7 +466,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMultiProfileBrowserTest, ...@@ -459,7 +466,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMultiProfileBrowserTest,
SetClipboardText("C"); SetClipboardText("C");
// Show the menu. // Show the menu.
ShowContextMenuViaAccelerator(); ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
ASSERT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); ASSERT_TRUE(GetClipboardHistoryController()->IsMenuShowing());
ASSERT_EQ(3, GetContextMenu()->GetMenuItemsCount()); ASSERT_EQ(3, GetContextMenu()->GetMenuItemsCount());
...@@ -485,7 +492,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMultiProfileBrowserTest, ...@@ -485,7 +492,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMultiProfileBrowserTest,
// Trigger the accelerator of opening the clipboard history menu. No menu // Trigger the accelerator of opening the clipboard history menu. No menu
// shows because of the empty history data. // shows because of the empty history data.
ShowContextMenuViaAccelerator(); ShowContextMenuViaAccelerator(/*wait_for_selection=*/false);
EXPECT_FALSE(GetClipboardHistoryController()->IsMenuShowing()); EXPECT_FALSE(GetClipboardHistoryController()->IsMenuShowing());
} }
...@@ -637,7 +644,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest, ...@@ -637,7 +644,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest,
VerifyResponseToGestures) { VerifyResponseToGestures) {
SetClipboardText("A"); SetClipboardText("A");
SetClipboardText("B"); SetClipboardText("B");
ShowContextMenuViaAccelerator(); ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
ASSERT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); ASSERT_TRUE(GetClipboardHistoryController()->IsMenuShowing());
// Tap at the second menu item view. Verify that "A" is pasted. // Tap at the second menu item view. Verify that "A" is pasted.
...@@ -655,7 +662,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest, ...@@ -655,7 +662,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest,
DeleteButtonShowAfterLongPress) { DeleteButtonShowAfterLongPress) {
SetClipboardText("A"); SetClipboardText("A");
SetClipboardText("B"); SetClipboardText("B");
ShowContextMenuViaAccelerator(); ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
ASSERT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); ASSERT_TRUE(GetClipboardHistoryController()->IsMenuShowing());
ash::ClipboardHistoryItemView* second_item_view = ash::ClipboardHistoryItemView* second_item_view =
...@@ -690,9 +697,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest, ...@@ -690,9 +697,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest,
SetClipboardText("B"); SetClipboardText("B");
SetClipboardText("C"); SetClipboardText("C");
// Verify we can paste the first history item via the COMMAND+V shortcut. ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
PressAndRelease(ui::KeyboardCode::VKEY_V, ui::EF_COMMAND_DOWN);
EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing());
histogram_tester.ExpectTotalCount( histogram_tester.ExpectTotalCount(
"Ash.ClipboardHistory.ContextMenu.DisplayFormatShown", 3); "Ash.ClipboardHistory.ContextMenu.DisplayFormatShown", 3);
...@@ -707,10 +712,10 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest, ...@@ -707,10 +712,10 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest,
textfield_->SetText(base::string16()); textfield_->SetText(base::string16());
EXPECT_TRUE(textfield_->GetText().empty()); EXPECT_TRUE(textfield_->GetText().empty());
// Verify we can paste the first history item via the COMMAND+V shortcut. ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
PressAndRelease(ui::KeyboardCode::VKEY_V, ui::EF_COMMAND_DOWN);
EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing());
// Verify we can paste the first history item via the COMMAND+V shortcut.
PressAndRelease(ui::KeyboardCode::VKEY_V, ui::EF_COMMAND_DOWN); PressAndRelease(ui::KeyboardCode::VKEY_V, ui::EF_COMMAND_DOWN);
EXPECT_FALSE(GetClipboardHistoryController()->IsMenuShowing()); EXPECT_FALSE(GetClipboardHistoryController()->IsMenuShowing());
...@@ -719,9 +724,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest, ...@@ -719,9 +724,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest,
textfield_->SetText(base::string16()); textfield_->SetText(base::string16());
EXPECT_TRUE(textfield_->GetText().empty()); EXPECT_TRUE(textfield_->GetText().empty());
// Verify we can paste the first history item via the COMMAND+V shortcut. ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
PressAndRelease(ui::KeyboardCode::VKEY_V, ui::EF_COMMAND_DOWN);
EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing());
PressAndRelease(ui::KeyboardCode::VKEY_DOWN); PressAndRelease(ui::KeyboardCode::VKEY_DOWN);
...@@ -735,9 +738,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest, ...@@ -735,9 +738,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest,
EXPECT_TRUE(textfield_->GetText().empty()); EXPECT_TRUE(textfield_->GetText().empty());
// Verify we can paste the last history item via the COMMAND+V shortcut. ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
PressAndRelease(ui::KeyboardCode::VKEY_V, ui::EF_COMMAND_DOWN);
EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing());
PressAndRelease(ui::KeyboardCode::VKEY_DOWN); PressAndRelease(ui::KeyboardCode::VKEY_DOWN);
...@@ -757,8 +758,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest, ...@@ -757,8 +758,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest,
// Verify we can traverse clipboard history and paste the first history item // Verify we can traverse clipboard history and paste the first history item
// while holding down the COMMAND key. // while holding down the COMMAND key.
Press(ui::KeyboardCode::VKEY_COMMAND); ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
PressAndRelease(ui::KeyboardCode::VKEY_V, ui::EF_COMMAND_DOWN);
EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing());
PressAndRelease(ui::KeyboardCode::VKEY_V, ui::EF_COMMAND_DOWN); PressAndRelease(ui::KeyboardCode::VKEY_V, ui::EF_COMMAND_DOWN);
EXPECT_FALSE(GetClipboardHistoryController()->IsMenuShowing()); EXPECT_FALSE(GetClipboardHistoryController()->IsMenuShowing());
...@@ -770,8 +770,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest, ...@@ -770,8 +770,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryTextfieldBrowserTest,
// Verify we can traverse clipboard history and paste the last history item // Verify we can traverse clipboard history and paste the last history item
// while holding down the COMMAND key. // while holding down the COMMAND key.
Press(ui::KeyboardCode::VKEY_COMMAND); ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
PressAndRelease(ui::KeyboardCode::VKEY_V, ui::EF_COMMAND_DOWN);
EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing());
PressAndRelease(ui::KeyboardCode::VKEY_DOWN, ui::EF_COMMAND_DOWN); PressAndRelease(ui::KeyboardCode::VKEY_DOWN, ui::EF_COMMAND_DOWN);
PressAndRelease(ui::KeyboardCode::VKEY_DOWN, ui::EF_COMMAND_DOWN); PressAndRelease(ui::KeyboardCode::VKEY_DOWN, ui::EF_COMMAND_DOWN);
...@@ -854,7 +853,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMockDLPBrowserTest, Basics) { ...@@ -854,7 +853,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMockDLPBrowserTest, Basics) {
SetClipboardTextWithInaccessibleSrc("B"); SetClipboardTextWithInaccessibleSrc("B");
EXPECT_TRUE(VerifyClipboardTextData({"B", "A"})); EXPECT_TRUE(VerifyClipboardTextData({"B", "A"}));
ShowContextMenuViaAccelerator(); ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing()); EXPECT_TRUE(GetClipboardHistoryController()->IsMenuShowing());
// Verify that the text is pasted into `textfield_` after the mouse click at // Verify that the text is pasted into `textfield_` after the mouse click at
...@@ -874,7 +873,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMockDLPBrowserTest, Basics) { ...@@ -874,7 +873,7 @@ IN_PROC_BROWSER_TEST_F(ClipboardHistoryWithMockDLPBrowserTest, Basics) {
// Re-show the multipaste menu since the menu is closed after the previous // Re-show the multipaste menu since the menu is closed after the previous
// mouse click. // mouse click.
ASSERT_FALSE(GetClipboardHistoryController()->IsMenuShowing()); ASSERT_FALSE(GetClipboardHistoryController()->IsMenuShowing());
ShowContextMenuViaAccelerator(); ShowContextMenuViaAccelerator(/*wait_for_selection=*/true);
// Move mouse to `inaccessible_menu_item_view` then click the left button. // Move mouse to `inaccessible_menu_item_view` then click the left button.
const views::MenuItemView* inaccessible_menu_item_view = const views::MenuItemView* inaccessible_menu_item_view =
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment