drag_drop_controller_unittest.cc 75 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/drag_drop/drag_drop_controller.h"
  5. #include <memory>
  6. #include "ash/constants/ash_features.h"
  7. #include "ash/drag_drop/drag_image_view.h"
  8. #include "ash/drag_drop/toplevel_window_drag_delegate.h"
  9. #include "ash/public/cpp/test/test_new_window_delegate.h"
  10. #include "ash/shell.h"
  11. #include "ash/test/ash_test_base.h"
  12. #include "ash/test_shell_delegate.h"
  13. #include "ash/wm/splitview/split_view_controller.h"
  14. #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
  15. #include "base/bind.h"
  16. #include "base/callback_helpers.h"
  17. #include "base/command_line.h"
  18. #include "base/location.h"
  19. #include "base/notreached.h"
  20. #include "base/run_loop.h"
  21. #include "base/strings/utf_string_conversions.h"
  22. #include "base/test/bind.h"
  23. #include "base/test/gmock_callback_support.h"
  24. #include "base/test/scoped_feature_list.h"
  25. #include "base/threading/thread_task_runner_handle.h"
  26. #include "testing/gmock/include/gmock/gmock.h"
  27. #include "third_party/abseil-cpp/absl/types/optional.h"
  28. #include "ui/aura/client/capture_client.h"
  29. #include "ui/aura/client/drag_drop_client_observer.h"
  30. #include "ui/aura/client/drag_drop_delegate.h"
  31. #include "ui/aura/test/test_window_delegate.h"
  32. #include "ui/aura/window_event_dispatcher.h"
  33. #include "ui/aura/window_tree_host.h"
  34. #include "ui/base/clipboard/clipboard.h"
  35. #include "ui/base/clipboard/scoped_clipboard_writer.h"
  36. #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
  37. #include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
  38. #include "ui/base/dragdrop/drag_drop_types.h"
  39. #include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
  40. #include "ui/base/dragdrop/os_exchange_data.h"
  41. #include "ui/events/event.h"
  42. #include "ui/events/event_utils.h"
  43. #include "ui/events/gesture_detection/gesture_configuration.h"
  44. #include "ui/events/gestures/gesture_types.h"
  45. #include "ui/events/test/event_generator.h"
  46. #include "ui/events/test/events_test_utils.h"
  47. #include "ui/gfx/animation/linear_animation.h"
  48. #include "ui/gfx/geometry/point.h"
  49. #include "ui/gfx/geometry/point_conversions.h"
  50. #include "ui/gfx/geometry/point_f.h"
  51. #include "ui/gfx/image/image_skia_rep.h"
  52. #include "ui/views/view.h"
  53. #include "ui/views/widget/widget.h"
  54. #include "ui/wm/core/coordinate_conversion.h"
  55. namespace ash {
  56. namespace {
  57. using ::base::test::RunOnceCallback;
  58. using ::testing::_;
  59. using ::testing::NiceMock;
  60. using ::testing::Return;
  61. using ::ui::mojom::DragOperation;
  62. // Sets string and drag image for testing.
  63. void SetDragData(OSExchangeData* data, bool with_image) {
  64. data->SetString(u"I am being dragged");
  65. if (with_image) {
  66. gfx::ImageSkiaRep image_rep(gfx::Size(10, 20), 1.0f);
  67. gfx::ImageSkia image_skia(image_rep);
  68. data->provider().SetDragImage(image_skia, gfx::Vector2d());
  69. }
  70. }
  71. std::unique_ptr<ui::OSExchangeData> CreateDragData(bool with_image) {
  72. auto data = std::make_unique<ui::OSExchangeData>();
  73. SetDragData(data.get(), with_image);
  74. return data;
  75. }
  76. // A simple view that makes sure RunShellDrag is invoked on mouse drag.
  77. class DragTestView : public views::View {
  78. public:
  79. DragTestView() : views::View() { Reset(); }
  80. DragTestView(const DragTestView&) = delete;
  81. DragTestView& operator=(const DragTestView&) = delete;
  82. void Reset() {
  83. num_drag_enters_ = 0;
  84. num_drag_exits_ = 0;
  85. num_drag_updates_ = 0;
  86. num_drops_ = 0;
  87. drag_done_received_ = false;
  88. long_tap_received_ = false;
  89. }
  90. int VerticalDragThreshold() {
  91. return views::View::GetVerticalDragThreshold();
  92. }
  93. int HorizontalDragThreshold() {
  94. return views::View::GetHorizontalDragThreshold();
  95. }
  96. void OmitDragImage() { omit_drag_image_ = true; }
  97. int num_drag_enters_;
  98. int num_drag_exits_;
  99. int num_drag_updates_;
  100. int num_drops_;
  101. bool drag_done_received_;
  102. bool long_tap_received_;
  103. private:
  104. // View overrides:
  105. int GetDragOperations(const gfx::Point& press_pt) override {
  106. return ui::DragDropTypes::DRAG_COPY;
  107. }
  108. void WriteDragData(const gfx::Point& p, OSExchangeData* data) override {
  109. SetDragData(data, /*with_image=*/!omit_drag_image_);
  110. }
  111. bool OnMousePressed(const ui::MouseEvent& event) override { return true; }
  112. void OnGestureEvent(ui::GestureEvent* event) override {
  113. if (event->type() == ui::ET_GESTURE_LONG_TAP)
  114. long_tap_received_ = true;
  115. return;
  116. }
  117. bool GetDropFormats(
  118. int* formats,
  119. std::set<ui::ClipboardFormatType>* format_types) override {
  120. *formats = ui::OSExchangeData::STRING;
  121. return true;
  122. }
  123. bool CanDrop(const OSExchangeData& data) override { return true; }
  124. void OnDragEntered(const ui::DropTargetEvent& event) override {
  125. num_drag_enters_++;
  126. }
  127. int OnDragUpdated(const ui::DropTargetEvent& event) override {
  128. num_drag_updates_++;
  129. return ui::DragDropTypes::DRAG_COPY;
  130. }
  131. void OnDragExited() override { num_drag_exits_++; }
  132. DropCallback GetDropCallback(const ui::DropTargetEvent& event) override {
  133. return base::BindOnce(&DragTestView::PerformDrop, base::Unretained(this));
  134. }
  135. void OnDragDone() override { drag_done_received_ = true; }
  136. void PerformDrop(const ui::DropTargetEvent& event,
  137. ui::mojom::DragOperation& output_drag_op) {
  138. num_drops_++;
  139. output_drag_op = DragOperation::kCopy;
  140. }
  141. bool omit_drag_image_ = false;
  142. };
  143. class CompletableLinearAnimation : public gfx::LinearAnimation {
  144. public:
  145. CompletableLinearAnimation(base::TimeDelta duration,
  146. int frame_rate,
  147. gfx::AnimationDelegate* delegate)
  148. : gfx::LinearAnimation(duration, frame_rate, delegate) {}
  149. CompletableLinearAnimation(const CompletableLinearAnimation&) = delete;
  150. CompletableLinearAnimation& operator=(const CompletableLinearAnimation&) =
  151. delete;
  152. void Complete() { Step(start_time() + duration()); }
  153. };
  154. class TestDragDropController : public DragDropController {
  155. public:
  156. TestDragDropController() : DragDropController() { Reset(); }
  157. TestDragDropController(const TestDragDropController&) = delete;
  158. TestDragDropController& operator=(const TestDragDropController&) = delete;
  159. void Reset() {
  160. drag_start_received_ = false;
  161. num_drag_updates_ = 0;
  162. drop_received_ = false;
  163. drag_canceled_ = false;
  164. drag_string_.clear();
  165. }
  166. DragOperation StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
  167. aura::Window* root_window,
  168. aura::Window* source_window,
  169. const gfx::Point& location,
  170. int allowed_operations,
  171. ui::mojom::DragEventSource source) override {
  172. drag_start_received_ = true;
  173. data->GetString(&drag_string_);
  174. return DragDropController::StartDragAndDrop(std::move(data), root_window,
  175. source_window, location,
  176. allowed_operations, source);
  177. }
  178. DragDropCaptureDelegate* get_capture_delegate() {
  179. return DragDropController::get_capture_delegate();
  180. }
  181. void DragUpdate(aura::Window* target,
  182. const ui::LocatedEvent& event) override {
  183. DragDropController::DragUpdate(target, event);
  184. num_drag_updates_++;
  185. }
  186. void Drop(aura::Window* target, const ui::LocatedEvent& event) override {
  187. DragDropController::Drop(target, event);
  188. drop_received_ = true;
  189. }
  190. void DragCancel() override {
  191. DragDropController::DragCancel();
  192. drag_canceled_ = true;
  193. }
  194. gfx::LinearAnimation* CreateCancelAnimation(
  195. base::TimeDelta duration,
  196. int frame_rate,
  197. gfx::AnimationDelegate* delegate) override {
  198. return new CompletableLinearAnimation(duration, frame_rate, delegate);
  199. }
  200. void DoDragCancel(base::TimeDelta animation_duration) override {
  201. DragDropController::DoDragCancel(animation_duration);
  202. drag_canceled_ = true;
  203. }
  204. bool drag_start_received_;
  205. int num_drag_updates_;
  206. bool drop_received_;
  207. bool drag_canceled_;
  208. std::u16string drag_string_;
  209. };
  210. class MockObserver : public aura::client::DragDropClientObserver {
  211. public:
  212. // aura::client::DragDropClientObserver
  213. MOCK_METHOD(void, OnDragStarted, (), (override));
  214. MOCK_METHOD(void, OnDragUpdated, (const ui::DropTargetEvent&), (override));
  215. MOCK_METHOD(void, OnDragCompleted, (const ui::DropTargetEvent&), (override));
  216. };
  217. class TestObserver : public aura::client::DragDropClientObserver {
  218. public:
  219. enum class State { kNotInvoked, kDragStartedInvoked, kDragEndedInvoked };
  220. TestObserver() : state_(State::kNotInvoked) {}
  221. TestObserver(const TestObserver&) = delete;
  222. TestObserver& operator=(const TestObserver&) = delete;
  223. State state() const { return state_; }
  224. // aura::client::DragDropClientObserver
  225. void OnDragStarted() override {
  226. EXPECT_EQ(State::kNotInvoked, state_);
  227. state_ = State::kDragStartedInvoked;
  228. }
  229. void OnDragCompleted(const ui::DropTargetEvent& event) override {
  230. EXPECT_EQ(State::kDragStartedInvoked, state_);
  231. state_ = State::kDragEndedInvoked;
  232. }
  233. private:
  234. State state_;
  235. };
  236. class EventTargetTestDelegate : public aura::client::DragDropDelegate {
  237. public:
  238. enum class State {
  239. kNotInvoked,
  240. kDragEnteredInvoked,
  241. kDragUpdateInvoked,
  242. kPerformDropInvoked,
  243. kDragExitInvoked
  244. };
  245. explicit EventTargetTestDelegate(aura::Window* window) : window_(window) {}
  246. EventTargetTestDelegate(const EventTargetTestDelegate&) = delete;
  247. EventTargetTestDelegate& operator=(const EventTargetTestDelegate&) = delete;
  248. State state() const { return state_; }
  249. // aura::client::DragDropDelegate:
  250. void OnDragEntered(const ui::DropTargetEvent& event) override {
  251. EXPECT_EQ(State::kNotInvoked, state_);
  252. EXPECT_EQ(window_, event.target());
  253. state_ = State::kDragEnteredInvoked;
  254. }
  255. aura::client::DragUpdateInfo OnDragUpdated(
  256. const ui::DropTargetEvent& event) override {
  257. EXPECT_TRUE(State::kDragEnteredInvoked == state_ ||
  258. State::kDragUpdateInvoked == state_);
  259. EXPECT_EQ(window_, event.target());
  260. state_ = State::kDragUpdateInvoked;
  261. return aura::client::DragUpdateInfo(
  262. ui::DragDropTypes::DRAG_MOVE,
  263. ui::DataTransferEndpoint(ui::EndpointType::kDefault));
  264. }
  265. void OnDragExited() override {
  266. EXPECT_TRUE(State::kDragEnteredInvoked == state_ ||
  267. State::kDragUpdateInvoked == state_);
  268. state_ = State::kDragExitInvoked;
  269. }
  270. DropCallback GetDropCallback(const ui::DropTargetEvent& event) override {
  271. return base::BindOnce(&EventTargetTestDelegate::PerformDrop,
  272. base::Unretained(this));
  273. }
  274. private:
  275. void PerformDrop(std::unique_ptr<ui::OSExchangeData> data,
  276. ui::mojom::DragOperation& output_drag_op) {
  277. EXPECT_EQ(State::kDragUpdateInvoked, state_);
  278. state_ = State::kPerformDropInvoked;
  279. output_drag_op = DragOperation::kMove;
  280. }
  281. aura::Window* const window_;
  282. State state_{State::kNotInvoked};
  283. };
  284. void AddViewToWidgetAndResize(views::Widget* widget, views::View* view) {
  285. if (!widget->GetContentsView())
  286. widget->SetContentsView(std::make_unique<views::View>());
  287. views::View* contents_view = widget->GetContentsView();
  288. contents_view->AddChildView(view);
  289. view->SetBounds(contents_view->width(), 0, 100, 100);
  290. gfx::Rect contents_view_bounds = contents_view->bounds();
  291. contents_view_bounds.Union(view->bounds());
  292. contents_view->SetBoundsRect(contents_view_bounds);
  293. widget->SetBounds(contents_view_bounds);
  294. }
  295. void DispatchGesture(ui::EventType gesture_type, gfx::Point location) {
  296. ui::GestureEventDetails event_details(gesture_type);
  297. ui::GestureEvent gesture_event(location.x(), location.y(), 0,
  298. ui::EventTimeForNow(), event_details);
  299. ui::EventSource* event_source =
  300. Shell::GetPrimaryRootWindow()->GetHost()->GetEventSource();
  301. ui::EventSourceTestApi event_source_test(event_source);
  302. ui::EventDispatchDetails details =
  303. event_source_test.SendEventToSink(&gesture_event);
  304. CHECK(!details.dispatcher_destroyed);
  305. }
  306. class TestToplevelWindowDragDelegate : public ToplevelWindowDragDelegate {
  307. public:
  308. enum class State {
  309. kNotInvoked,
  310. kDragStartedInvoked,
  311. kDragDroppedInvoked,
  312. kDragCancelledInvoked,
  313. kDragEventInvoked
  314. };
  315. TestToplevelWindowDragDelegate() = default;
  316. TestToplevelWindowDragDelegate(const TestToplevelWindowDragDelegate&) =
  317. delete;
  318. TestToplevelWindowDragDelegate& operator=(
  319. const TestToplevelWindowDragDelegate&) = delete;
  320. ~TestToplevelWindowDragDelegate() override = default;
  321. State state() const { return state_; }
  322. int events_forwarded() const { return events_forwarded_; }
  323. ui::mojom::DragEventSource source() const { return source_; }
  324. absl::optional<gfx::PointF> current_location() const {
  325. return current_location_;
  326. }
  327. // ToplevelWindowDragDelegate:
  328. void OnToplevelWindowDragStarted(const gfx::PointF& start_location,
  329. ui::mojom::DragEventSource source,
  330. aura::Window* source_window) override {
  331. ASSERT_EQ(State::kNotInvoked, state_);
  332. ASSERT_TRUE(source_window);
  333. state_ = State::kDragStartedInvoked;
  334. current_location_.emplace(start_location);
  335. source_ = source;
  336. if (source == ui::mojom::DragEventSource::kMouse)
  337. source_window->SetCapture();
  338. }
  339. DragOperation OnToplevelWindowDragDropped() override {
  340. EXPECT_EQ(State::kDragStartedInvoked, state_);
  341. state_ = State::kDragDroppedInvoked;
  342. return DragOperation::kMove;
  343. }
  344. void OnToplevelWindowDragCancelled() override {
  345. EXPECT_EQ(State::kDragStartedInvoked, state_);
  346. state_ = State::kDragCancelledInvoked;
  347. }
  348. void OnToplevelWindowDragEvent(ui::LocatedEvent* event) override {
  349. ASSERT_TRUE(event);
  350. EXPECT_TRUE(current_location_.has_value());
  351. current_location_.emplace(event->root_location_f());
  352. events_forwarded_++;
  353. event->StopPropagation();
  354. }
  355. private:
  356. State state_ = State::kNotInvoked;
  357. int events_forwarded_ = 0;
  358. absl::optional<gfx::PointF> current_location_;
  359. ui::mojom::DragEventSource source_;
  360. };
  361. } // namespace
  362. class MockShellDelegate : public TestShellDelegate {
  363. public:
  364. MockShellDelegate() = default;
  365. ~MockShellDelegate() override = default;
  366. MOCK_METHOD(bool, IsTabDrag, (const ui::OSExchangeData&), (override));
  367. };
  368. class MockNewWindowDelegate : public TestNewWindowDelegate {
  369. public:
  370. MockNewWindowDelegate() = default;
  371. ~MockNewWindowDelegate() override = default;
  372. MOCK_METHOD(void,
  373. NewWindowForDetachingTab,
  374. (aura::Window*,
  375. const ui::OSExchangeData&,
  376. NewWindowForDetachingTabCallback),
  377. (override));
  378. };
  379. class DragDropControllerTest : public AshTestBase {
  380. public:
  381. DragDropControllerTest()
  382. : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
  383. DragDropControllerTest(const DragDropControllerTest&) = delete;
  384. DragDropControllerTest& operator=(const DragDropControllerTest&) = delete;
  385. ~DragDropControllerTest() override = default;
  386. void SetUp() override {
  387. auto mock_new_window_delegate =
  388. std::make_unique<NiceMock<MockNewWindowDelegate>>();
  389. mock_new_window_delegate_ptr_ = mock_new_window_delegate.get();
  390. test_new_window_delegate_provider_ =
  391. std::make_unique<TestNewWindowDelegateProvider>(
  392. std::move(mock_new_window_delegate));
  393. auto mock_shell_delegate = std::make_unique<NiceMock<MockShellDelegate>>();
  394. mock_shell_delegate_ = mock_shell_delegate.get();
  395. AshTestBase::SetUp(std::move(mock_shell_delegate));
  396. drag_drop_controller_ = std::make_unique<TestDragDropController>();
  397. drag_drop_controller_->set_should_block_during_drag_drop(false);
  398. drag_drop_controller_->set_enabled(true);
  399. aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(),
  400. drag_drop_controller_.get());
  401. }
  402. void TearDown() override {
  403. aura::client::SetDragDropClient(Shell::GetPrimaryRootWindow(), NULL);
  404. drag_drop_controller_.reset();
  405. AshTestBase::TearDown();
  406. }
  407. aura::Window* GetDragWindow() { return drag_drop_controller_->drag_window_; }
  408. aura::Window* GetDragSourceWindow() {
  409. return drag_drop_controller_->drag_source_window_;
  410. }
  411. void SetDragSourceWindow(aura::Window* drag_source_window) {
  412. drag_drop_controller_->drag_source_window_ = drag_source_window;
  413. drag_source_window->AddObserver(drag_drop_controller_.get());
  414. }
  415. gfx::ImageSkia GetDragImage() {
  416. return static_cast<DragImageView*>(
  417. drag_drop_controller_->drag_image_widget_->GetContentsView())
  418. ->GetImage();
  419. }
  420. aura::Window* GetDragImageWindow() {
  421. return drag_drop_controller_->drag_image_widget_
  422. ? drag_drop_controller_->drag_image_widget_->GetNativeWindow()
  423. : nullptr;
  424. }
  425. MockShellDelegate* mock_shell_delegate() { return mock_shell_delegate_; }
  426. MockNewWindowDelegate* mock_new_window_delegate() {
  427. return mock_new_window_delegate_ptr_;
  428. }
  429. gfx::LinearAnimation* cancel_animation() {
  430. return drag_drop_controller_->cancel_animation_.get();
  431. }
  432. void CompleteCancelAnimation() {
  433. CompletableLinearAnimation* animation =
  434. static_cast<CompletableLinearAnimation*>(
  435. drag_drop_controller_->cancel_animation_.get());
  436. animation->Complete();
  437. }
  438. protected:
  439. std::unique_ptr<views::Widget> CreateFramelessWidget() {
  440. std::unique_ptr<views::Widget> widget = std::make_unique<views::Widget>();
  441. views::Widget::InitParams params;
  442. params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
  443. params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  444. params.context = GetContext();
  445. widget->Init(std::move(params));
  446. widget->Show();
  447. return widget;
  448. }
  449. std::unique_ptr<TestDragDropController> drag_drop_controller_;
  450. NiceMock<MockShellDelegate>* mock_shell_delegate_ = nullptr;
  451. std::unique_ptr<TestNewWindowDelegateProvider>
  452. test_new_window_delegate_provider_;
  453. NiceMock<MockNewWindowDelegate>* mock_new_window_delegate_ptr_ = nullptr;
  454. bool quit_ = false;
  455. void RunWithClosure(base::RepeatingCallback<void(bool)> loop) {
  456. quit_ = false;
  457. drag_drop_controller_->SetLoopClosureForTesting(
  458. base::BindLambdaForTesting([&]() { loop.Run(/*inside=*/true); }),
  459. base::BindLambdaForTesting([&]() { quit_ = true; }));
  460. while (!quit_) {
  461. loop.Run(/*inside=*/false);
  462. }
  463. }
  464. };
  465. TEST_F(DragDropControllerTest, DragDropInSingleViewTest) {
  466. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  467. DragTestView* drag_view = new DragTestView;
  468. AddViewToWidgetAndResize(widget.get(), drag_view);
  469. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  470. widget->GetNativeView());
  471. generator.PressLeftButton();
  472. int num_drags = 17;
  473. for (int i = 0; i < num_drags; ++i) {
  474. generator.MoveMouseBy(0, 1);
  475. }
  476. generator.ReleaseLeftButton();
  477. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  478. EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
  479. drag_drop_controller_->num_drag_updates_);
  480. EXPECT_TRUE(drag_drop_controller_->drop_received_);
  481. EXPECT_EQ(u"I am being dragged", drag_drop_controller_->drag_string_);
  482. EXPECT_EQ(1, drag_view->num_drag_enters_);
  483. EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
  484. drag_view->num_drag_updates_);
  485. EXPECT_EQ(1, drag_view->num_drops_);
  486. EXPECT_EQ(0, drag_view->num_drag_exits_);
  487. EXPECT_TRUE(drag_view->drag_done_received_);
  488. }
  489. TEST_F(DragDropControllerTest, DragDropMouseReleasesWindowCapture) {
  490. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  491. DragTestView* drag_view = new DragTestView;
  492. AddViewToWidgetAndResize(widget.get(), drag_view);
  493. aura::Window* window = widget->GetNativeView();
  494. EXPECT_FALSE(window->HasCapture());
  495. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), window);
  496. generator.PressLeftButton();
  497. // aura::Window does not explicitly take capture, so call this manually to
  498. // simulate dragging a view which does take capture.
  499. window->SetCapture();
  500. EXPECT_TRUE(window->HasCapture());
  501. int n = 0;
  502. auto loop_task = [&](bool inside) {
  503. generator.MoveMouseBy(0, 1);
  504. n++;
  505. if (n == 17)
  506. generator.ReleaseLeftButton();
  507. };
  508. RunWithClosure(base::BindLambdaForTesting(loop_task));
  509. EXPECT_TRUE(drag_view->drag_done_received_);
  510. EXPECT_FALSE(window->HasCapture());
  511. }
  512. TEST_F(DragDropControllerTest, DragDropWithZeroDragUpdates) {
  513. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  514. DragTestView* drag_view = new DragTestView;
  515. AddViewToWidgetAndResize(widget.get(), drag_view);
  516. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  517. widget->GetNativeView());
  518. generator.PressLeftButton();
  519. int num_drags = drag_view->VerticalDragThreshold() + 1;
  520. for (int i = 0; i < num_drags; ++i) {
  521. generator.MoveMouseBy(0, 1);
  522. }
  523. generator.ReleaseLeftButton();
  524. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  525. EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold() + 1,
  526. drag_drop_controller_->num_drag_updates_);
  527. EXPECT_TRUE(drag_drop_controller_->drop_received_);
  528. EXPECT_EQ(1, drag_view->num_drag_enters_);
  529. EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold() + 1,
  530. drag_view->num_drag_updates_);
  531. EXPECT_EQ(1, drag_view->num_drops_);
  532. EXPECT_EQ(0, drag_view->num_drag_exits_);
  533. EXPECT_TRUE(drag_view->drag_done_received_);
  534. }
  535. TEST_F(DragDropControllerTest, DragDropInMultipleViewsSingleWidgetTest) {
  536. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  537. DragTestView* drag_view1 = new DragTestView;
  538. AddViewToWidgetAndResize(widget.get(), drag_view1);
  539. DragTestView* drag_view2 = new DragTestView;
  540. AddViewToWidgetAndResize(widget.get(), drag_view2);
  541. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
  542. generator.MoveMouseRelativeTo(widget->GetNativeView(),
  543. drag_view1->bounds().CenterPoint());
  544. generator.PressLeftButton();
  545. int num_drags = drag_view1->width();
  546. for (int i = 0; i < num_drags; ++i) {
  547. generator.MoveMouseBy(1, 0);
  548. }
  549. generator.ReleaseLeftButton();
  550. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  551. EXPECT_EQ(num_drags - 1 - drag_view1->HorizontalDragThreshold(),
  552. drag_drop_controller_->num_drag_updates_);
  553. EXPECT_TRUE(drag_drop_controller_->drop_received_);
  554. EXPECT_EQ(u"I am being dragged", drag_drop_controller_->drag_string_);
  555. EXPECT_EQ(1, drag_view1->num_drag_enters_);
  556. int num_expected_updates =
  557. drag_view1->bounds().width() - drag_view1->bounds().CenterPoint().x() - 2;
  558. EXPECT_EQ(num_expected_updates - drag_view1->HorizontalDragThreshold(),
  559. drag_view1->num_drag_updates_);
  560. EXPECT_EQ(0, drag_view1->num_drops_);
  561. EXPECT_EQ(1, drag_view1->num_drag_exits_);
  562. EXPECT_TRUE(drag_view1->drag_done_received_);
  563. EXPECT_EQ(1, drag_view2->num_drag_enters_);
  564. num_expected_updates = num_drags - num_expected_updates - 1;
  565. EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
  566. EXPECT_EQ(1, drag_view2->num_drops_);
  567. EXPECT_EQ(0, drag_view2->num_drag_exits_);
  568. EXPECT_FALSE(drag_view2->drag_done_received_);
  569. }
  570. TEST_F(DragDropControllerTest, DragDropInMultipleViewsMultipleWidgetsTest) {
  571. std::unique_ptr<views::Widget> widget1 = CreateFramelessWidget();
  572. DragTestView* drag_view1 = new DragTestView;
  573. AddViewToWidgetAndResize(widget1.get(), drag_view1);
  574. std::unique_ptr<views::Widget> widget2 = CreateFramelessWidget();
  575. DragTestView* drag_view2 = new DragTestView;
  576. AddViewToWidgetAndResize(widget2.get(), drag_view2);
  577. gfx::Rect widget1_bounds = widget1->GetClientAreaBoundsInScreen();
  578. gfx::Rect widget2_bounds = widget2->GetClientAreaBoundsInScreen();
  579. widget2->SetBounds(gfx::Rect(widget1_bounds.width(), 0,
  580. widget2_bounds.width(),
  581. widget2_bounds.height()));
  582. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  583. widget1->GetNativeView());
  584. generator.PressLeftButton();
  585. int num_drags = drag_view1->width();
  586. for (int i = 0; i < num_drags; ++i) {
  587. generator.MoveMouseBy(1, 0);
  588. }
  589. generator.ReleaseLeftButton();
  590. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  591. EXPECT_EQ(num_drags - 1 - drag_view1->HorizontalDragThreshold(),
  592. drag_drop_controller_->num_drag_updates_);
  593. EXPECT_TRUE(drag_drop_controller_->drop_received_);
  594. EXPECT_EQ(u"I am being dragged", drag_drop_controller_->drag_string_);
  595. EXPECT_EQ(1, drag_view1->num_drag_enters_);
  596. int num_expected_updates =
  597. drag_view1->bounds().width() - drag_view1->bounds().CenterPoint().x() - 2;
  598. EXPECT_EQ(num_expected_updates - drag_view1->HorizontalDragThreshold(),
  599. drag_view1->num_drag_updates_);
  600. EXPECT_EQ(0, drag_view1->num_drops_);
  601. EXPECT_EQ(1, drag_view1->num_drag_exits_);
  602. EXPECT_TRUE(drag_view1->drag_done_received_);
  603. EXPECT_EQ(1, drag_view2->num_drag_enters_);
  604. num_expected_updates = num_drags - num_expected_updates - 1;
  605. EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
  606. EXPECT_EQ(1, drag_view2->num_drops_);
  607. EXPECT_EQ(0, drag_view2->num_drag_exits_);
  608. EXPECT_FALSE(drag_view2->drag_done_received_);
  609. }
  610. TEST_F(DragDropControllerTest, ViewRemovedWhileInDragDropTest) {
  611. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  612. std::unique_ptr<DragTestView> drag_view(new DragTestView);
  613. AddViewToWidgetAndResize(widget.get(), drag_view.get());
  614. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
  615. generator.MoveMouseToCenterOf(widget->GetNativeView());
  616. generator.PressLeftButton();
  617. int num_drags_1 = 17;
  618. for (int i = 0; i < num_drags_1; ++i) {
  619. generator.MoveMouseBy(0, 1);
  620. }
  621. drag_view->parent()->RemoveChildView(drag_view.get());
  622. // View has been removed. We will not get any of the following drag updates.
  623. int num_drags_2 = 23;
  624. for (int i = 0; i < num_drags_2; ++i) {
  625. generator.MoveMouseBy(0, 1);
  626. }
  627. generator.ReleaseLeftButton();
  628. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  629. EXPECT_EQ(num_drags_1 + num_drags_2 - 1 - drag_view->VerticalDragThreshold(),
  630. drag_drop_controller_->num_drag_updates_);
  631. EXPECT_TRUE(drag_drop_controller_->drop_received_);
  632. EXPECT_EQ(u"I am being dragged", drag_drop_controller_->drag_string_);
  633. EXPECT_EQ(1, drag_view->num_drag_enters_);
  634. EXPECT_EQ(num_drags_1 - 1 - drag_view->VerticalDragThreshold(),
  635. drag_view->num_drag_updates_);
  636. EXPECT_EQ(0, drag_view->num_drops_);
  637. EXPECT_EQ(0, drag_view->num_drag_exits_);
  638. EXPECT_TRUE(drag_view->drag_done_received_);
  639. }
  640. TEST_F(DragDropControllerTest, DragLeavesClipboardAloneTest) {
  641. ui::Clipboard* cb = ui::Clipboard::GetForCurrentThread();
  642. std::string clip_str("I am on the clipboard");
  643. {
  644. // We first copy some text to the clipboard.
  645. ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste);
  646. scw.WriteText(base::ASCIIToUTF16(clip_str));
  647. }
  648. EXPECT_TRUE(cb->IsFormatAvailable(ui::ClipboardFormatType::PlainTextType(),
  649. ui::ClipboardBuffer::kCopyPaste,
  650. /* data_dst = */ nullptr));
  651. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  652. DragTestView* drag_view = new DragTestView;
  653. AddViewToWidgetAndResize(widget.get(), drag_view);
  654. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  655. widget->GetNativeView());
  656. generator.PressLeftButton();
  657. generator.MoveMouseBy(0, drag_view->VerticalDragThreshold() + 1);
  658. // Execute any scheduled draws to process deferred mouse events.
  659. base::RunLoop().RunUntilIdle();
  660. // Verify the clipboard contents haven't changed
  661. std::string result;
  662. EXPECT_TRUE(cb->IsFormatAvailable(ui::ClipboardFormatType::PlainTextType(),
  663. ui::ClipboardBuffer::kCopyPaste,
  664. /* data_dst = */ nullptr));
  665. cb->ReadAsciiText(ui::ClipboardBuffer::kCopyPaste, /* data_dst = */ nullptr,
  666. &result);
  667. EXPECT_EQ(clip_str, result);
  668. // Destroy the clipboard here because ash doesn't delete it.
  669. // crbug.com/158150.
  670. ui::Clipboard::DestroyClipboardForCurrentThread();
  671. }
  672. // Cancelling followed by closing window should not cause use after free.
  673. // This happens when closing a browser window while dragging.
  674. // crbug.com/1282480
  675. TEST_F(DragDropControllerTest, DragCanceledThenWindowDestroyedDuringDragDrop) {
  676. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  677. DragTestView* drag_view = new DragTestView;
  678. AddViewToWidgetAndResize(widget.get(), drag_view);
  679. aura::Window* window = widget->GetNativeView();
  680. EventTargetTestDelegate delegate(window);
  681. aura::client::SetDragDropDelegate(window, &delegate);
  682. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  683. widget->GetNativeView());
  684. generator.PressLeftButton();
  685. int n = 0;
  686. bool dragged = false;
  687. auto loop_task = [&](bool inside) {
  688. generator.MoveMouseBy(0, 1);
  689. base::RunLoop().RunUntilIdle();
  690. n++;
  691. if (inside && window) {
  692. dragged = true;
  693. EXPECT_EQ(window, GetDragWindow());
  694. EXPECT_GT(n, drag_view->VerticalDragThreshold());
  695. }
  696. if (n == 18) {
  697. drag_drop_controller_->DragCancel();
  698. widget->CloseNow();
  699. EXPECT_FALSE(this->GetDragWindow());
  700. window = nullptr;
  701. }
  702. };
  703. RunWithClosure(base::BindLambdaForTesting(loop_task));
  704. EXPECT_TRUE(dragged);
  705. EXPECT_FALSE(GetDragWindow());
  706. generator.ReleaseLeftButton();
  707. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  708. // Drag must have been canceled.
  709. EXPECT_TRUE(drag_drop_controller_->drag_canceled_);
  710. EXPECT_FALSE(drag_drop_controller_->drop_received_);
  711. EXPECT_EQ(EventTargetTestDelegate::State::kDragExitInvoked, delegate.state());
  712. }
  713. TEST_F(DragDropControllerTest, SyntheticEventsDuringDragDrop) {
  714. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  715. DragTestView* drag_view = new DragTestView;
  716. AddViewToWidgetAndResize(widget.get(), drag_view);
  717. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  718. widget->GetNativeView());
  719. generator.PressLeftButton();
  720. int num_drags = 17;
  721. for (int i = 0; i < num_drags; ++i) {
  722. generator.MoveMouseBy(0, 1);
  723. // We send a unexpected mouse move event. Note that we cannot use
  724. // EventGenerator since it implicitly turns these into mouse drag events.
  725. // The DragDropController should simply ignore these events.
  726. gfx::Point mouse_move_location = drag_view->bounds().CenterPoint();
  727. ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED, mouse_move_location,
  728. mouse_move_location, ui::EventTimeForNow(), 0, 0);
  729. ui::EventDispatchDetails details = Shell::GetPrimaryRootWindow()
  730. ->GetHost()
  731. ->GetEventSink()
  732. ->OnEventFromSource(&mouse_move);
  733. ASSERT_FALSE(details.dispatcher_destroyed);
  734. }
  735. generator.ReleaseLeftButton();
  736. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  737. EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
  738. drag_drop_controller_->num_drag_updates_);
  739. EXPECT_TRUE(drag_drop_controller_->drop_received_);
  740. EXPECT_EQ(u"I am being dragged", drag_drop_controller_->drag_string_);
  741. EXPECT_EQ(1, drag_view->num_drag_enters_);
  742. EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
  743. drag_view->num_drag_updates_);
  744. EXPECT_EQ(1, drag_view->num_drops_);
  745. EXPECT_EQ(0, drag_view->num_drag_exits_);
  746. EXPECT_TRUE(drag_view->drag_done_received_);
  747. }
  748. TEST_F(DragDropControllerTest, PressingEscapeCancelsDragDrop) {
  749. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  750. DragTestView* drag_view = new DragTestView;
  751. AddViewToWidgetAndResize(widget.get(), drag_view);
  752. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  753. widget->GetNativeView());
  754. generator.PressLeftButton();
  755. int num_drags = 17;
  756. for (int i = 0; i < num_drags; ++i) {
  757. generator.MoveMouseBy(0, 1);
  758. }
  759. generator.PressKey(ui::VKEY_ESCAPE, 0);
  760. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  761. EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
  762. drag_drop_controller_->num_drag_updates_);
  763. EXPECT_FALSE(drag_drop_controller_->drop_received_);
  764. EXPECT_TRUE(drag_drop_controller_->drag_canceled_);
  765. EXPECT_EQ(u"I am being dragged", drag_drop_controller_->drag_string_);
  766. EXPECT_EQ(1, drag_view->num_drag_enters_);
  767. EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
  768. drag_view->num_drag_updates_);
  769. EXPECT_EQ(0, drag_view->num_drops_);
  770. EXPECT_EQ(1, drag_view->num_drag_exits_);
  771. EXPECT_TRUE(drag_view->drag_done_received_);
  772. }
  773. TEST_F(DragDropControllerTest, CaptureLostDoesNotCancelsDragDrop) {
  774. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  775. DragTestView* drag_view = new DragTestView;
  776. AddViewToWidgetAndResize(widget.get(), drag_view);
  777. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  778. widget->GetNativeView());
  779. generator.PressLeftButton();
  780. int num_drags = 17;
  781. for (int i = 0; i < num_drags; ++i) {
  782. generator.MoveMouseBy(0, 1);
  783. }
  784. aura::client::GetCaptureClient(widget->GetNativeView()->GetRootWindow())
  785. ->SetCapture(nullptr);
  786. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  787. EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
  788. drag_drop_controller_->num_drag_updates_);
  789. EXPECT_FALSE(drag_drop_controller_->drop_received_);
  790. EXPECT_FALSE(drag_drop_controller_->drag_canceled_);
  791. EXPECT_EQ(u"I am being dragged", drag_drop_controller_->drag_string_);
  792. EXPECT_EQ(1, drag_view->num_drag_enters_);
  793. EXPECT_EQ(num_drags - 1 - drag_view->VerticalDragThreshold(),
  794. drag_view->num_drag_updates_);
  795. EXPECT_EQ(0, drag_view->num_drops_);
  796. EXPECT_EQ(0, drag_view->num_drag_exits_);
  797. EXPECT_TRUE(drag_view->drag_done_received_);
  798. }
  799. TEST_F(DragDropControllerTest, TouchDragDropInMultipleWindows) {
  800. std::unique_ptr<views::Widget> widget1 = CreateFramelessWidget();
  801. DragTestView* drag_view1 = new DragTestView;
  802. AddViewToWidgetAndResize(widget1.get(), drag_view1);
  803. std::unique_ptr<views::Widget> widget2 = CreateFramelessWidget();
  804. DragTestView* drag_view2 = new DragTestView;
  805. AddViewToWidgetAndResize(widget2.get(), drag_view2);
  806. gfx::Rect widget1_bounds = widget1->GetClientAreaBoundsInScreen();
  807. gfx::Rect widget2_bounds = widget2->GetClientAreaBoundsInScreen();
  808. widget2->SetBounds(gfx::Rect(widget1_bounds.width(), 0,
  809. widget2_bounds.width(),
  810. widget2_bounds.height()));
  811. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  812. widget1->GetNativeView());
  813. generator.PressTouch();
  814. gfx::Point point = gfx::Rect(drag_view1->bounds()).CenterPoint();
  815. DispatchGesture(ui::ET_GESTURE_LONG_PRESS, point);
  816. gfx::Point gesture_location = point;
  817. int num_drags = drag_view1->width();
  818. for (int i = 0; i < num_drags; ++i) {
  819. gesture_location.Offset(1, 0);
  820. DispatchGesture(ui::ET_GESTURE_SCROLL_UPDATE, gesture_location);
  821. }
  822. DispatchGesture(ui::ET_GESTURE_SCROLL_END, gesture_location);
  823. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  824. EXPECT_EQ(num_drags, drag_drop_controller_->num_drag_updates_);
  825. EXPECT_TRUE(drag_drop_controller_->drop_received_);
  826. EXPECT_EQ(u"I am being dragged", drag_drop_controller_->drag_string_);
  827. EXPECT_EQ(1, drag_view1->num_drag_enters_);
  828. int num_expected_updates =
  829. drag_view1->bounds().width() - drag_view1->bounds().CenterPoint().x() - 1;
  830. EXPECT_EQ(num_expected_updates, drag_view1->num_drag_updates_);
  831. EXPECT_EQ(0, drag_view1->num_drops_);
  832. EXPECT_EQ(1, drag_view1->num_drag_exits_);
  833. EXPECT_TRUE(drag_view1->drag_done_received_);
  834. EXPECT_EQ(1, drag_view2->num_drag_enters_);
  835. num_expected_updates = num_drags - num_expected_updates;
  836. EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
  837. EXPECT_EQ(1, drag_view2->num_drops_);
  838. EXPECT_EQ(0, drag_view2->num_drag_exits_);
  839. EXPECT_FALSE(drag_view2->drag_done_received_);
  840. }
  841. TEST_F(DragDropControllerTest, DragDropWithChangingIcon) {
  842. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  843. DragTestView* drag_view1 = new DragTestView;
  844. AddViewToWidgetAndResize(widget.get(), drag_view1);
  845. DragTestView* drag_view2 = new DragTestView;
  846. AddViewToWidgetAndResize(widget.get(), drag_view2);
  847. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
  848. generator.MoveMouseRelativeTo(widget->GetNativeView(),
  849. drag_view1->bounds().CenterPoint());
  850. generator.PressLeftButton();
  851. int num_drags = drag_view1->width();
  852. int icon_replacements = 0;
  853. for (int i = 0; i < num_drags; ++i) {
  854. if (drag_drop_controller_->IsDragDropInProgress()) {
  855. if (!GetDragSourceWindow())
  856. SetDragSourceWindow(widget->GetNativeWindow());
  857. gfx::ImageSkia new_icon;
  858. new_icon.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10), 1.0f));
  859. EXPECT_FALSE(GetDragImage().BackedBySameObjectAs(new_icon));
  860. drag_drop_controller_->SetDragImage(new_icon, gfx::Vector2d());
  861. EXPECT_TRUE(GetDragImage().BackedBySameObjectAs(new_icon));
  862. icon_replacements++;
  863. }
  864. generator.MoveMouseBy(1, 0);
  865. }
  866. generator.ReleaseLeftButton();
  867. EXPECT_GT(icon_replacements, 0);
  868. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  869. EXPECT_EQ(num_drags - 1 - drag_view1->HorizontalDragThreshold(),
  870. drag_drop_controller_->num_drag_updates_);
  871. EXPECT_TRUE(drag_drop_controller_->drop_received_);
  872. EXPECT_EQ(u"I am being dragged", drag_drop_controller_->drag_string_);
  873. EXPECT_EQ(1, drag_view1->num_drag_enters_);
  874. int num_expected_updates =
  875. drag_view1->bounds().width() - drag_view1->bounds().CenterPoint().x() - 2;
  876. EXPECT_EQ(num_expected_updates - drag_view1->HorizontalDragThreshold(),
  877. drag_view1->num_drag_updates_);
  878. EXPECT_EQ(0, drag_view1->num_drops_);
  879. EXPECT_EQ(1, drag_view1->num_drag_exits_);
  880. EXPECT_TRUE(drag_view1->drag_done_received_);
  881. EXPECT_EQ(1, drag_view2->num_drag_enters_);
  882. num_expected_updates = num_drags - num_expected_updates - 1;
  883. EXPECT_EQ(num_expected_updates, drag_view2->num_drag_updates_);
  884. EXPECT_EQ(1, drag_view2->num_drops_);
  885. EXPECT_EQ(0, drag_view2->num_drag_exits_);
  886. EXPECT_FALSE(drag_view2->drag_done_received_);
  887. }
  888. namespace {
  889. class DragImageWindowObserver : public aura::WindowObserver {
  890. public:
  891. void OnWindowDestroying(aura::Window* window) override {
  892. window_location_on_destroying_ = window->GetBoundsInScreen().origin();
  893. }
  894. gfx::Point window_location_on_destroying() const {
  895. return window_location_on_destroying_;
  896. }
  897. public:
  898. gfx::Point window_location_on_destroying_;
  899. };
  900. } // namespace
  901. // Verifies the drag image moves back to the position where drag is started
  902. // across displays when drag is cancelled.
  903. TEST_F(DragDropControllerTest, DragCancelAcrossDisplays) {
  904. UpdateDisplay("500x400,500x400");
  905. aura::Window::Windows root_windows = Shell::Get()->GetAllRootWindows();
  906. for (aura::Window::Windows::iterator iter = root_windows.begin();
  907. iter != root_windows.end(); ++iter) {
  908. aura::client::SetDragDropClient(*iter, drag_drop_controller_.get());
  909. }
  910. {
  911. auto data = CreateDragData(/*with_image=*/true);
  912. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  913. aura::Window* window = widget->GetNativeWindow();
  914. drag_drop_controller_->StartDragAndDrop(
  915. std::move(data), window->GetRootWindow(), window, gfx::Point(5, 5),
  916. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kMouse);
  917. DragImageWindowObserver observer;
  918. ASSERT_TRUE(GetDragImageWindow());
  919. GetDragImageWindow()->AddObserver(&observer);
  920. {
  921. ui::MouseEvent e(ui::ET_MOUSE_DRAGGED, gfx::Point(200, 0),
  922. gfx::Point(200, 0), ui::EventTimeForNow(), ui::EF_NONE,
  923. ui::EF_NONE);
  924. drag_drop_controller_->DragUpdate(window, e);
  925. }
  926. {
  927. ui::MouseEvent e(ui::ET_MOUSE_DRAGGED, gfx::Point(600, 0),
  928. gfx::Point(600, 0), ui::EventTimeForNow(), ui::EF_NONE,
  929. ui::EF_NONE);
  930. drag_drop_controller_->DragUpdate(window, e);
  931. }
  932. drag_drop_controller_->DragCancel();
  933. CompleteCancelAnimation();
  934. // Make sure all pending tasks complete to finish cancellation.
  935. base::RunLoop().RunUntilIdle();
  936. EXPECT_EQ("5,5", observer.window_location_on_destroying().ToString());
  937. }
  938. {
  939. auto data = CreateDragData(/*with_image=*/true);
  940. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  941. aura::Window* window = widget->GetNativeWindow();
  942. drag_drop_controller_->StartDragAndDrop(
  943. std::move(data), window->GetRootWindow(), window, gfx::Point(405, 405),
  944. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kMouse);
  945. DragImageWindowObserver observer;
  946. ASSERT_TRUE(GetDragImageWindow());
  947. GetDragImageWindow()->AddObserver(&observer);
  948. {
  949. ui::MouseEvent e(ui::ET_MOUSE_DRAGGED, gfx::Point(600, 0),
  950. gfx::Point(600, 0), ui::EventTimeForNow(), ui::EF_NONE,
  951. ui::EF_NONE);
  952. drag_drop_controller_->DragUpdate(window, e);
  953. }
  954. {
  955. ui::MouseEvent e(ui::ET_MOUSE_DRAGGED, gfx::Point(200, 0),
  956. gfx::Point(200, 0), ui::EventTimeForNow(), ui::EF_NONE,
  957. ui::EF_NONE);
  958. drag_drop_controller_->DragUpdate(window, e);
  959. }
  960. drag_drop_controller_->DragCancel();
  961. CompleteCancelAnimation();
  962. // Make sure all pending tasks complete to finish cancellation.
  963. base::RunLoop().RunUntilIdle();
  964. EXPECT_EQ("405,405", observer.window_location_on_destroying().ToString());
  965. }
  966. for (aura::Window::Windows::iterator iter = root_windows.begin();
  967. iter != root_windows.end(); ++iter) {
  968. aura::client::SetDragDropClient(*iter, NULL);
  969. }
  970. }
  971. // Verifies that a drag is aborted if a display is disconnected during the drag.
  972. TEST_F(DragDropControllerTest, DragCancelOnDisplayDisconnect) {
  973. UpdateDisplay("500x400,500x400");
  974. for (aura::Window* root : Shell::Get()->GetAllRootWindows()) {
  975. aura::client::SetDragDropClient(root, drag_drop_controller_.get());
  976. }
  977. auto data = CreateDragData(/*with_image=*/false);
  978. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  979. aura::Window* window = widget->GetNativeWindow();
  980. drag_drop_controller_->StartDragAndDrop(
  981. std::move(data), window->GetRootWindow(), window, gfx::Point(5, 5),
  982. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kMouse);
  983. // Start dragging.
  984. ui::MouseEvent e1(ui::ET_MOUSE_DRAGGED, gfx::Point(200, 0),
  985. gfx::Point(200, 0), ui::EventTimeForNow(), ui::EF_NONE,
  986. ui::EF_NONE);
  987. drag_drop_controller_->DragUpdate(window, e1);
  988. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  989. EXPECT_TRUE(drag_drop_controller_->IsDragDropInProgress());
  990. // Drag onto the secondary display.
  991. ui::MouseEvent e2(ui::ET_MOUSE_DRAGGED, gfx::Point(600, 0),
  992. gfx::Point(600, 0), ui::EventTimeForNow(), ui::EF_NONE,
  993. ui::EF_NONE);
  994. drag_drop_controller_->DragUpdate(window, e2);
  995. EXPECT_TRUE(drag_drop_controller_->IsDragDropInProgress());
  996. // Disconnect the secondary display.
  997. UpdateDisplay("800x600");
  998. // The drag is canceled.
  999. EXPECT_TRUE(drag_drop_controller_->drag_canceled_);
  1000. EXPECT_FALSE(drag_drop_controller_->IsDragDropInProgress());
  1001. }
  1002. TEST_F(DragDropControllerTest, TouchDragDropCompletesOnFling) {
  1003. ui::GestureConfiguration::GetInstance()
  1004. ->set_max_touch_move_in_pixels_for_click(1);
  1005. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  1006. DragTestView* drag_view = new DragTestView;
  1007. AddViewToWidgetAndResize(widget.get(), drag_view);
  1008. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  1009. widget->GetNativeView());
  1010. gfx::Point start = gfx::Rect(drag_view->bounds()).CenterPoint();
  1011. gfx::Point mid = start + gfx::Vector2d(drag_view->bounds().width() / 6, 0);
  1012. gfx::Point end = start + gfx::Vector2d(drag_view->bounds().width() / 3, 0);
  1013. base::TimeTicks timestamp = ui::EventTimeForNow();
  1014. ui::TouchEvent press(ui::ET_TOUCH_PRESSED, start, timestamp,
  1015. ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  1016. generator.Dispatch(&press);
  1017. DispatchGesture(ui::ET_GESTURE_LONG_PRESS, start);
  1018. timestamp += base::Milliseconds(10);
  1019. ui::TouchEvent move1(ui::ET_TOUCH_MOVED, mid, timestamp,
  1020. ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  1021. generator.Dispatch(&move1);
  1022. // Doing two moves instead of one will guarantee to generate a fling at the
  1023. // end.
  1024. timestamp += base::Milliseconds(10);
  1025. ui::TouchEvent move2(ui::ET_TOUCH_MOVED, end, timestamp,
  1026. ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  1027. generator.Dispatch(&move2);
  1028. ui::TouchEvent release(ui::ET_TOUCH_RELEASED, end, timestamp,
  1029. ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  1030. generator.Dispatch(&release);
  1031. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  1032. EXPECT_FALSE(drag_drop_controller_->drag_canceled_);
  1033. EXPECT_EQ(2, drag_drop_controller_->num_drag_updates_);
  1034. EXPECT_TRUE(drag_drop_controller_->drop_received_);
  1035. EXPECT_EQ(u"I am being dragged", drag_drop_controller_->drag_string_);
  1036. EXPECT_EQ(1, drag_view->num_drag_enters_);
  1037. EXPECT_EQ(2, drag_view->num_drag_updates_);
  1038. EXPECT_EQ(1, drag_view->num_drops_);
  1039. EXPECT_EQ(0, drag_view->num_drag_exits_);
  1040. EXPECT_TRUE(drag_view->drag_done_received_);
  1041. }
  1042. TEST_F(DragDropControllerTest, DragObserverEvents) {
  1043. testing::StrictMock<MockObserver> observer;
  1044. drag_drop_controller_->AddObserver(&observer);
  1045. {
  1046. auto data = CreateDragData(/*with_image=*/false);
  1047. ui::OSExchangeData* data_ptr = data.get();
  1048. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  1049. aura::Window* window = widget->GetNativeWindow();
  1050. EXPECT_CALL(observer, OnDragStarted);
  1051. drag_drop_controller_->StartDragAndDrop(
  1052. std::move(data), window->GetRootWindow(), window, gfx::Point(5, 5),
  1053. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kMouse);
  1054. testing::Mock::VerifyAndClearExpectations(&observer);
  1055. ui::MouseEvent e(ui::ET_MOUSE_DRAGGED, gfx::Point(200, 0),
  1056. gfx::Point(200, 0), ui::EventTimeForNow(), ui::EF_NONE,
  1057. ui::EF_NONE);
  1058. {
  1059. testing::InSequence sequence;
  1060. EXPECT_CALL(observer, OnDragUpdated)
  1061. .WillOnce(testing::Invoke([&](const ui::DropTargetEvent& event) {
  1062. gfx::Point root_location_in_screen = event.root_location();
  1063. ::wm::ConvertPointToScreen(
  1064. static_cast<aura::Window*>(event.target())->GetRootWindow(),
  1065. &root_location_in_screen);
  1066. EXPECT_EQ(gfx::Point(200, 0), root_location_in_screen);
  1067. EXPECT_EQ(&event.data(), data_ptr);
  1068. }));
  1069. EXPECT_CALL(observer, OnDragCompleted);
  1070. }
  1071. drag_drop_controller_->Drop(window, e);
  1072. testing::Mock::VerifyAndClearExpectations(&observer);
  1073. }
  1074. drag_drop_controller_->RemoveObserver(&observer);
  1075. }
  1076. TEST_F(DragDropControllerTest, SetEnabled) {
  1077. TestObserver observer;
  1078. drag_drop_controller_->AddObserver(&observer);
  1079. // Data for the drag.
  1080. auto data = CreateDragData(/*with_image=*/false);
  1081. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  1082. aura::Window* window = widget->GetNativeWindow();
  1083. // Cannot start a drag when the controller is disabled.
  1084. drag_drop_controller_->set_enabled(false);
  1085. drag_drop_controller_->StartDragAndDrop(
  1086. std::move(data), window->GetRootWindow(), window, gfx::Point(5, 5),
  1087. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kMouse);
  1088. EXPECT_EQ(TestObserver::State::kNotInvoked, observer.state());
  1089. drag_drop_controller_->RemoveObserver(&observer);
  1090. }
  1091. TEST_F(DragDropControllerTest, EventTarget) {
  1092. std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
  1093. aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), -1,
  1094. gfx::Rect(0, 0, 100, 100)));
  1095. EventTargetTestDelegate delegate(window.get());
  1096. aura::client::SetDragDropDelegate(window.get(), &delegate);
  1097. // Posted task will be run when the inner loop runs in StartDragAndDrop.
  1098. ui::test::EventGenerator generator(window->GetRootWindow(), window.get());
  1099. generator.PressLeftButton();
  1100. // For drag enter
  1101. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1102. FROM_HERE, base::BindOnce(&ui::test::EventGenerator::MoveMouseBy,
  1103. base::Unretained(&generator), 0, 1));
  1104. // For drag update
  1105. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1106. FROM_HERE, base::BindOnce(&ui::test::EventGenerator::MoveMouseBy,
  1107. base::Unretained(&generator), 0, 1));
  1108. // For perform drop
  1109. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1110. FROM_HERE, base::BindOnce(&ui::test::EventGenerator::ReleaseLeftButton,
  1111. base::Unretained(&generator)));
  1112. drag_drop_controller_->set_should_block_during_drag_drop(true);
  1113. auto data = CreateDragData(/*with_image=*/false);
  1114. drag_drop_controller_->StartDragAndDrop(
  1115. std::move(data), window->GetRootWindow(), window.get(), gfx::Point(5, 5),
  1116. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kMouse);
  1117. EXPECT_EQ(EventTargetTestDelegate::State::kPerformDropInvoked,
  1118. delegate.state());
  1119. base::RunLoop().RunUntilIdle();
  1120. }
  1121. // Verifies that a tab drag changes the drag operation to a move.
  1122. TEST_F(DragDropControllerTest, DragTabChangesDragOperationToMove) {
  1123. base::test::ScopedFeatureList feature_list;
  1124. feature_list.InitAndEnableFeature(features::kWebUITabStripTabDragIntegration);
  1125. EXPECT_CALL(*mock_shell_delegate(), IsTabDrag(_))
  1126. .Times(1)
  1127. .WillOnce(Return(true));
  1128. std::unique_ptr<aura::Window> new_window = CreateToplevelTestWindow();
  1129. EXPECT_CALL(*mock_new_window_delegate(), NewWindowForDetachingTab(_, _, _))
  1130. .Times(1)
  1131. .WillOnce(RunOnceCallback<2>(new_window.get()));
  1132. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  1133. aura::Window* window = widget->GetNativeWindow();
  1134. // Posted task will be run when the inner loop runs in StartDragAndDrop.
  1135. ui::test::EventGenerator generator(window->GetRootWindow(), window);
  1136. generator.PressLeftButton();
  1137. // For drag enter.
  1138. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1139. FROM_HERE, base::BindOnce(&ui::test::EventGenerator::MoveMouseBy,
  1140. base::Unretained(&generator), 0, 1));
  1141. // For perform drop.
  1142. base::ThreadTaskRunnerHandle::Get()->PostTask(
  1143. FROM_HERE, base::BindOnce(&ui::test::EventGenerator::ReleaseLeftButton,
  1144. base::Unretained(&generator)));
  1145. drag_drop_controller_->set_should_block_during_drag_drop(true);
  1146. DragOperation operation = drag_drop_controller_->StartDragAndDrop(
  1147. std::make_unique<ui::OSExchangeData>(), window->GetRootWindow(), window,
  1148. gfx::Point(5, 5), ui::DragDropTypes::DRAG_NONE,
  1149. ui::mojom::DragEventSource::kMouse);
  1150. EXPECT_EQ(operation, DragOperation::kMove);
  1151. }
  1152. // Verifies that a tab drag does not crash (UAF) on source window destruction.
  1153. TEST_F(DragDropControllerTest, DragTabDoesNotCrashOnSourceWindowDestruction) {
  1154. base::test::ScopedFeatureList feature_list;
  1155. feature_list.InitAndEnableFeature(features::kWebUITabStripTabDragIntegration);
  1156. EXPECT_CALL(*mock_shell_delegate(), IsTabDrag(_))
  1157. .Times(1)
  1158. .WillOnce(Return(true));
  1159. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  1160. aura::Window* window = widget->GetNativeWindow();
  1161. // Posted task will be run when the inner loop runs in StartDragAndDrop.
  1162. ui::test::EventGenerator generator(window->GetRootWindow(), window);
  1163. generator.PressLeftButton();
  1164. int step = 0;
  1165. drag_drop_controller_->SetLoopClosureForTesting(
  1166. base::BindLambdaForTesting([&]() {
  1167. switch (step++) {
  1168. case 0:
  1169. // For drag enter.
  1170. generator.MoveMouseBy(0, 1);
  1171. break;
  1172. case 1:
  1173. // Forces a |TabDragDropDelegate::source_window_| destruction.
  1174. widget.reset();
  1175. break;
  1176. case 2:
  1177. // For perform more drag and drop.
  1178. generator.ReleaseLeftButton();
  1179. break;
  1180. default:
  1181. NOTREACHED();
  1182. }
  1183. }),
  1184. base::DoNothing());
  1185. DragOperation operation = drag_drop_controller_->StartDragAndDrop(
  1186. std::make_unique<ui::OSExchangeData>(), window->GetRootWindow(), window,
  1187. gfx::Point(5, 5), ui::DragDropTypes::DRAG_NONE,
  1188. ui::mojom::DragEventSource::kMouse);
  1189. EXPECT_EQ(step, 3);
  1190. EXPECT_EQ(operation, DragOperation::kNone);
  1191. }
  1192. TEST_F(DragDropControllerTest, ToplevelWindowDragDelegate) {
  1193. std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
  1194. aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), -1,
  1195. gfx::Rect(0, 0, 100, 100)));
  1196. // Emulate a full drag and drop flow and verify that toplevel window drag
  1197. // delegate gets notified about the events as expected.
  1198. {
  1199. TestToplevelWindowDragDelegate delegate;
  1200. drag_drop_controller_->set_toplevel_window_drag_delegate(&delegate);
  1201. ui::test::EventGenerator generator(window->GetRootWindow(), window.get());
  1202. generator.PressLeftButton();
  1203. auto data(std::make_unique<ui::OSExchangeData>());
  1204. drag_drop_controller_->StartDragAndDrop(
  1205. std::move(data), window->GetRootWindow(), window.get(),
  1206. gfx::Point(5, 5), ui::DragDropTypes::DRAG_MOVE,
  1207. ui::mojom::DragEventSource::kMouse);
  1208. EXPECT_EQ(TestToplevelWindowDragDelegate::State::kDragStartedInvoked,
  1209. delegate.state());
  1210. EXPECT_EQ(ui::mojom::DragEventSource::kMouse, delegate.source());
  1211. EXPECT_TRUE(delegate.current_location().has_value());
  1212. EXPECT_EQ(gfx::PointF(5, 5), *delegate.current_location());
  1213. EXPECT_EQ(0, delegate.events_forwarded());
  1214. generator.MoveMouseBy(1, 1);
  1215. generator.MoveMouseBy(1, 1);
  1216. generator.MoveMouseBy(1, 1);
  1217. generator.MoveMouseBy(1, 1);
  1218. generator.ReleaseLeftButton();
  1219. EXPECT_EQ(TestToplevelWindowDragDelegate::State::kDragDroppedInvoked,
  1220. delegate.state());
  1221. EXPECT_TRUE(delegate.current_location().has_value());
  1222. EXPECT_EQ(gfx::PointF(54, 54), *delegate.current_location());
  1223. EXPECT_EQ(5, delegate.events_forwarded());
  1224. }
  1225. // Emulate a drag session cancellation and verify the toplevel window drag
  1226. // delegate gets notified about the events as expected.
  1227. {
  1228. TestToplevelWindowDragDelegate delegate;
  1229. drag_drop_controller_->set_toplevel_window_drag_delegate(&delegate);
  1230. ui::test::EventGenerator generator(window->GetRootWindow(), window.get());
  1231. generator.PressLeftButton();
  1232. auto data(std::make_unique<ui::OSExchangeData>());
  1233. drag_drop_controller_->StartDragAndDrop(
  1234. std::move(data), window->GetRootWindow(), window.get(),
  1235. gfx::Point(5, 5), ui::DragDropTypes::DRAG_MOVE,
  1236. ui::mojom::DragEventSource::kMouse);
  1237. EXPECT_EQ(TestToplevelWindowDragDelegate::State::kDragStartedInvoked,
  1238. delegate.state());
  1239. EXPECT_EQ(ui::mojom::DragEventSource::kMouse, delegate.source());
  1240. EXPECT_TRUE(delegate.current_location().has_value());
  1241. EXPECT_EQ(gfx::PointF(5, 5), *delegate.current_location());
  1242. EXPECT_EQ(0, delegate.events_forwarded());
  1243. generator.MoveMouseBy(1, 1);
  1244. generator.MoveMouseBy(1, 1);
  1245. generator.PressKey(ui::VKEY_ESCAPE, 0);
  1246. EXPECT_EQ(TestToplevelWindowDragDelegate::State::kDragCancelledInvoked,
  1247. delegate.state());
  1248. EXPECT_TRUE(delegate.current_location().has_value());
  1249. EXPECT_EQ(gfx::PointF(52, 52), *delegate.current_location());
  1250. EXPECT_EQ(2, delegate.events_forwarded());
  1251. }
  1252. // Regression test for https://crbug.com/1280128.
  1253. // With 2 side-by-side displays, ensures that, when ext-dragging a toplevel
  1254. // window from the rightmost display, entering in the leftmost display results
  1255. // in correct mouse (drag update) events being sent over to toplevel window
  1256. // drag delegate, i.e: negative 'x' coordinates.
  1257. {
  1258. UpdateDisplay("800x600,800x600");
  1259. aura::Window::Windows root_windows = Shell::GetAllRootWindows();
  1260. ASSERT_EQ(2u, root_windows.size());
  1261. aura::client::SetDragDropClient(root_windows[0],
  1262. drag_drop_controller_.get());
  1263. aura::client::SetDragDropClient(root_windows[1],
  1264. drag_drop_controller_.get());
  1265. const gfx::Rect bounds_within_root1(0, 0, 800, 600);
  1266. const gfx::Rect bounds_within_root2(800, 0, 800, 600);
  1267. std::unique_ptr<aura::Window> window1 =
  1268. CreateTestWindow(bounds_within_root1);
  1269. std::unique_ptr<aura::Window> window2 =
  1270. CreateTestWindow(bounds_within_root2);
  1271. ASSERT_EQ(root_windows[0], window1->GetRootWindow());
  1272. ASSERT_EQ(root_windows[1], window2->GetRootWindow());
  1273. TestToplevelWindowDragDelegate delegate;
  1274. drag_drop_controller_->set_toplevel_window_drag_delegate(&delegate);
  1275. // Press and hold left mouse button at (0,0) in the rightmost display.
  1276. ui::test::EventGenerator generator(window2->GetRootWindow(), {0, 0});
  1277. generator.PressLeftButton();
  1278. auto data(std::make_unique<ui::OSExchangeData>());
  1279. drag_drop_controller_->StartDragAndDrop(
  1280. std::move(data), window2->GetRootWindow(), window2.get(),
  1281. gfx::Point(5, 5), ui::DragDropTypes::DRAG_MOVE,
  1282. ui::mojom::DragEventSource::kMouse);
  1283. EXPECT_EQ(TestToplevelWindowDragDelegate::State::kDragStartedInvoked,
  1284. delegate.state());
  1285. EXPECT_EQ(ui::mojom::DragEventSource::kMouse, delegate.source());
  1286. EXPECT_TRUE(delegate.current_location().has_value());
  1287. EXPECT_EQ(gfx::PointF(5, 5), *delegate.current_location());
  1288. EXPECT_EQ(0, delegate.events_forwarded());
  1289. // Drag to (790,0) in the root window corresponding to the leftmost display,
  1290. // and ensure that the latest drag event received by toplevel window drag
  1291. // delegate targets (-10, 0) location.
  1292. generator.SetTargetWindow(root_windows[0]);
  1293. generator.MoveMouseTo(gfx::Point(790, 0));
  1294. EXPECT_TRUE(delegate.current_location().has_value());
  1295. EXPECT_EQ(gfx::PointF(-10, 0), *delegate.current_location());
  1296. EXPECT_EQ(1, delegate.events_forwarded());
  1297. generator.ReleaseLeftButton();
  1298. EXPECT_EQ(TestToplevelWindowDragDelegate::State::kDragDroppedInvoked,
  1299. delegate.state());
  1300. EXPECT_EQ(2, delegate.events_forwarded());
  1301. }
  1302. }
  1303. TEST_F(DragDropControllerTest, ToplevelWindowDragDelegateWithTouch) {
  1304. std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
  1305. aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), -1,
  1306. gfx::Rect(0, 0, 100, 100)));
  1307. // Emulate a full drag and drop flow and verify that toplevel window drag
  1308. // delegate gets notified about the events as expected.
  1309. TestToplevelWindowDragDelegate delegate;
  1310. drag_drop_controller_->set_toplevel_window_drag_delegate(&delegate);
  1311. auto data(std::make_unique<ui::OSExchangeData>());
  1312. drag_drop_controller_->StartDragAndDrop(
  1313. std::move(data), window->GetRootWindow(), window.get(), gfx::Point(5, 5),
  1314. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kTouch);
  1315. EXPECT_EQ(TestToplevelWindowDragDelegate::State::kDragStartedInvoked,
  1316. delegate.state());
  1317. EXPECT_EQ(ui::mojom::DragEventSource::kTouch, delegate.source());
  1318. EXPECT_TRUE(delegate.current_location().has_value());
  1319. EXPECT_EQ(gfx::PointF(5, 5), *delegate.current_location());
  1320. EXPECT_EQ(0, delegate.events_forwarded());
  1321. drag_drop_controller_->DragCancel();
  1322. }
  1323. TEST_F(DragDropControllerTest, ToplevelWindowDragDelegateWithTouch2) {
  1324. std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
  1325. aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), -1,
  1326. gfx::Rect(0, 0, 100, 100)));
  1327. // Emulate a full drag and drop flow with touch and verify that toplevel
  1328. // window drag delegate gets notified about the events as expected.
  1329. TestToplevelWindowDragDelegate delegate;
  1330. drag_drop_controller_->set_toplevel_window_drag_delegate(&delegate);
  1331. ui::test::EventGenerator generator(window->GetRootWindow(), window.get());
  1332. generator.PressTouch();
  1333. auto point = gfx::Point(5, 5);
  1334. auto data(std::make_unique<ui::OSExchangeData>());
  1335. drag_drop_controller_->StartDragAndDrop(
  1336. std::move(data), window->GetRootWindow(), window.get(), point,
  1337. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kTouch);
  1338. EXPECT_EQ(TestToplevelWindowDragDelegate::State::kDragStartedInvoked,
  1339. delegate.state());
  1340. EXPECT_EQ(ui::mojom::DragEventSource::kTouch, delegate.source());
  1341. EXPECT_TRUE(delegate.current_location().has_value());
  1342. EXPECT_EQ(gfx::PointF(point), *delegate.current_location());
  1343. EXPECT_EQ(0, delegate.events_forwarded());
  1344. gfx::Point gesture_location = point;
  1345. int num_drags = 5;
  1346. for (int i = 0; i < num_drags; ++i) {
  1347. gesture_location.Offset(1, 1);
  1348. DispatchGesture(ui::ET_GESTURE_SCROLL_UPDATE, gesture_location);
  1349. EXPECT_EQ(i + 1, delegate.events_forwarded());
  1350. }
  1351. DispatchGesture(ui::ET_GESTURE_SCROLL_END, gesture_location);
  1352. EXPECT_EQ(TestToplevelWindowDragDelegate::State::kDragDroppedInvoked,
  1353. delegate.state());
  1354. EXPECT_TRUE(delegate.current_location().has_value());
  1355. EXPECT_EQ(gfx::PointF(10, 10), *delegate.current_location());
  1356. EXPECT_EQ(6, delegate.events_forwarded());
  1357. }
  1358. TEST_F(DragDropControllerTest, DragWithChromeTabDelegateTakesCapture) {
  1359. base::test::ScopedFeatureList feature_list;
  1360. feature_list.InitAndEnableFeature(features::kWebUITabStripTabDragIntegration);
  1361. EXPECT_CALL(*mock_shell_delegate(), IsTabDrag(_))
  1362. .Times(1)
  1363. .WillOnce(Return(true));
  1364. std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
  1365. aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), -1,
  1366. gfx::Rect(0, 0, 100, 100)));
  1367. auto data = CreateDragData(/*with_image=*/true);
  1368. drag_drop_controller_->StartDragAndDrop(
  1369. std::move(data), window->GetRootWindow(), window.get(), gfx::Point(5, 5),
  1370. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kTouch);
  1371. // Should create a captue delegate which takes capture from the window.
  1372. EXPECT_TRUE(drag_drop_controller_->get_capture_delegate());
  1373. drag_drop_controller_.reset();
  1374. }
  1375. // Regression test for crbug.com/1297209.
  1376. // In tablet mode split view, with the browser tab strip on one side and desks
  1377. // overview (or any other window) on the other, touch and hold a desk mini view
  1378. // (or that other window) and drag a browser tab simultaneously.
  1379. TEST_F(DragDropControllerTest, TabletSplitViewDragTwoBrowserTabs) {
  1380. base::test::ScopedFeatureList feature_list;
  1381. feature_list.InitAndEnableFeature(features::kWebUITabStripTabDragIntegration);
  1382. // Enter tablet mode. Avoid TabletModeController::OnGetSwitchStates() from
  1383. // disabling tablet mode.
  1384. base::RunLoop().RunUntilIdle();
  1385. ash::TabletModeControllerTestApi().EnterTabletMode();
  1386. // Enter tablet split view mode by snapping a tab window on each side.
  1387. // A generic top level window is enough to fake a chrome tab.
  1388. std::unique_ptr<aura::Window> tab_window1 = CreateToplevelTestWindow();
  1389. std::unique_ptr<aura::Window> tab_window2 = CreateToplevelTestWindow();
  1390. SplitViewController* const split_view_controller =
  1391. SplitViewController::Get(tab_window1.get());
  1392. split_view_controller->SnapWindow(tab_window1.get(),
  1393. SplitViewController::SnapPosition::LEFT);
  1394. split_view_controller->SnapWindow(tab_window2.get(),
  1395. SplitViewController::SnapPosition::RIGHT);
  1396. EXPECT_TRUE(split_view_controller->InTabletSplitViewMode());
  1397. // Touch and hold the right tab window.
  1398. GetEventGenerator()->PressTouch(
  1399. tab_window2->GetBoundsInScreen().CenterPoint());
  1400. // Prepare to drag the left tab window.
  1401. EXPECT_CALL(*mock_shell_delegate(), IsTabDrag(_)).WillOnce(Return(true));
  1402. // Drag and drop needs a drag image to work.
  1403. auto data = CreateDragData(/*with_image=*/true);
  1404. // Start drag and drop on the left tab window.
  1405. auto drag_operation = drag_drop_controller_->StartDragAndDrop(
  1406. std::move(data), tab_window1->GetRootWindow(), tab_window1.get(),
  1407. tab_window1->GetBoundsInScreen().CenterPoint(),
  1408. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kTouch);
  1409. EXPECT_EQ(drag_operation, DragOperation::kNone);
  1410. EXPECT_FALSE(drag_drop_controller_->IsDragDropInProgress());
  1411. EXPECT_FALSE(drag_drop_controller_->get_capture_delegate());
  1412. EXPECT_FALSE(tab_window1->HasObserver(drag_drop_controller_.get()));
  1413. }
  1414. namespace {
  1415. class MockDataTransferPolicyController
  1416. : public ui::DataTransferPolicyController {
  1417. public:
  1418. MOCK_METHOD3(IsClipboardReadAllowed,
  1419. bool(const ui::DataTransferEndpoint* const data_src,
  1420. const ui::DataTransferEndpoint* const data_dst,
  1421. const absl::optional<size_t> size));
  1422. MOCK_METHOD5(PasteIfAllowed,
  1423. void(const ui::DataTransferEndpoint* const data_src,
  1424. const ui::DataTransferEndpoint* const data_dst,
  1425. const absl::optional<size_t> size,
  1426. content::RenderFrameHost* rfh,
  1427. base::OnceCallback<void(bool)> callback));
  1428. MOCK_METHOD3(DropIfAllowed,
  1429. void(const ui::DataTransferEndpoint* data_src,
  1430. const ui::DataTransferEndpoint* data_dst,
  1431. base::OnceClosure drop_cb));
  1432. };
  1433. } // namespace
  1434. TEST_F(DragDropControllerTest, DlpAllowDragDrop) {
  1435. std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
  1436. aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), -1,
  1437. gfx::Rect(0, 0, 100, 100)));
  1438. EventTargetTestDelegate delegate(window.get());
  1439. aura::client::SetDragDropDelegate(window.get(), &delegate);
  1440. MockDataTransferPolicyController dlp_contoller;
  1441. // Posted task will be run when the inner loop runs in StartDragAndDrop.
  1442. ui::test::EventGenerator generator(window->GetRootWindow(), window.get());
  1443. generator.PressLeftButton();
  1444. auto data = CreateDragData(/*with_image=*/false);
  1445. // Drop.
  1446. EXPECT_CALL(dlp_contoller, DropIfAllowed(_, _, _))
  1447. .WillOnce([&](const ui::DataTransferEndpoint* data_src,
  1448. const ui::DataTransferEndpoint* data_dst,
  1449. base::OnceClosure drop_cb) { std::move(drop_cb).Run(); });
  1450. drag_drop_controller_->StartDragAndDrop(
  1451. std::move(data), window->GetRootWindow(), window.get(), gfx::Point(5, 5),
  1452. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kMouse);
  1453. // For drag enter
  1454. generator.MoveMouseBy(0, 1);
  1455. // For drag update
  1456. generator.MoveMouseBy(0, 1);
  1457. // For perform drop
  1458. generator.ReleaseLeftButton();
  1459. EXPECT_EQ(EventTargetTestDelegate::State::kPerformDropInvoked,
  1460. delegate.state());
  1461. }
  1462. TEST_F(DragDropControllerTest, DlpDisallowDragDrop) {
  1463. std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
  1464. aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), -1,
  1465. gfx::Rect(0, 0, 100, 100)));
  1466. EventTargetTestDelegate delegate(window.get());
  1467. aura::client::SetDragDropDelegate(window.get(), &delegate);
  1468. MockDataTransferPolicyController dlp_contoller;
  1469. // Posted task will be run when the inner loop runs in StartDragAndDrop.
  1470. ui::test::EventGenerator generator(window->GetRootWindow(), window.get());
  1471. generator.PressLeftButton();
  1472. auto data = CreateDragData(/*with_image=*/true);
  1473. EXPECT_CALL(dlp_contoller, DropIfAllowed(_, _, _));
  1474. drag_drop_controller_->StartDragAndDrop(
  1475. std::move(data), window->GetRootWindow(), window.get(), gfx::Point(5, 5),
  1476. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kMouse);
  1477. // For drag enter
  1478. generator.MoveMouseBy(0, 1);
  1479. // For drag update
  1480. generator.MoveMouseBy(0, 1);
  1481. // For perform drop
  1482. generator.ReleaseLeftButton();
  1483. // There is a non-empty drag image, an animation is expected to be run for
  1484. // cancellation.
  1485. EXPECT_TRUE(cancel_animation());
  1486. EXPECT_TRUE(GetDragImageWindow());
  1487. EXPECT_EQ(EventTargetTestDelegate::State::kDragExitInvoked, delegate.state());
  1488. }
  1489. TEST_F(DragDropControllerTest, DlpAsyncDrop) {
  1490. std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
  1491. aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), -1,
  1492. gfx::Rect(0, 0, 100, 100)));
  1493. EventTargetTestDelegate delegate(window.get());
  1494. aura::client::SetDragDropDelegate(window.get(), &delegate);
  1495. MockDataTransferPolicyController dlp_contoller;
  1496. // Posted task will be run when the inner loop runs in StartDragAndDrop.
  1497. ui::test::EventGenerator generator(window->GetRootWindow(), window.get());
  1498. generator.PressLeftButton();
  1499. auto data = CreateDragData(/*with_image=*/true);
  1500. base::OnceClosure drop_callback;
  1501. // Hold Drop.
  1502. EXPECT_CALL(dlp_contoller, DropIfAllowed(_, _, _))
  1503. .WillOnce([&](const ui::DataTransferEndpoint* data_src,
  1504. const ui::DataTransferEndpoint* data_dst,
  1505. base::OnceClosure drop_cb) {
  1506. drop_callback = std::move(drop_cb);
  1507. });
  1508. drag_drop_controller_->StartDragAndDrop(
  1509. std::move(data), window->GetRootWindow(), window.get(), gfx::Point(5, 5),
  1510. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kMouse);
  1511. // For drag enter
  1512. generator.MoveMouseBy(0, 1);
  1513. // For drag update
  1514. generator.MoveMouseBy(0, 1);
  1515. // For perform drop
  1516. generator.ReleaseLeftButton();
  1517. EXPECT_FALSE(cancel_animation());
  1518. EXPECT_FALSE(GetDragImageWindow());
  1519. data = std::make_unique<ui::OSExchangeData>();
  1520. data->SetString(u"I am being dragged 2");
  1521. drag_drop_controller_->StartDragAndDrop(
  1522. std::move(data), window->GetRootWindow(), window.get(), gfx::Point(5, 5),
  1523. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kMouse);
  1524. std::move(drop_callback).Run();
  1525. EXPECT_EQ(EventTargetTestDelegate::State::kDragUpdateInvoked,
  1526. delegate.state());
  1527. }
  1528. TEST_F(DragDropControllerTest, DragImageWidgetNotCreatedIfNoImage) {
  1529. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  1530. aura::Window* window = widget->GetNativeWindow();
  1531. auto data = CreateDragData(/*with_image=*/false);
  1532. drag_drop_controller_->StartDragAndDrop(
  1533. std::move(data), window->GetRootWindow(), window, gfx::Point(5, 5),
  1534. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kMouse);
  1535. EXPECT_FALSE(GetDragImageWindow());
  1536. drag_drop_controller_->DragCancel();
  1537. data = CreateDragData(/*with_image=*/true);
  1538. drag_drop_controller_->StartDragAndDrop(
  1539. std::move(data), window->GetRootWindow(), window, gfx::Point(5, 5),
  1540. ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kMouse);
  1541. EXPECT_TRUE(GetDragImageWindow());
  1542. }
  1543. class MouseOrTouchDragDropControllerTest
  1544. : public DragDropControllerTest,
  1545. public testing::WithParamInterface<bool> {
  1546. public:
  1547. MouseOrTouchDragDropControllerTest() = default;
  1548. MouseOrTouchDragDropControllerTest(
  1549. const MouseOrTouchDragDropControllerTest&) = delete;
  1550. MouseOrTouchDragDropControllerTest& operator=(
  1551. const MouseOrTouchDragDropControllerTest&) = delete;
  1552. ~MouseOrTouchDragDropControllerTest() = default;
  1553. bool IsMouse() const { return GetParam(); }
  1554. void Press(ui::test::EventGenerator& generator) {
  1555. if (IsMouse()) {
  1556. generator.PressLeftButton();
  1557. } else {
  1558. generator.PressTouch();
  1559. // long press requires > 1.15s
  1560. task_environment()->AdvanceClock(base::Seconds(2));
  1561. }
  1562. }
  1563. void MoveBy(ui::test::EventGenerator& generator, int x, int y) {
  1564. if (IsMouse())
  1565. generator.MoveMouseBy(x, y);
  1566. else
  1567. generator.MoveTouchBy(x, y);
  1568. }
  1569. void Release(ui::test::EventGenerator& generator) {
  1570. if (IsMouse())
  1571. generator.ReleaseLeftButton();
  1572. else
  1573. generator.ReleaseTouch();
  1574. }
  1575. };
  1576. // Ensures that the drag drop continues after window destruction.
  1577. TEST_P(MouseOrTouchDragDropControllerTest, WindowDestroyedDuringDragDrop) {
  1578. std::unique_ptr<views::Widget> widget = CreateFramelessWidget();
  1579. DragTestView* drag_view = new DragTestView;
  1580. AddViewToWidgetAndResize(widget.get(), drag_view);
  1581. aura::Window* window = widget->GetNativeView();
  1582. EventTargetTestDelegate delegate(window);
  1583. aura::client::SetDragDropDelegate(window, &delegate);
  1584. ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
  1585. widget->GetNativeView());
  1586. Press(generator);
  1587. int n = 0;
  1588. bool dragged = false;
  1589. auto loop_task = [&](bool inside) {
  1590. MoveBy(generator, 0, 1);
  1591. base::RunLoop().RunUntilIdle();
  1592. n++;
  1593. if (inside && window) {
  1594. dragged = true;
  1595. if (IsMouse()) {
  1596. EXPECT_EQ(window, GetDragWindow());
  1597. EXPECT_GT(n, drag_view->VerticalDragThreshold());
  1598. } else if (n > 5) {
  1599. EXPECT_EQ(window, GetDragWindow());
  1600. }
  1601. }
  1602. if (n == 18) {
  1603. widget->CloseNow();
  1604. EXPECT_FALSE(this->GetDragWindow());
  1605. window = nullptr;
  1606. }
  1607. if (n == 100)
  1608. Release(generator);
  1609. };
  1610. RunWithClosure(base::BindLambdaForTesting(loop_task));
  1611. EXPECT_TRUE(dragged);
  1612. EXPECT_FALSE(GetDragWindow());
  1613. EXPECT_GT(n, 50);
  1614. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  1615. EXPECT_FALSE(drag_drop_controller_->drag_canceled_);
  1616. EXPECT_TRUE(drag_drop_controller_->drop_received_);
  1617. EXPECT_EQ(EventTargetTestDelegate::State::kDragExitInvoked, delegate.state());
  1618. }
  1619. INSTANTIATE_TEST_SUITE_P(All,
  1620. MouseOrTouchDragDropControllerTest,
  1621. testing::Bool());
  1622. namespace {
  1623. class DragDropControllerLongTapCancelTest : public DragDropControllerTest {
  1624. public:
  1625. DragDropControllerLongTapCancelTest(
  1626. const DragDropControllerLongTapCancelTest& other) = delete;
  1627. DragDropControllerLongTapCancelTest& operator=(
  1628. const DragDropControllerLongTapCancelTest& other) = delete;
  1629. protected:
  1630. DragDropControllerLongTapCancelTest() = default;
  1631. ~DragDropControllerLongTapCancelTest() override = default;
  1632. void SetUp() override {
  1633. DragDropControllerTest::SetUp();
  1634. widget_ = CreateFramelessWidget();
  1635. drag_view_ = new DragTestView;
  1636. AddViewToWidgetAndResize(widget_.get(), drag_view_);
  1637. generator_ = std::make_unique<ui::test::EventGenerator>(
  1638. Shell::GetPrimaryRootWindow(), widget_->GetNativeView());
  1639. }
  1640. void IssueLongTap() {
  1641. auto loop_task = [this](bool inside) {
  1642. gfx::Point point = gfx::Rect(drag_view_->bounds()).CenterPoint();
  1643. if (!inside) {
  1644. generator_->PressTouch();
  1645. DispatchGesture(ui::ET_GESTURE_LONG_PRESS, point);
  1646. } else {
  1647. ASSERT_FALSE(inside_loop_task_executed_);
  1648. inside_loop_task_executed_ = true;
  1649. EXPECT_FALSE(drag_view_->long_tap_received_);
  1650. DispatchGesture(ui::ET_GESTURE_LONG_TAP, point);
  1651. }
  1652. };
  1653. RunWithClosure(base::BindLambdaForTesting(loop_task));
  1654. }
  1655. std::unique_ptr<views::Widget> widget_;
  1656. DragTestView* drag_view_ = nullptr;
  1657. std::unique_ptr<ui::test::EventGenerator> generator_;
  1658. bool inside_loop_task_executed_ = false;
  1659. };
  1660. } // namespace
  1661. TEST_F(DragDropControllerLongTapCancelTest, TouchDragDropCancelsOnLongTap) {
  1662. IssueLongTap();
  1663. EXPECT_TRUE(drag_drop_controller_->drag_start_received_);
  1664. EXPECT_TRUE(drag_drop_controller_->drag_canceled_);
  1665. EXPECT_EQ(0, drag_drop_controller_->num_drag_updates_);
  1666. EXPECT_FALSE(drag_drop_controller_->drop_received_);
  1667. EXPECT_EQ(u"I am being dragged", drag_drop_controller_->drag_string_);
  1668. EXPECT_EQ(0, drag_view_->num_drag_enters_);
  1669. EXPECT_EQ(0, drag_view_->num_drops_);
  1670. EXPECT_EQ(0, drag_view_->num_drag_exits_);
  1671. EXPECT_TRUE(drag_view_->drag_done_received_);
  1672. // The long tap gesture is expected to be forwarded after the cancel
  1673. // animation.
  1674. ASSERT_TRUE(cancel_animation());
  1675. EXPECT_FALSE(drag_view_->long_tap_received_);
  1676. CompleteCancelAnimation();
  1677. EXPECT_TRUE(drag_view_->long_tap_received_);
  1678. }
  1679. TEST_F(DragDropControllerLongTapCancelTest,
  1680. LongTapForwardedWithoutCancelAnimation) {
  1681. drag_view_->OmitDragImage();
  1682. // DragDropController does not support touch drag/drop without a drag image,
  1683. // unless it has a non-null |toplevel_window_drag_delegate_|.
  1684. TestToplevelWindowDragDelegate delegate;
  1685. drag_drop_controller_->set_toplevel_window_drag_delegate(&delegate);
  1686. IssueLongTap();
  1687. ASSERT_FALSE(cancel_animation());
  1688. EXPECT_TRUE(drag_view_->long_tap_received_);
  1689. }
  1690. } // namespace ash