123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ash/shelf/shelf_view.h"
- #include <algorithm>
- #include <cmath>
- #include <memory>
- #include <utility>
- #include <vector>
- #include "ash/accessibility/accessibility_controller_impl.h"
- #include "ash/app_list/test/app_list_test_helper.h"
- #include "ash/app_list/views/app_list_view.h"
- #include "ash/constants/ash_features.h"
- #include "ash/display/screen_orientation_controller.h"
- #include "ash/display/screen_orientation_controller_test_api.h"
- #include "ash/focus_cycler.h"
- #include "ash/ime/ime_controller_impl.h"
- #include "ash/public/cpp/shelf_config.h"
- #include "ash/public/cpp/shelf_model.h"
- #include "ash/public/cpp/shelf_prefs.h"
- #include "ash/public/cpp/shell_window_ids.h"
- #include "ash/public/cpp/test/test_shelf_item_delegate.h"
- #include "ash/public/cpp/window_properties.h"
- #include "ash/root_window_controller.h"
- #include "ash/screen_util.h"
- #include "ash/session/session_controller_impl.h"
- #include "ash/shelf/back_button.h"
- #include "ash/shelf/home_button.h"
- #include "ash/shelf/shelf.h"
- #include "ash/shelf/shelf_app_button.h"
- #include "ash/shelf/shelf_focus_cycler.h"
- #include "ash/shelf/shelf_navigation_widget.h"
- #include "ash/shelf/shelf_observer.h"
- #include "ash/shelf/shelf_test_util.h"
- #include "ash/shelf/shelf_tooltip_manager.h"
- #include "ash/shelf/shelf_view_test_api.h"
- #include "ash/shelf/shelf_widget.h"
- #include "ash/shell.h"
- #include "ash/strings/grit/ash_strings.h"
- #include "ash/system/status_area_widget.h"
- #include "ash/test/ash_test_base.h"
- #include "ash/test/ash_test_helper.h"
- #include "ash/test/ui_controls_factory_ash.h"
- #include "ash/utility/haptics_tracking_test_input_controller.h"
- #include "ash/wallpaper/wallpaper_controller_impl.h"
- #include "ash/wallpaper/wallpaper_controller_test_api.h"
- #include "ash/wm/tablet_mode/tablet_mode_controller.h"
- #include "ash/wm/window_state.h"
- #include "base/i18n/rtl.h"
- #include "base/memory/ptr_util.h"
- #include "base/numerics/safe_conversions.h"
- #include "base/run_loop.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/test/icu_test_util.h"
- #include "base/test/metrics/histogram_tester.h"
- #include "base/test/metrics/user_action_tester.h"
- #include "base/test/scoped_feature_list.h"
- #include "base/test/scoped_mock_time_message_loop_task_runner.h"
- #include "base/time/time.h"
- #include "components/prefs/pref_service.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "ui/aura/test/aura_test_base.h"
- #include "ui/aura/window.h"
- #include "ui/aura/window_event_dispatcher.h"
- #include "ui/base/l10n/l10n_util.h"
- #include "ui/base/test/ui_controls.h"
- #include "ui/compositor/layer.h"
- #include "ui/compositor/scoped_animation_duration_scale_mode.h"
- #include "ui/display/display.h"
- #include "ui/display/screen.h"
- #include "ui/display/test/display_manager_test_api.h"
- #include "ui/events/event.h"
- #include "ui/events/event_constants.h"
- #include "ui/events/event_utils.h"
- #include "ui/events/test/event_generator.h"
- #include "ui/events/types/event_type.h"
- #include "ui/gfx/geometry/point.h"
- #include "ui/views/animation/bounds_animator.h"
- #include "ui/views/animation/ink_drop.h"
- #include "ui/views/animation/ink_drop_impl.h"
- #include "ui/views/animation/test/ink_drop_host_view_test_api.h"
- #include "ui/views/animation/test/ink_drop_impl_test_api.h"
- #include "ui/views/bubble/bubble_frame_view.h"
- #include "ui/views/view_model.h"
- #include "ui/views/widget/widget.h"
- #include "ui/views/widget/widget_delegate.h"
- #include "ui/wm/core/coordinate_conversion.h"
- #include "ui/wm/core/window_util.h"
- using testing::ElementsAre;
- using testing::IsEmpty;
- namespace ash {
- namespace {
- // Create a test 1x1 icon image with a given |color|.
- gfx::ImageSkia CreateImageSkiaIcon(SkColor color) {
- SkBitmap bitmap;
- bitmap.allocN32Pixels(1, 1);
- bitmap.eraseColor(color);
- return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
- }
- int64_t GetPrimaryDisplayId() {
- return display::Screen::GetScreen()->GetPrimaryDisplay().id();
- }
- void ExpectFocused(views::View* view) {
- EXPECT_TRUE(view->GetWidget()->IsActive());
- EXPECT_TRUE(view->Contains(view->GetFocusManager()->GetFocusedView()));
- }
- void ExpectNotFocused(views::View* view) {
- EXPECT_FALSE(view->GetWidget()->IsActive());
- EXPECT_FALSE(view->Contains(view->GetFocusManager()->GetFocusedView()));
- }
- class TestShelfObserver : public ShelfObserver {
- public:
- explicit TestShelfObserver(Shelf* shelf) : shelf_(shelf) {
- shelf_->AddObserver(this);
- }
- TestShelfObserver(const TestShelfObserver&) = delete;
- TestShelfObserver& operator=(const TestShelfObserver&) = delete;
- ~TestShelfObserver() override { shelf_->RemoveObserver(this); }
- // ShelfObserver implementation.
- void OnShelfIconPositionsChanged() override {
- icon_positions_changed_ = true;
- icon_positions_animation_duration_ =
- ShelfViewTestAPI(shelf_->GetShelfViewForTesting())
- .GetAnimationDuration();
- }
- bool icon_positions_changed() const { return icon_positions_changed_; }
- void Reset() {
- icon_positions_changed_ = false;
- icon_positions_animation_duration_ = base::TimeDelta();
- }
- base::TimeDelta icon_positions_animation_duration() const {
- return icon_positions_animation_duration_;
- }
- private:
- Shelf* const shelf_;
- bool icon_positions_changed_ = false;
- base::TimeDelta icon_positions_animation_duration_;
- };
- // A ShelfItemDelegate that tracks the last context menu request, and exposes a
- // method tests can use to finish the tracked request.
- class AsyncContextMenuShelfItemDelegate : public ShelfItemDelegate {
- public:
- AsyncContextMenuShelfItemDelegate() : ShelfItemDelegate(ShelfID()) {}
- ~AsyncContextMenuShelfItemDelegate() override = default;
- bool RunPendingContextMenuCallback(
- std::unique_ptr<ui::SimpleMenuModel> model) {
- if (pending_context_menu_callback_.is_null())
- return false;
- std::move(pending_context_menu_callback_).Run(std::move(model));
- return true;
- }
- bool HasPendingContextMenuCallback() const {
- return !pending_context_menu_callback_.is_null();
- }
- private:
- // ShelfItemDelegate:
- void GetContextMenu(int64_t display_id,
- GetContextMenuCallback callback) override {
- ASSERT_TRUE(pending_context_menu_callback_.is_null());
- pending_context_menu_callback_ = std::move(callback);
- }
- void ExecuteCommand(bool, int64_t, int32_t, int64_t) override {}
- void Close() override {}
- GetContextMenuCallback pending_context_menu_callback_;
- };
- } // namespace
- ////////////////////////////////////////////////////////////////////////////////
- // ShelfObserver::OnShelfIconPositionsChanged tests.
- class ShelfObserverIconTest : public AshTestBase {
- public:
- ShelfObserverIconTest() = default;
- ShelfObserverIconTest(const ShelfObserverIconTest&) = delete;
- ShelfObserverIconTest& operator=(const ShelfObserverIconTest&) = delete;
- ~ShelfObserverIconTest() override = default;
- void SetUp() override {
- AshTestBase::SetUp();
- observer_ = std::make_unique<TestShelfObserver>(GetPrimaryShelf());
- shelf_view_test_ = std::make_unique<ShelfViewTestAPI>(
- GetPrimaryShelf()->GetShelfViewForTesting());
- shelf_view_test_->SetAnimationDuration(base::Milliseconds(1));
- }
- void TearDown() override {
- observer_.reset();
- AshTestBase::TearDown();
- }
- TestShelfObserver* observer() { return observer_.get(); }
- ShelfViewTestAPI* shelf_view_test() { return shelf_view_test_.get(); }
- private:
- std::unique_ptr<TestShelfObserver> observer_;
- std::unique_ptr<ShelfViewTestAPI> shelf_view_test_;
- };
- // A ShelfItemDelegate that tracks selections and reports a custom action.
- class ShelfItemSelectionTracker : public ShelfItemDelegate {
- public:
- ShelfItemSelectionTracker() : ShelfItemDelegate(ShelfID()) {}
- ShelfItemSelectionTracker(const ShelfItemSelectionTracker&) = delete;
- ShelfItemSelectionTracker& operator=(const ShelfItemSelectionTracker&) =
- delete;
- ~ShelfItemSelectionTracker() override = default;
- size_t item_selected_count() const { return item_selected_count_; }
- void set_item_selected_action(ShelfAction item_selected_action) {
- item_selected_action_ = item_selected_action;
- }
- // ShelfItemDelegate:
- void ItemSelected(std::unique_ptr<ui::Event> event,
- int64_t display_id,
- ShelfLaunchSource source,
- ItemSelectedCallback callback,
- const ItemFilterPredicate& filter_predicate) override {
- item_selected_count_++;
- std::move(callback).Run(item_selected_action_, {});
- }
- void ExecuteCommand(bool, int64_t, int32_t, int64_t) override {}
- void Close() override {}
- private:
- size_t item_selected_count_ = 0;
- ShelfAction item_selected_action_ = SHELF_ACTION_NONE;
- };
- // A ShelfItemDelegate to generate empty shelf context menu.
- class EmptyContextMenuBuilder : public ShelfItemDelegate {
- public:
- EmptyContextMenuBuilder() : ShelfItemDelegate(ShelfID()) {}
- EmptyContextMenuBuilder(const EmptyContextMenuBuilder&) = delete;
- EmptyContextMenuBuilder& operator=(const EmptyContextMenuBuilder&) = delete;
- ~EmptyContextMenuBuilder() override = default;
- // ShelfItemDelegate:
- void GetContextMenu(int64_t display_id,
- GetContextMenuCallback callback) override {
- std::move(callback).Run(std::make_unique<ui::SimpleMenuModel>(nullptr));
- }
- void ExecuteCommand(bool, int64_t, int32_t, int64_t) override {}
- void Close() override {}
- };
- TEST_F(ShelfObserverIconTest, AddRemove) {
- ShelfItem item;
- item.id = ShelfID("foo");
- item.type = TYPE_APP;
- EXPECT_FALSE(observer()->icon_positions_changed());
- const int shelf_item_index = ShelfModel::Get()->Add(
- item, std::make_unique<TestShelfItemDelegate>(item.id));
- shelf_view_test()->RunMessageLoopUntilAnimationsDone();
- EXPECT_TRUE(observer()->icon_positions_changed());
- observer()->Reset();
- EXPECT_FALSE(observer()->icon_positions_changed());
- ShelfModel::Get()->RemoveItemAt(shelf_item_index);
- shelf_view_test()->RunMessageLoopUntilAnimationsDone();
- EXPECT_TRUE(observer()->icon_positions_changed());
- observer()->Reset();
- }
- // Make sure creating/deleting an window on one displays notifies a
- // shelf on external display as well as one on primary.
- TEST_F(ShelfObserverIconTest, AddRemoveWithMultipleDisplays) {
- UpdateDisplay("500x400,500x400");
- observer()->Reset();
- Shelf* second_shelf = Shelf::ForWindow(Shell::GetAllRootWindows()[1]);
- TestShelfObserver second_observer(second_shelf);
- ShelfViewTestAPI second_shelf_test_api(
- second_shelf->GetShelfViewForTesting());
- ShelfItem item;
- item.id = ShelfID("foo");
- item.type = TYPE_APP;
- EXPECT_FALSE(observer()->icon_positions_changed());
- EXPECT_FALSE(second_observer.icon_positions_changed());
- // Add item and wait for all animations to finish.
- const int shelf_item_index = ShelfModel::Get()->Add(
- item, std::make_unique<TestShelfItemDelegate>(item.id));
- shelf_view_test()->RunMessageLoopUntilAnimationsDone();
- second_shelf_test_api.RunMessageLoopUntilAnimationsDone();
- EXPECT_TRUE(observer()->icon_positions_changed());
- EXPECT_TRUE(second_observer.icon_positions_changed());
- // Reset observer so they can track the next set of animations.
- observer()->Reset();
- ASSERT_FALSE(observer()->icon_positions_changed());
- second_observer.Reset();
- ASSERT_FALSE(second_observer.icon_positions_changed());
- // Remove the item, and wait for all the animations to complete.
- ShelfModel::Get()->RemoveItemAt(shelf_item_index);
- shelf_view_test()->RunMessageLoopUntilAnimationsDone();
- second_shelf_test_api.RunMessageLoopUntilAnimationsDone();
- EXPECT_TRUE(observer()->icon_positions_changed());
- EXPECT_TRUE(second_observer.icon_positions_changed());
- observer()->Reset();
- second_observer.Reset();
- }
- ////////////////////////////////////////////////////////////////////////////////
- // ShelfView tests.
- class ShelfViewTest : public AshTestBase {
- public:
- static const char*
- kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName;
- template <typename... TaskEnvironmentTraits>
- explicit ShelfViewTest(TaskEnvironmentTraits&&... traits)
- : AshTestBase(std::forward<TaskEnvironmentTraits>(traits)...) {}
- ShelfViewTest(const ShelfViewTest&) = delete;
- ShelfViewTest& operator=(const ShelfViewTest&) = delete;
- ~ShelfViewTest() override = default;
- void SetUp() override {
- AshTestBase::SetUp();
- haptics_tracker_ = std::make_unique<HapticsTrackingTestInputController>();
- model_ = ShelfModel::Get();
- shelf_view_ = GetPrimaryShelf()->GetShelfViewForTesting();
- navigation_view_ = GetPrimaryShelf()
- ->shelf_widget()
- ->navigation_widget()
- ->GetContentsView();
- gfx::NativeWindow window = shelf_view_->shelf_widget()->GetNativeWindow();
- status_area_ = RootWindowController::ForWindow(window)
- ->GetStatusAreaWidget()
- ->GetContentsView();
- // The bounds should be big enough for 4 buttons.
- ASSERT_GE(GetPrimaryShelf()
- ->shelf_widget()
- ->hotseat_widget()
- ->GetWindowBoundsInScreen()
- .width(),
- 500);
- test_api_ = std::make_unique<ShelfViewTestAPI>(shelf_view_);
- test_api_->SetAnimationDuration(base::Milliseconds(1));
- // Add a browser shortcut shelf item, as chrome does, for testing.
- AddItem(TYPE_BROWSER_SHORTCUT, true);
- }
- void TearDown() override {
- test_api_.reset();
- haptics_tracker_.reset();
- AshTestBase::TearDown();
- }
- std::string GetNextAppId() const { return base::NumberToString(id_); }
- protected:
- // Add shelf items of various types, and optionally wait for animations.
- ShelfID AddItem(ShelfItemType type, bool wait_for_animations) {
- ShelfItem item = ShelfTestUtil::AddAppShortcutWithIcon(
- base::NumberToString(id_++), type, CreateImageSkiaIcon(SK_ColorRED));
- // Set a delegate; some tests require one to select the item.
- model_->ReplaceShelfItemDelegate(
- item.id, std::make_unique<ShelfItemSelectionTracker>());
- if (wait_for_animations)
- test_api_->RunMessageLoopUntilAnimationsDone();
- return item.id;
- }
- ShelfID AddAppShortcut() { return AddItem(TYPE_PINNED_APP, true); }
- ShelfID AddAppNoWait() { return AddItem(TYPE_APP, false); }
- ShelfID AddApp() { return AddItem(TYPE_APP, true); }
- void SetShelfItemTypeToAppShortcut(const ShelfID& id) {
- int index = model_->ItemIndexByID(id);
- DCHECK_GE(index, 0);
- ShelfItem item = model_->items()[index];
- if (item.type == TYPE_APP) {
- item.type = TYPE_PINNED_APP;
- model_->Set(index, item);
- }
- test_api_->RunMessageLoopUntilAnimationsDone();
- }
- void RemoveByID(const ShelfID& id) {
- model_->RemoveItemAt(model_->ItemIndexByID(id));
- test_api_->RunMessageLoopUntilAnimationsDone();
- }
- ShelfAppButton* GetButtonByID(const ShelfID& id) {
- return test_api_->GetButton(model_->ItemIndexByID(id));
- }
- ShelfItem GetItemByID(const ShelfID& id) { return *model_->ItemByID(id); }
- bool IsAppPinned(const ShelfID& id) const {
- return model_->IsAppPinned(id.app_id);
- }
- void CheckModelIDs(
- const std::vector<std::pair<ShelfID, views::View*>>& id_map) {
- size_t map_index = 0;
- for (size_t model_index = 0; model_index < model_->items().size();
- ++model_index) {
- ShelfItem item = model_->items()[model_index];
- ShelfID id = item.id;
- EXPECT_EQ(id_map[map_index].first, id);
- ++map_index;
- }
- ASSERT_EQ(map_index, id_map.size());
- }
- void VerifyShelfItemBoundsAreValid() {
- for (int i : shelf_view_->visible_views_indices()) {
- if (test_api_->GetButton(i)) {
- gfx::Rect shelf_view_bounds = shelf_view_->GetLocalBounds();
- gfx::Rect item_bounds = test_api_->GetBoundsByIndex(i);
- EXPECT_GE(item_bounds.x(), 0);
- EXPECT_GE(item_bounds.y(), 0);
- EXPECT_LE(item_bounds.right(), shelf_view_bounds.width());
- EXPECT_LE(item_bounds.bottom(), shelf_view_bounds.height());
- }
- }
- }
- // Simulate a mouse press event on the shelf's view at |view_index|.
- views::View* SimulateViewPressed(ShelfView::Pointer pointer, int view_index) {
- views::View* view = test_api_->GetViewAt(view_index);
- ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(),
- view->GetBoundsInScreen().origin(),
- ui::EventTimeForNow(), 0, 0);
- shelf_view_->PointerPressedOnButton(view, pointer, pressed_event);
- return view;
- }
- // Similar to SimulateViewPressed, but the index must not be for the app list,
- // since the home button is not a ShelfAppButton.
- ShelfAppButton* SimulateButtonPressed(ShelfView::Pointer pointer,
- int button_index) {
- ShelfAppButton* button = test_api_->GetButton(button_index);
- EXPECT_EQ(button, SimulateViewPressed(pointer, button_index));
- return button;
- }
- // Simulates a single mouse click.
- void SimulateClick(int button_index) {
- ShelfAppButton* button =
- SimulateButtonPressed(ShelfView::MOUSE, button_index);
- ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, gfx::Point(),
- button->GetBoundsInScreen().origin(),
- ui::EventTimeForNow(), 0, 0);
- button->NotifyClick(release_event);
- button->OnMouseReleased(release_event);
- }
- // Simulates the second click of a double click.
- void SimulateDoubleClick(int button_index) {
- ShelfAppButton* button =
- SimulateButtonPressed(ShelfView::MOUSE, button_index);
- ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, gfx::Point(),
- button->GetBoundsInScreen().origin(),
- ui::EventTimeForNow(), ui::EF_IS_DOUBLE_CLICK,
- 0);
- button->NotifyClick(release_event);
- button->OnMouseReleased(release_event);
- }
- void DoDrag(int dist_x,
- int dist_y,
- views::View* button,
- ShelfView::Pointer pointer,
- views::View* to) {
- ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, gfx::Point(dist_x, dist_y),
- to->GetBoundsInScreen().origin(),
- ui::EventTimeForNow(), 0, 0);
- shelf_view_->PointerDraggedOnButton(button, pointer, drag_event);
- }
- /*
- * Trigger ContinueDrag of the shelf
- * The argument progressively means whether to simulate the drag progress (a
- * series of changes of the posistion of dragged item), like the normal user
- * drag behavior.
- */
- void ContinueDrag(views::View* button,
- ShelfView::Pointer pointer,
- int from_index,
- int to_index,
- bool progressively) {
- views::View* to = test_api_->GetViewAt(to_index);
- views::View* from = test_api_->GetViewAt(from_index);
- gfx::Rect to_rect = to->GetMirroredBounds();
- gfx::Rect from_rect = from->GetMirroredBounds();
- int dist_x = to_rect.x() - from_rect.x();
- int dist_y = to_rect.y() - from_rect.y();
- if (progressively) {
- int sgn = dist_x > 0 ? 1 : -1;
- dist_x = abs(dist_x);
- for (; dist_x; dist_x -= std::min(10, dist_x))
- DoDrag(sgn * std::min(10, abs(dist_x)), 0, button, pointer, to);
- } else {
- DoDrag(dist_x, dist_y, button, pointer, to);
- }
- }
- /*
- * Simulate drag operation.
- * Argument progressively means whether to simulate the drag progress (a
- * series of changes of the posistion of dragged item) like the behavior of
- * user drags.
- */
- views::View* SimulateDrag(ShelfView::Pointer pointer,
- int button_index,
- int destination_index,
- bool progressively) {
- views::View* button = SimulateViewPressed(pointer, button_index);
- if (!progressively) {
- ContinueDrag(button, pointer, button_index, destination_index, false);
- } else if (button_index < destination_index) {
- for (int cur_index = button_index + 1; cur_index <= destination_index;
- cur_index++)
- ContinueDrag(button, pointer, cur_index - 1, cur_index, true);
- } else if (button_index > destination_index) {
- for (int cur_index = button_index - 1; cur_index >= destination_index;
- cur_index--)
- ContinueDrag(button, pointer, cur_index + 1, cur_index, true);
- }
- return button;
- }
- void DragAndVerify(
- int from,
- int to,
- ShelfView* shelf_view,
- const std::vector<std::pair<ShelfID, views::View*>>& expected_id_map) {
- views::View* dragged_button =
- SimulateDrag(ShelfView::MOUSE, from, to, true);
- shelf_view->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE,
- false);
- test_api_->RunMessageLoopUntilAnimationsDone();
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(expected_id_map));
- }
- void SetupForDragTest(std::vector<std::pair<ShelfID, views::View*>>* id_map) {
- // Initialize |id_map| with the automatically-created shelf buttons.
- for (size_t i = 0; i < model_->items().size(); ++i) {
- ShelfAppButton* button = test_api_->GetButton(i);
- id_map->push_back(std::make_pair(model_->items()[i].id, button));
- }
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(*id_map));
- // Add 5 app shelf buttons for testing.
- for (int i = 0; i < 5; ++i) {
- ShelfID id = AddAppShortcut();
- // The browser shortcut is located at index 0. So we should start to add
- // app shortcuts at index 1.
- id_map->insert(id_map->begin() + i + 1,
- std::make_pair(id, GetButtonByID(id)));
- }
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(*id_map));
- }
- // Returns the item's ShelfID at |index|.
- ShelfID GetItemId(int index) const {
- DCHECK_GE(index, 0);
- return model_->items()[index].id;
- }
- // Returns the center point of a button. Helper function for event generators.
- gfx::Point GetButtonCenter(const ShelfID& button_id) {
- return GetButtonCenter(GetButtonByID(button_id));
- }
- gfx::Point GetButtonCenter(const ShelfAppButton* button) {
- return button->GetBoundsInScreen().CenterPoint();
- }
- int GetHapticTickEventsCount() const {
- return haptics_tracker_->GetSentHapticCount(
- ui::HapticTouchpadEffect::kTick,
- ui::HapticTouchpadEffectStrength::kMedium);
- }
- ShelfModel* model_ = nullptr;
- ShelfView* shelf_view_ = nullptr;
- views::View* navigation_view_ = nullptr;
- views::View* status_area_ = nullptr;
- int id_ = 0;
- // Used to track haptics events sent during drag.
- std::unique_ptr<HapticsTrackingTestInputController> haptics_tracker_;
- std::unique_ptr<ShelfViewTestAPI> test_api_;
- };
- class LtrRtlShelfViewTest : public ShelfViewTest,
- public testing::WithParamInterface<bool> {
- public:
- LtrRtlShelfViewTest() : scoped_locale_(GetParam() ? "he" : "") {}
- LtrRtlShelfViewTest(const LtrRtlShelfViewTest&) = delete;
- LtrRtlShelfViewTest& operator=(const LtrRtlShelfViewTest&) = delete;
- ~LtrRtlShelfViewTest() override = default;
- bool IsRtlEnabled() const { return GetParam(); }
- private:
- // Restores locale to the default when destructor is called.
- base::test::ScopedRestoreICUDefaultLocale scoped_locale_;
- };
- INSTANTIATE_TEST_SUITE_P(All, LtrRtlShelfViewTest, testing::Bool());
- const char*
- ShelfViewTest::kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName =
- ShelfButtonPressedMetricTracker::
- kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName;
- class ShelfViewDragToPinTest : public ShelfViewTest {
- public:
- ShelfViewDragToPinTest() {
- feature_list_.InitAndEnableFeature(features::kDragUnpinnedAppToPin);
- }
- ~ShelfViewDragToPinTest() override = default;
- private:
- base::test::ScopedFeatureList feature_list_;
- };
- TEST_P(LtrRtlShelfViewTest, VisibleShelfItemsBounds) {
- // Add 3 pinned apps, and a normal app.
- AddAppShortcut();
- AddAppShortcut();
- AddAppShortcut();
- const auto app_id = AddApp();
- EXPECT_EQ(static_cast<size_t>(model_->item_count()),
- shelf_view_->number_of_visible_apps());
- const gfx::Rect visible_items_bounds =
- test_api_->visible_shelf_item_bounds_union();
- // Pin the app with `app_id` and expect that the visible items bounds union
- // remains the same.
- SetShelfItemTypeToAppShortcut(app_id);
- EXPECT_EQ(static_cast<size_t>(model_->item_count()),
- shelf_view_->number_of_visible_apps());
- EXPECT_EQ(visible_items_bounds, test_api_->visible_shelf_item_bounds_union());
- }
- // Checks that shelf view contents are considered in the correct drag group.
- TEST_P(LtrRtlShelfViewTest, EnforceDragType) {
- EXPECT_TRUE(test_api_->SameDragType(TYPE_APP, TYPE_APP));
- EXPECT_FALSE(test_api_->SameDragType(TYPE_APP, TYPE_PINNED_APP));
- EXPECT_FALSE(test_api_->SameDragType(TYPE_APP, TYPE_BROWSER_SHORTCUT));
- EXPECT_FALSE(
- test_api_->SameDragType(TYPE_APP, TYPE_UNPINNED_BROWSER_SHORTCUT));
- EXPECT_TRUE(test_api_->SameDragType(TYPE_PINNED_APP, TYPE_PINNED_APP));
- EXPECT_TRUE(test_api_->SameDragType(TYPE_PINNED_APP, TYPE_BROWSER_SHORTCUT));
- EXPECT_FALSE(
- test_api_->SameDragType(TYPE_PINNED_APP, TYPE_UNPINNED_BROWSER_SHORTCUT));
- EXPECT_TRUE(
- test_api_->SameDragType(TYPE_BROWSER_SHORTCUT, TYPE_BROWSER_SHORTCUT));
- EXPECT_TRUE(test_api_->SameDragType(TYPE_UNPINNED_BROWSER_SHORTCUT,
- TYPE_UNPINNED_BROWSER_SHORTCUT));
- // No test for TYPE_BROWSER_SHORTCUT and TYPE_UNPINNED_BROWSER_SHORTCUT,
- // because they should be mutually exclusive.
- }
- // Check that model changes are handled correctly while a shelf icon is being
- // dragged.
- TEST_P(LtrRtlShelfViewTest, ModelChangesWhileDragging) {
- std::vector<std::pair<ShelfID, views::View*>> id_map;
- SetupForDragTest(&id_map);
- // Dragging browser shortcut at index 1.
- EXPECT_TRUE(model_->items()[0].type == TYPE_BROWSER_SHORTCUT);
- views::View* dragged_button = SimulateDrag(ShelfView::MOUSE, 0, 2, false);
- EXPECT_EQ(1, GetHapticTickEventsCount());
- std::rotate(id_map.begin(), id_map.begin() + 1, id_map.begin() + 3);
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, false);
- EXPECT_EQ(1, GetHapticTickEventsCount());
- EXPECT_TRUE(model_->items()[2].type == TYPE_BROWSER_SHORTCUT);
- test_api_->RunMessageLoopUntilAnimationsDone();
- // Dragging changes model order.
- dragged_button = SimulateDrag(ShelfView::MOUSE, 0, 2, false);
- EXPECT_EQ(2, GetHapticTickEventsCount());
- std::rotate(id_map.begin(), id_map.begin() + 1, id_map.begin() + 3);
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- // Cancelling the drag operation restores previous order.
- shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, true);
- test_api_->RunMessageLoopUntilAnimationsDone();
- EXPECT_EQ(2, GetHapticTickEventsCount());
- std::rotate(id_map.begin(), id_map.begin() + 2, id_map.begin() + 3);
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- // Deleting an item keeps the remaining intact.
- dragged_button = SimulateDrag(ShelfView::MOUSE, 0, 2, false);
- EXPECT_EQ(3, GetHapticTickEventsCount());
- // The dragged view has been moved to index 2 during drag.
- std::rotate(id_map.begin(), id_map.begin() + 1, id_map.begin() + 3);
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- model_->RemoveItemAt(2);
- id_map.erase(id_map.begin() + 2);
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, false);
- // Waits until app removal animation finishes.
- test_api_->RunMessageLoopUntilAnimationsDone();
- // Adding a shelf item cancels the drag and respects the order.
- dragged_button = SimulateDrag(ShelfView::MOUSE, 0, 2, false);
- EXPECT_EQ(4, GetHapticTickEventsCount());
- ShelfID new_id = AddAppShortcut();
- id_map.insert(id_map.begin() + 5,
- std::make_pair(new_id, GetButtonByID(new_id)));
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, false);
- EXPECT_EQ(4, GetHapticTickEventsCount());
- }
- // Check that 2nd drag from the other pointer would be ignored.
- TEST_P(LtrRtlShelfViewTest, SimultaneousDrag) {
- std::vector<std::pair<ShelfID, views::View*>> id_map;
- SetupForDragTest(&id_map);
- // Start a mouse drag.
- views::View* dragged_button_mouse =
- SimulateDrag(ShelfView::MOUSE, 2, 4, false);
- EXPECT_EQ(1, GetHapticTickEventsCount());
- std::rotate(id_map.begin() + 2, id_map.begin() + 3, id_map.begin() + 5);
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- // Attempt a touch drag before the mouse drag finishes.
- views::View* dragged_button_touch =
- SimulateDrag(ShelfView::TOUCH, 5, 3, false);
- EXPECT_EQ(1, GetHapticTickEventsCount());
- // Nothing changes since 2nd drag is ignored.
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- // Finish the mouse drag.
- shelf_view_->PointerReleasedOnButton(dragged_button_mouse, ShelfView::MOUSE,
- false);
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- // Now start a touch drag.
- dragged_button_touch = SimulateDrag(ShelfView::TOUCH, 5, 3, false);
- std::rotate(id_map.begin() + 4, id_map.begin() + 5, id_map.begin() + 6);
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- // And attempt a mouse drag before the touch drag finishes.
- dragged_button_mouse = SimulateDrag(ShelfView::MOUSE, 2, 3, false);
- // Nothing changes since 2nd drag is ignored.
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- shelf_view_->PointerReleasedOnButton(dragged_button_touch, ShelfView::TOUCH,
- false);
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- EXPECT_EQ(1, GetHapticTickEventsCount());
- }
- // Ensure that the behavior of pinning and unpinning by dragging works as
- // expected.
- TEST_F(ShelfViewDragToPinTest, DragAppsToPinAndUnpin) {
- std::vector<std::pair<ShelfID, views::View*>> id_map;
- SetupForDragTest(&id_map);
- size_t pinned_apps_size = id_map.size();
- const ShelfID open_app_id = AddApp();
- id_map.emplace_back(open_app_id, GetButtonByID(open_app_id));
- // Run the pinned app at index 1.
- ShelfItem item = model_->items()[1];
- item.status = STATUS_RUNNING;
- model_->Set(1, item);
- id_map[1].second = GetButtonByID(item.id);
- ASSERT_TRUE(static_cast<ShelfAppButton*>(id_map[1].second)->state() &
- ShelfAppButton::STATE_RUNNING);
- ASSERT_FALSE(static_cast<ShelfAppButton*>(id_map[2].second)->state() &
- ShelfAppButton::STATE_RUNNING);
- ASSERT_TRUE(GetButtonByID(open_app_id)->state() &
- ShelfAppButton::STATE_RUNNING);
- EXPECT_EQ(test_api_->GetSeparatorIndex(), pinned_apps_size - 1);
- // Drag the app at index 1 and move it to the end of the shelf. With separator
- // available and the app is dragged to the unpinned app side, the dragged open
- // app should be unpinned and moved to the released position.
- views::View* dragged_button =
- SimulateDrag(ShelfView::MOUSE, 1, id_map.size() - 1, false);
- EXPECT_EQ(1, GetHapticTickEventsCount());
- std::rotate(id_map.begin() + 1, id_map.begin() + 2, id_map.end());
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, false);
- test_api_->RunMessageLoopUntilAnimationsDone();
- EXPECT_EQ(1, GetHapticTickEventsCount());
- EXPECT_FALSE(IsAppPinned(id_map.back().first));
- --pinned_apps_size;
- // Drag the app at index 2 and move it to the end of the shelf. With separator
- // available and the app is dragged to the unpinned app side, the dragged app
- // with no running instance should be unpinned and removed from shelf.
- dragged_button = SimulateDrag(ShelfView::MOUSE, 2, id_map.size() - 1, false);
- EXPECT_EQ(2, GetHapticTickEventsCount());
- shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, false);
- id_map.erase(id_map.begin() + 2);
- EXPECT_EQ(id_map.size(), model_->items().size());
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- --pinned_apps_size;
- EXPECT_EQ(2, GetHapticTickEventsCount());
- // Drag an app in unpinned app side and move it to the beginning of the shelf.
- // With separator available and the app is dragged to the pinned app side, the
- // dragged app should be pinned and moved to the released position.
- dragged_button = SimulateDrag(ShelfView::MOUSE, id_map.size() - 2, 0, false);
- EXPECT_EQ(3, GetHapticTickEventsCount());
- std::rotate(id_map.rbegin() + 1, id_map.rbegin() + 2, id_map.rend());
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, false);
- test_api_->RunMessageLoopUntilAnimationsDone();
- EXPECT_EQ(3, GetHapticTickEventsCount());
- EXPECT_TRUE(IsAppPinned(id_map[0].first));
- ++pinned_apps_size;
- EXPECT_EQ(test_api_->GetSeparatorIndex(), pinned_apps_size - 1);
- }
- // Check that the Browser Shortcut will not be dragged to the unpinned app side
- // or be unpinned by dragging.
- TEST_F(ShelfViewDragToPinTest, BlockBrowserShortcutFromUnpinningByDragging) {
- std::vector<std::pair<ShelfID, views::View*>> id_map;
- SetupForDragTest(&id_map);
- const size_t pinned_apps_size = id_map.size();
- const ShelfID open_app_id = AddApp();
- id_map.emplace_back(open_app_id, GetButtonByID(open_app_id));
- EXPECT_TRUE(model_->items()[0].type == TYPE_BROWSER_SHORTCUT);
- EXPECT_EQ(test_api_->GetSeparatorIndex(), pinned_apps_size - 1);
- // Dragging the browser shortcut to the unpinned app side should not make it
- // unpinned.
- views::View* dragged_button =
- SimulateDrag(ShelfView::MOUSE, 0, id_map.size() - 1, false);
- EXPECT_EQ(1, GetHapticTickEventsCount());
- std::rotate(id_map.begin(), id_map.begin() + 1,
- id_map.begin() + pinned_apps_size);
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- // When drag pointer released, the browser shortcut should be the last app in
- // the pinned app side.
- shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, false);
- EXPECT_EQ(model_->items()[pinned_apps_size - 1].type, TYPE_BROWSER_SHORTCUT);
- EXPECT_EQ(1, GetHapticTickEventsCount());
- }
- // Check that separator index updates as expected when a drag view is dragged
- // over it.
- TEST_F(ShelfViewDragToPinTest, DragAppAroundSeparator) {
- std::vector<std::pair<ShelfID, views::View*>> id_map;
- SetupForDragTest(&id_map);
- const size_t pinned_apps_size = id_map.size();
- const ShelfID open_app_id = AddApp();
- id_map.emplace_back(open_app_id, GetButtonByID(open_app_id));
- EXPECT_EQ(test_api_->GetSeparatorIndex(), pinned_apps_size - 1);
- const int button_width =
- GetButtonByID(open_app_id)->GetBoundsInScreen().width();
- ui::test::EventGenerator* generator = GetEventGenerator();
- // The test makes some assumptions that the shelf is bottom aligned.
- ASSERT_EQ(shelf_view_->shelf()->alignment(), ShelfAlignment::kBottom);
- // Drag an unpinned open app that is beside the separator around and check
- // that the separator is correctly placed.
- ASSERT_EQ(static_cast<size_t>(model_->ItemIndexByID(open_app_id)),
- test_api_->GetSeparatorIndex().value() + 1);
- gfx::Point unpinned_app_location =
- GetButtonCenter(GetButtonByID(open_app_id));
- generator->set_current_screen_location(unpinned_app_location);
- generator->PressLeftButton();
- // Drag the mouse slightly to the left. The dragged app will stay at the same
- // index but the separator will move to the right.
- generator->MoveMouseBy(-button_width / 4, 0);
- EXPECT_EQ(1, GetHapticTickEventsCount());
- // In this case, the separator is moved to the end of the shelf so it is set
- // invisible and the |separator_index_| will be updated to nullopt.
- EXPECT_FALSE(test_api_->IsSeparatorVisible());
- EXPECT_FALSE(test_api_->GetSeparatorIndex().has_value());
- // Drag the mouse slightly to the right where the dragged app will stay at the
- // same index.
- generator->MoveMouseBy(button_width / 2, 0);
- // In this case, because the dragged app is not released or pinned yet,
- // dragging it back to its original place will show the separator again.
- EXPECT_EQ(test_api_->GetSeparatorIndex(), pinned_apps_size - 1);
- generator->ReleaseLeftButton();
- EXPECT_EQ(1, GetHapticTickEventsCount());
- // Drag an pinned app that is beside the separator around and check that the
- // separator is correctly placed. Check that the dragged app is not a browser
- // shortcut, which can not be dragged across the separator.
- ASSERT_NE(model_->items()[pinned_apps_size - 1].type, TYPE_BROWSER_SHORTCUT);
- ASSERT_EQ(static_cast<size_t>(
- model_->ItemIndexByID(id_map[pinned_apps_size - 1].first)),
- test_api_->GetSeparatorIndex());
- gfx::Point pinned_app_location =
- GetButtonCenter(id_map[pinned_apps_size - 1].first);
- generator->set_current_screen_location(pinned_app_location);
- generator->PressLeftButton();
- // Drag the mouse slightly to the right. The dragged app will stay at the same
- // index but the separator will move to the left.
- generator->MoveMouseBy(button_width / 4, 0);
- EXPECT_EQ(2, GetHapticTickEventsCount());
- EXPECT_EQ(test_api_->GetSeparatorIndex(), pinned_apps_size - 2);
- // Drag the mouse slightly to the left. The dragged app will stay at the same
- // index but the separator will move to the right.
- generator->MoveMouseBy(-button_width / 2, 0);
- EXPECT_EQ(test_api_->GetSeparatorIndex(), pinned_apps_size - 1);
- generator->ReleaseLeftButton();
- EXPECT_EQ(2, GetHapticTickEventsCount());
- }
- // Ensure that clicking on one item and then dragging another works as expected.
- TEST_P(LtrRtlShelfViewTest, ClickOneDragAnother) {
- std::vector<std::pair<ShelfID, views::View*>> id_map;
- SetupForDragTest(&id_map);
- // A click on the item at index 1 is simulated.
- SimulateClick(1);
- // Dragging the browser item at index 0 should change the model order.
- EXPECT_TRUE(model_->items()[0].type == TYPE_BROWSER_SHORTCUT);
- views::View* dragged_button = SimulateDrag(ShelfView::MOUSE, 0, 2, false);
- EXPECT_EQ(1, GetHapticTickEventsCount());
- std::rotate(id_map.begin(), id_map.begin() + 1, id_map.begin() + 3);
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, false);
- EXPECT_TRUE(model_->items()[2].type == TYPE_BROWSER_SHORTCUT);
- EXPECT_EQ(1, GetHapticTickEventsCount());
- }
- // Tests that double-clicking an item does not activate it twice.
- TEST_P(LtrRtlShelfViewTest, ClickingTwiceActivatesOnce) {
- // Watch for selection of the browser shortcut.
- ShelfItemSelectionTracker* selection_tracker = new ShelfItemSelectionTracker;
- model_->ReplaceShelfItemDelegate(model_->items()[0].id,
- base::WrapUnique(selection_tracker));
- // A single click selects the item, but a double-click does not.
- EXPECT_EQ(0u, selection_tracker->item_selected_count());
- SimulateClick(0);
- EXPECT_EQ(1u, selection_tracker->item_selected_count());
- SimulateDoubleClick(0);
- EXPECT_EQ(1u, selection_tracker->item_selected_count());
- EXPECT_EQ(0, GetHapticTickEventsCount());
- }
- // Check that very small mouse drags do not prevent shelf item selection.
- TEST_P(LtrRtlShelfViewTest, ClickAndMoveSlightly) {
- std::vector<std::pair<ShelfID, views::View*>> id_map;
- SetupForDragTest(&id_map);
- ShelfID shelf_id = (id_map.begin() + 2)->first;
- views::View* button = (id_map.begin() + 2)->second;
- // Install a ShelfItemDelegate that tracks when the shelf item is selected.
- ShelfItemSelectionTracker* selection_tracker = new ShelfItemSelectionTracker;
- model_->ReplaceShelfItemDelegate(
- shelf_id, base::WrapUnique<ShelfItemSelectionTracker>(selection_tracker));
- gfx::Vector2d press_offset(5, 30);
- gfx::Point press_location = gfx::Point() + press_offset;
- gfx::Point press_location_in_screen =
- button->GetBoundsInScreen().origin() + press_offset;
- ui::MouseEvent click_event(ui::ET_MOUSE_PRESSED, press_location,
- press_location_in_screen, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMousePressed(click_event);
- EXPECT_EQ(0u, selection_tracker->item_selected_count());
- ui::MouseEvent drag_event1(
- ui::ET_MOUSE_DRAGGED, press_location + gfx::Vector2d(0, 1),
- press_location_in_screen + gfx::Vector2d(0, 1), ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMouseDragged(drag_event1);
- ui::MouseEvent drag_event2(
- ui::ET_MOUSE_DRAGGED, press_location + gfx::Vector2d(-1, 0),
- press_location_in_screen + gfx::Vector2d(-1, 0), ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMouseDragged(drag_event2);
- EXPECT_EQ(0u, selection_tracker->item_selected_count());
- ui::MouseEvent release_event(
- ui::ET_MOUSE_RELEASED, press_location + gfx::Vector2d(-1, 0),
- press_location_in_screen + gfx::Vector2d(-1, 0), ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMouseReleased(release_event);
- EXPECT_EQ(1u, selection_tracker->item_selected_count());
- EXPECT_EQ(0, GetHapticTickEventsCount());
- }
- // Confirm that item status changes are reflected in the buttons.
- TEST_P(LtrRtlShelfViewTest, ShelfItemStatus) {
- // All buttons should be visible.
- ASSERT_EQ(test_api_->GetButtonCount(), shelf_view_->number_of_visible_apps());
- // Add platform app button.
- ShelfID last_added = AddApp();
- ShelfItem item = GetItemByID(last_added);
- int index = model_->ItemIndexByID(last_added);
- ShelfAppButton* button = GetButtonByID(last_added);
- ASSERT_EQ(ShelfAppButton::STATE_RUNNING, button->state());
- item.status = STATUS_ATTENTION;
- model_->Set(index, item);
- ASSERT_EQ(ShelfAppButton::STATE_ATTENTION, button->state());
- }
- // Test what drag movements will rip an item off the shelf.
- TEST_P(LtrRtlShelfViewTest, ShelfRipOff) {
- ui::test::EventGenerator* generator = GetEventGenerator();
- // The test makes some assumptions that the shelf is bottom aligned.
- ASSERT_EQ(shelf_view_->shelf()->alignment(), ShelfAlignment::kBottom);
- // The rip off threshold. Taken from |kRipOffDistance| in shelf_view.cc.
- const int kRipOffDistance = 48;
- // Add two apps on the main shelf.
- ShelfID first_app_id = AddAppShortcut();
- ShelfID second_app_id = AddAppShortcut();
- // Verify that dragging an app off the shelf will trigger the app getting
- // ripped off, unless the distance is less than |kRipOffDistance|.
- gfx::Point first_app_location = GetButtonCenter(GetButtonByID(first_app_id));
- generator->set_current_screen_location(first_app_location);
- generator->PressLeftButton();
- // Drag the mouse to just off the shelf.
- generator->MoveMouseBy(0, -ShelfConfig::Get()->shelf_size() / 2 - 1);
- EXPECT_EQ(1, GetHapticTickEventsCount());
- EXPECT_FALSE(test_api_->IsRippedOffFromShelf());
- // Drag the mouse past the rip off threshold.
- generator->MoveMouseBy(0, -kRipOffDistance);
- EXPECT_TRUE(test_api_->IsRippedOffFromShelf());
- // Drag the mouse back to the original position, so that the app does not get
- // deleted.
- generator->MoveMouseTo(first_app_location);
- generator->ReleaseLeftButton();
- EXPECT_EQ(1, GetHapticTickEventsCount());
- EXPECT_FALSE(test_api_->IsRippedOffFromShelf());
- }
- // Test that rip off drag can gracefully be canceled.
- TEST_P(LtrRtlShelfViewTest, ShelfRipOffCancel) {
- // The test makes some assumptions that the shelf is bottom aligned.
- ASSERT_EQ(shelf_view_->shelf()->alignment(), ShelfAlignment::kBottom);
- // The rip off threshold. Taken from |kRipOffDistance| in shelf_view.cc.
- constexpr int kRipOffDistance = 48;
- // Add two apps on the main shelf.
- ShelfID first_app_id = AddAppShortcut();
- AddAppShortcut();
- // Cache the shelf state - test will verify that shelf items are not changed
- // if rip off drag gets canceled.
- std::vector<std::pair<ShelfID, views::View*>> id_map;
- for (size_t i = 0; i < model_->items().size(); ++i) {
- ShelfAppButton* button = test_api_->GetButton(i);
- id_map.emplace_back(model_->items()[i].id, button);
- }
- // Verify that dragging an app off the shelf will trigger the app getting
- // ripped off, unless the distance is less than |kRipOffDistance|.
- const ShelfAppButton* dragged_button = GetButtonByID(first_app_id);
- gfx::Point first_app_location = GetButtonCenter(dragged_button);
- ui::test::EventGenerator* generator = GetEventGenerator();
- generator->set_current_screen_location(first_app_location);
- generator->PressLeftButton();
- // Drag the mouse to just off the shelf.
- generator->MoveMouseBy(0, -ShelfConfig::Get()->shelf_size() / 2 - 1);
- EXPECT_EQ(1, GetHapticTickEventsCount());
- EXPECT_FALSE(test_api_->IsRippedOffFromShelf());
- // Drag the mouse past the rip off threshold.
- generator->MoveMouseBy(0, -kRipOffDistance);
- EXPECT_TRUE(test_api_->IsRippedOffFromShelf());
- shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, true);
- generator->ReleaseLeftButton();
- EXPECT_EQ(1, GetHapticTickEventsCount());
- EXPECT_FALSE(test_api_->IsRippedOffFromShelf());
- ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map));
- }
- // Tests that drag and drop a pinned running app will unpin it.
- TEST_P(LtrRtlShelfViewTest, DragAndDropPinnedRunningApp) {
- ui::test::EventGenerator* generator = GetEventGenerator();
- // The test makes some assumptions that the shelf is bottom aligned.
- ASSERT_EQ(shelf_view_->shelf()->alignment(), ShelfAlignment::kBottom);
- // The rip off threshold. Taken from |kRipOffDistance| in shelf_view.cc.
- constexpr int kRipOffDistance = 48;
- const ShelfID id = AddApp();
- // Added only one app here, the index of the app will not change after drag
- // and drop.
- int index = model_->ItemIndexByID(id);
- ShelfItem item = GetItemByID(id);
- EXPECT_EQ(STATUS_RUNNING, item.status);
- model_->PinExistingItemWithID(id.app_id);
- EXPECT_TRUE(IsAppPinned(GetItemId(index)));
- gfx::Point app_location = GetButtonCenter(GetButtonByID(id));
- generator->set_current_screen_location(app_location);
- generator->PressLeftButton();
- generator->MoveMouseBy(0, -ShelfConfig::Get()->shelf_size() / 2 - 1);
- EXPECT_EQ(1, GetHapticTickEventsCount());
- EXPECT_FALSE(test_api_->IsRippedOffFromShelf());
- generator->MoveMouseBy(0, -kRipOffDistance);
- EXPECT_TRUE(test_api_->IsRippedOffFromShelf());
- generator->ReleaseLeftButton();
- EXPECT_FALSE(IsAppPinned(GetItemId(index)));
- EXPECT_EQ(1, GetHapticTickEventsCount());
- }
- // Double click an app while animating drag icon drop.
- TEST_P(LtrRtlShelfViewTest, ActivateAppButtonDuringDropAnimation) {
- ui::test::EventGenerator* generator = GetEventGenerator();
- // Enable animations, as the test verifies behavior while a drop animation is
- // in progress.
- ui::ScopedAnimationDurationScaleMode regular_animations(
- ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
- // The test makes some assumptions that the shelf is bottom aligned.
- ASSERT_EQ(shelf_view_->shelf()->alignment(), ShelfAlignment::kBottom);
- const ShelfID drag_item_id = AddApp();
- const ShelfID activated_item_id = AddApp();
- // Watch for selection of the browser shortcut.
- auto owned_selection_tracker = std::make_unique<ShelfItemSelectionTracker>();
- ShelfItemSelectionTracker* selection_tracker = owned_selection_tracker.get();
- model_->ReplaceShelfItemDelegate(activated_item_id,
- std::move(owned_selection_tracker));
- generator->set_current_screen_location(
- GetButtonCenter(GetButtonByID(drag_item_id)));
- generator->PressLeftButton();
- generator->MoveMouseBy(0, -ShelfConfig::Get()->shelf_size() / 2 - 1);
- EXPECT_EQ(1, GetHapticTickEventsCount());
- generator->ReleaseLeftButton();
- EXPECT_EQ(1, GetHapticTickEventsCount());
- generator->set_current_screen_location(
- GetButtonCenter(GetButtonByID(activated_item_id)));
- generator->DoubleClickLeftButton();
- EXPECT_EQ(1, GetHapticTickEventsCount());
- EXPECT_EQ(1u, selection_tracker->item_selected_count());
- VerifyShelfItemBoundsAreValid();
- }
- // Confirm that item status changes are reflected in the buttons
- // for platform apps.
- TEST_P(LtrRtlShelfViewTest, ShelfItemStatusPlatformApp) {
- // All buttons should be visible.
- ASSERT_EQ(test_api_->GetButtonCount(), shelf_view_->number_of_visible_apps());
- // Add platform app button.
- ShelfID last_added = AddApp();
- ShelfItem item = GetItemByID(last_added);
- int index = model_->ItemIndexByID(last_added);
- ShelfAppButton* button = GetButtonByID(last_added);
- ASSERT_EQ(ShelfAppButton::STATE_RUNNING, button->state());
- item.status = STATUS_ATTENTION;
- model_->Set(index, item);
- ASSERT_EQ(ShelfAppButton::STATE_ATTENTION, button->state());
- }
- // Confirm that shelf item bounds are correctly updated on shelf changes.
- TEST_P(LtrRtlShelfViewTest, ShelfItemBoundsCheck) {
- VerifyShelfItemBoundsAreValid();
- shelf_view_->shelf()->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
- test_api_->RunMessageLoopUntilAnimationsDone();
- VerifyShelfItemBoundsAreValid();
- shelf_view_->shelf()->SetAutoHideBehavior(ShelfAutoHideBehavior::kNever);
- test_api_->RunMessageLoopUntilAnimationsDone();
- VerifyShelfItemBoundsAreValid();
- }
- TEST_P(LtrRtlShelfViewTest, ShelfTooltipTest) {
- ASSERT_EQ(shelf_view_->number_of_visible_apps(), test_api_->GetButtonCount());
- // Prepare some items to the shelf.
- ShelfID app_button_id = AddAppShortcut();
- ShelfID platform_button_id = AddApp();
- ShelfAppButton* app_button = GetButtonByID(app_button_id);
- ShelfAppButton* platform_button = GetButtonByID(platform_button_id);
- ShelfTooltipManager* tooltip_manager = test_api_->tooltip_manager();
- EXPECT_TRUE(shelf_view_->GetWidget()->GetNativeWindow());
- ui::test::EventGenerator* generator = GetEventGenerator();
- generator->MoveMouseTo(app_button->GetBoundsInScreen().CenterPoint());
- // There's a delay to show the tooltip, so it's not visible yet.
- EXPECT_FALSE(tooltip_manager->IsVisible());
- EXPECT_EQ(nullptr, tooltip_manager->GetCurrentAnchorView());
- tooltip_manager->ShowTooltip(app_button);
- EXPECT_TRUE(tooltip_manager->IsVisible());
- EXPECT_EQ(app_button, tooltip_manager->GetCurrentAnchorView());
- // The tooltip will continue showing while the cursor moves between buttons.
- const gfx::Point midpoint =
- gfx::UnionRects(app_button->GetBoundsInScreen(),
- platform_button->GetBoundsInScreen())
- .CenterPoint();
- generator->MoveMouseTo(midpoint);
- EXPECT_TRUE(tooltip_manager->IsVisible());
- EXPECT_EQ(app_button, tooltip_manager->GetCurrentAnchorView());
- // When the cursor moves over another item, its tooltip shows immediately.
- generator->MoveMouseTo(platform_button->GetBoundsInScreen().CenterPoint());
- EXPECT_TRUE(tooltip_manager->IsVisible());
- EXPECT_EQ(platform_button, tooltip_manager->GetCurrentAnchorView());
- tooltip_manager->Close();
- // Now cursor over the app_button and move immediately to the platform_button.
- generator->MoveMouseTo(app_button->GetBoundsInScreen().CenterPoint());
- generator->MoveMouseTo(midpoint);
- generator->MoveMouseTo(platform_button->GetBoundsInScreen().CenterPoint());
- EXPECT_FALSE(tooltip_manager->IsVisible());
- EXPECT_EQ(nullptr, tooltip_manager->GetCurrentAnchorView());
- }
- // Verify a fix for crash caused by a tooltip update for a deleted shelf
- // button, see crbug.com/288838.
- TEST_P(LtrRtlShelfViewTest, RemovingItemClosesTooltip) {
- ShelfTooltipManager* tooltip_manager = test_api_->tooltip_manager();
- // Add an item to the shelf.
- ShelfID app_button_id = AddAppShortcut();
- ShelfAppButton* app_button = GetButtonByID(app_button_id);
- // Spawn a tooltip on that item.
- tooltip_manager->ShowTooltip(app_button);
- EXPECT_TRUE(tooltip_manager->IsVisible());
- // Remove the app shortcut while the tooltip is open. The tooltip should be
- // closed.
- RemoveByID(app_button_id);
- EXPECT_FALSE(tooltip_manager->IsVisible());
- // Change the shelf layout. This should not crash.
- GetPrimaryShelf()->SetAlignment(ShelfAlignment::kLeft);
- }
- // Changing the shelf alignment closes any open tooltip.
- TEST_P(LtrRtlShelfViewTest, ShelfAlignmentClosesTooltip) {
- ShelfTooltipManager* tooltip_manager = test_api_->tooltip_manager();
- // Add an item to the shelf.
- ShelfID app_button_id = AddAppShortcut();
- ShelfAppButton* app_button = GetButtonByID(app_button_id);
- // Spawn a tooltip on the item.
- tooltip_manager->ShowTooltip(app_button);
- EXPECT_TRUE(tooltip_manager->IsVisible());
- // Changing shelf alignment hides the tooltip.
- GetPrimaryShelf()->SetAlignment(ShelfAlignment::kLeft);
- EXPECT_FALSE(tooltip_manager->IsVisible());
- }
- // Verifies that the time of button press is recorded correctly in clamshell.
- TEST_P(LtrRtlShelfViewTest, HomeButtonMetricsInClamshell) {
- const HomeButton* home_button =
- GetPrimaryShelf()->navigation_widget()->GetHomeButton();
- // Make sure we're not showing the app list.
- EXPECT_FALSE(home_button->IsShowingAppList());
- base::UserActionTester user_action_tester;
- ASSERT_EQ(0, user_action_tester.GetActionCount(
- "AppList_HomeButtonPressedClamshell"));
- GetEventGenerator()->GestureTapAt(
- home_button->GetBoundsInScreen().CenterPoint());
- ASSERT_EQ(1, user_action_tester.GetActionCount(
- "AppList_HomeButtonPressedClamshell"));
- EXPECT_TRUE(home_button->IsShowingAppList());
- }
- // Verifies that the time of button press is recorded correctly in tablet.
- TEST_P(LtrRtlShelfViewTest, HomeButtonMetricsInTablet) {
- // Enable accessibility feature that forces home button to be shown even with
- // kHideShelfControlsInTabletMode enabled.
- Shell::Get()
- ->accessibility_controller()
- ->SetTabletModeShelfNavigationButtonsEnabled(true);
- Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
- const HomeButton* home_button =
- GetPrimaryShelf()->navigation_widget()->GetHomeButton();
- // Make sure we're not showing the app list.
- std::unique_ptr<aura::Window> window = CreateTestWindow();
- wm::ActivateWindow(window.get());
- EXPECT_FALSE(home_button->IsShowingAppList());
- base::UserActionTester user_action_tester;
- ASSERT_EQ(
- 0, user_action_tester.GetActionCount("AppList_HomeButtonPressedTablet"));
- GetEventGenerator()->GestureTapAt(
- home_button->GetBoundsInScreen().CenterPoint());
- ASSERT_EQ(
- 1, user_action_tester.GetActionCount("AppList_HomeButtonPressedTablet"));
- EXPECT_TRUE(home_button->IsShowingAppList());
- }
- TEST_P(LtrRtlShelfViewTest, ShouldHideTooltipTest) {
- // Set a screen size large enough to have space between the home button and
- // app buttons.
- UpdateDisplay("2000x600");
- ShelfID app_button_id = AddAppShortcut();
- ShelfID platform_button_id = AddApp();
- // TODO(manucornet): It should not be necessary to call this manually. The
- // |AddItem| call seems to sometimes be missing some re-layout steps. We
- // should find out what's going on there.
- shelf_view_->UpdateVisibleShelfItemBoundsUnion();
- const HomeButton* home_button =
- GetPrimaryShelf()->navigation_widget()->GetHomeButton();
- // Make sure we're not showing the app list.
- EXPECT_FALSE(home_button->IsShowingAppList())
- << "We should not be showing the app list";
- // The tooltip shouldn't hide if the mouse is on normal buttons.
- for (size_t i = 0; i < test_api_->GetButtonCount(); i++) {
- ShelfAppButton* button = test_api_->GetButton(i);
- if (!button)
- continue;
- EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
- button->GetMirroredBounds().CenterPoint()))
- << "ShelfView tries to hide on button " << i;
- }
- // The tooltip should hide if placed in between the home button and the
- // first shelf button.
- const int left = home_button->GetBoundsInScreen().right();
- // Find the first shelf button that's to the right of the home button.
- int right = 0;
- for (size_t i = 0; i < test_api_->GetButtonCount(); ++i) {
- ShelfAppButton* button = test_api_->GetButton(i);
- if (!button)
- continue;
- right = button->GetBoundsInScreen().x();
- if (right > left)
- break;
- }
- gfx::Point test_point(left + (right - left) / 2,
- home_button->GetBoundsInScreen().y());
- views::View::ConvertPointFromScreen(shelf_view_, &test_point);
- EXPECT_TRUE(shelf_view_->ShouldHideTooltip(gfx::Point(
- shelf_view_->GetMirroredXInView(test_point.x()), test_point.y())))
- << "Tooltip should hide between home button and first shelf item";
- // The tooltip shouldn't hide if the mouse is in the gap between two buttons.
- gfx::Rect app_button_rect = GetButtonByID(app_button_id)->GetMirroredBounds();
- gfx::Rect platform_button_rect =
- GetButtonByID(platform_button_id)->GetMirroredBounds();
- ASSERT_FALSE(app_button_rect.Intersects(platform_button_rect));
- EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
- gfx::UnionRects(app_button_rect, platform_button_rect).CenterPoint()));
- // The tooltip should hide if it's outside of all buttons.
- gfx::Rect all_area;
- for (size_t i = 0; i < test_api_->GetButtonCount(); i++) {
- ShelfAppButton* button = test_api_->GetButton(i);
- if (!button)
- continue;
- all_area.Union(button->GetMirroredBounds());
- }
- EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
- gfx::Point(all_area.right() - 1, all_area.bottom() - 1)));
- EXPECT_TRUE(shelf_view_->ShouldHideTooltip(
- gfx::Point(all_area.right(), all_area.y())));
- EXPECT_TRUE(shelf_view_->ShouldHideTooltip(
- gfx::Point(all_area.x() - 1, all_area.y())));
- EXPECT_TRUE(shelf_view_->ShouldHideTooltip(
- gfx::Point(all_area.x(), all_area.y() - 1)));
- EXPECT_TRUE(shelf_view_->ShouldHideTooltip(
- gfx::Point(all_area.x(), all_area.bottom())));
- }
- // Test that shelf button tooltips show (except app list) with an open app list.
- TEST_P(LtrRtlShelfViewTest, ShouldHideTooltipWithAppListWindowTest) {
- GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
- // The tooltip shouldn't hide if the mouse is on normal buttons.
- for (size_t i = 2; i < test_api_->GetButtonCount(); i++) {
- ShelfAppButton* button = test_api_->GetButton(i);
- if (!button)
- continue;
- EXPECT_FALSE(shelf_view_->ShouldHideTooltip(
- button->GetMirroredBounds().CenterPoint()))
- << "ShelfView tries to hide on button " << i;
- }
- // The tooltip should hide on the home button if the app list is visible.
- HomeButton* home_button =
- GetPrimaryShelf()->navigation_widget()->GetHomeButton();
- gfx::Point center_point = home_button->GetBoundsInScreen().CenterPoint();
- views::View::ConvertPointFromScreen(shelf_view_, ¢er_point);
- EXPECT_TRUE(shelf_view_->ShouldHideTooltip(gfx::Point(
- shelf_view_->GetMirroredXInView(center_point.x()), center_point.y())));
- }
- // Test that by moving the mouse cursor off the button onto the bubble it closes
- // the bubble.
- TEST_P(LtrRtlShelfViewTest, ShouldHideTooltipWhenHoveringOnTooltip) {
- ShelfTooltipManager* tooltip_manager = test_api_->tooltip_manager();
- tooltip_manager->set_timer_delay_for_test(0);
- ui::test::EventGenerator* generator = GetEventGenerator();
- // Move the mouse off any item and check that no tooltip is shown.
- generator->MoveMouseTo(gfx::Point(0, 0));
- EXPECT_FALSE(tooltip_manager->IsVisible());
- // Move the mouse over the button and check that it is visible.
- views::View* button = shelf_view_->first_visible_button_for_testing();
- gfx::Rect bounds = button->GetBoundsInScreen();
- generator->MoveMouseTo(bounds.CenterPoint());
- // Wait for the timer to go off.
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(tooltip_manager->IsVisible());
- // Move the mouse cursor slightly to the right of the item. The tooltip should
- // now close.
- generator->MoveMouseBy(bounds.width() / 2 + 5, 0);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(tooltip_manager->IsVisible());
- // Move back - it should appear again.
- generator->MoveMouseBy(-(bounds.width() / 2 + 5), 0);
- // Make sure there is no delayed close.
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(tooltip_manager->IsVisible());
- // Now move the mouse cursor slightly above the item - so that it is over the
- // tooltip bubble. Now it should disappear.
- generator->MoveMouseBy(0, -(bounds.height() / 2 + 5));
- // Wait until the delayed close kicked in.
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(tooltip_manager->IsVisible());
- }
- // Checks the rip an item off from left aligned shelf in secondary monitor.
- TEST_P(LtrRtlShelfViewTest, CheckRipOffFromLeftShelfAlignmentWithMultiMonitor) {
- UpdateDisplay("800x600,800x600");
- ASSERT_EQ(2U, Shell::GetAllRootWindows().size());
- aura::Window* root_window = Shell::GetAllRootWindows()[1];
- Shelf* secondary_shelf = Shelf::ForWindow(root_window);
- secondary_shelf->SetAlignment(ShelfAlignment::kLeft);
- ASSERT_EQ(ShelfAlignment::kLeft, secondary_shelf->alignment());
- ShelfView* shelf_view_for_secondary =
- secondary_shelf->GetShelfViewForTesting();
- AddAppShortcut();
- ShelfViewTestAPI test_api_for_secondary_shelf_view(shelf_view_for_secondary);
- ShelfAppButton* button = test_api_for_secondary_shelf_view.GetButton(0);
- // Fetch the start point of dragging.
- gfx::Point start_point = button->GetBoundsInScreen().CenterPoint();
- gfx::Point end_point = start_point + gfx::Vector2d(400, 0);
- ::wm::ConvertPointFromScreen(root_window, &start_point);
- ui::test::EventGenerator generator(root_window, start_point);
- // Rip off the browser item.
- generator.PressLeftButton();
- generator.MoveMouseTo(end_point);
- test_api_for_secondary_shelf_view.RunMessageLoopUntilAnimationsDone();
- EXPECT_TRUE(test_api_for_secondary_shelf_view.IsRippedOffFromShelf());
- // Release the button to prevent crash in test destructor (releasing the
- // button triggers animating shelf to ideal bounds during shell destruction).
- generator.ReleaseLeftButton();
- }
- // Verifies that Launcher_ButtonPressed_* UMA user actions are recorded when an
- // item is selected.
- TEST_P(LtrRtlShelfViewTest,
- Launcher_ButtonPressedUserActionsRecordedWhenItemSelected) {
- base::UserActionTester user_action_tester;
- ShelfItemSelectionTracker* selection_tracker = new ShelfItemSelectionTracker;
- model_->ReplaceShelfItemDelegate(
- model_->items()[0].id,
- base::WrapUnique<ShelfItemSelectionTracker>(selection_tracker));
- SimulateClick(0);
- EXPECT_EQ(1,
- user_action_tester.GetActionCount("Launcher_ButtonPressed_Mouse"));
- }
- // Verifies that Launcher_*Task UMA user actions are recorded when an item is
- // selected.
- TEST_P(LtrRtlShelfViewTest, Launcher_TaskUserActionsRecordedWhenItemSelected) {
- base::UserActionTester user_action_tester;
- ShelfItemSelectionTracker* selection_tracker = new ShelfItemSelectionTracker;
- selection_tracker->set_item_selected_action(SHELF_ACTION_NEW_WINDOW_CREATED);
- model_->ReplaceShelfItemDelegate(
- model_->items()[0].id,
- base::WrapUnique<ShelfItemSelectionTracker>(selection_tracker));
- SimulateClick(0);
- EXPECT_EQ(1, user_action_tester.GetActionCount("Launcher_LaunchTask"));
- }
- // Verifies that metrics are recorded when an item is minimized and subsequently
- // activated.
- TEST_P(LtrRtlShelfViewTest,
- VerifyMetricsAreRecordedWhenAnItemIsMinimizedAndActivated) {
- base::HistogramTester histogram_tester;
- ShelfItemSelectionTracker* selection_tracker = new ShelfItemSelectionTracker;
- model_->ReplaceShelfItemDelegate(
- model_->items()[0].id,
- base::WrapUnique<ShelfItemSelectionTracker>(selection_tracker));
- selection_tracker->set_item_selected_action(SHELF_ACTION_WINDOW_MINIMIZED);
- SimulateClick(0);
- selection_tracker->set_item_selected_action(SHELF_ACTION_WINDOW_ACTIVATED);
- SimulateClick(0);
- histogram_tester.ExpectTotalCount(
- kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 1);
- }
- // Verify the animations of the shelf items are as long as expected.
- TEST_P(LtrRtlShelfViewTest, TestShelfItemsAnimations) {
- TestShelfObserver observer(shelf_view_->shelf());
- ui::test::EventGenerator* generator = GetEventGenerator();
- ShelfID first_app_id = AddAppShortcut();
- ShelfID second_app_id = AddAppShortcut();
- // Set the animation duration for shelf items.
- test_api_->SetAnimationDuration(base::Milliseconds(100));
- // The shelf items should animate if they are moved within the shelf, either
- // by swapping or if the items need to be rearranged due to an item getting
- // ripped off.
- generator->set_current_screen_location(GetButtonCenter(first_app_id));
- generator->DragMouseTo(GetButtonCenter(second_app_id));
- generator->DragMouseBy(0, 50);
- test_api_->RunMessageLoopUntilAnimationsDone();
- EXPECT_EQ(100, observer.icon_positions_animation_duration().InMilliseconds());
- // The shelf items should not animate when the whole shelf and its contents
- // have to move.
- observer.Reset();
- shelf_view_->shelf()->SetAlignment(ShelfAlignment::kLeft);
- test_api_->RunMessageLoopUntilAnimationsDone();
- EXPECT_EQ(1, observer.icon_positions_animation_duration().InMilliseconds());
- // The shelf items should animate if we are entering or exiting tablet mode,
- // and the shelf alignment is bottom aligned, and scrollable shelf is not
- // enabled.
- PrefService* prefs =
- Shell::Get()->session_controller()->GetLastActiveUserPrefService();
- const int64_t id = GetPrimaryDisplay().id();
- shelf_view_->shelf()->SetAlignment(ShelfAlignment::kBottom);
- SetShelfAlignmentPref(prefs, id, ShelfAlignment::kBottom);
- observer.Reset();
- Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
- test_api_->RunMessageLoopUntilAnimationsDone();
- EXPECT_EQ(1, observer.icon_positions_animation_duration().InMilliseconds());
- observer.Reset();
- Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
- test_api_->RunMessageLoopUntilAnimationsDone();
- EXPECT_EQ(1, observer.icon_positions_animation_duration().InMilliseconds());
- // The shelf items should not animate if we are entering or exiting tablet
- // mode, and the shelf alignment is not bottom aligned.
- shelf_view_->shelf()->SetAlignment(ShelfAlignment::kLeft);
- SetShelfAlignmentPref(prefs, id, ShelfAlignment::kLeft);
- observer.Reset();
- Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
- test_api_->RunMessageLoopUntilAnimationsDone();
- EXPECT_EQ(1, observer.icon_positions_animation_duration().InMilliseconds());
- observer.Reset();
- Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
- test_api_->RunMessageLoopUntilAnimationsDone();
- EXPECT_EQ(1, observer.icon_positions_animation_duration().InMilliseconds());
- }
- // Tests that the blank shelf view area shows a context menu on right click.
- TEST_P(LtrRtlShelfViewTest, ShelfViewShowsContextMenu) {
- ui::test::EventGenerator* generator = GetEventGenerator();
- generator->MoveMouseTo(shelf_view_->GetBoundsInScreen().CenterPoint());
- generator->PressRightButton();
- generator->ReleaseRightButton();
- EXPECT_TRUE(test_api_->CloseMenu());
- }
- TEST_P(LtrRtlShelfViewTest, TabletModeStartAndEndClosesContextMenu) {
- // Show a context menu on the shelf
- ui::test::EventGenerator* generator = GetEventGenerator();
- generator->MoveMouseTo(shelf_view_->GetBoundsInScreen().CenterPoint());
- generator->PressRightButton();
- // Start tablet mode, which should close the menu.
- shelf_view_->OnTabletModeStarted();
- // Attempt to close the menu, which should already be closed.
- EXPECT_FALSE(test_api_->CloseMenu());
- // Show another context menu on the shelf.
- generator->MoveMouseTo(shelf_view_->GetBoundsInScreen().CenterPoint());
- generator->PressRightButton();
- // End tablet mode, which should close the menu.
- shelf_view_->OnTabletModeEnded();
- // Attempt to close the menu, which should already be closed.
- EXPECT_FALSE(test_api_->CloseMenu());
- }
- // Tests that ShelfWindowWatcher buttons show a context menu on right click.
- TEST_P(LtrRtlShelfViewTest, ShelfWindowWatcherButtonShowsContextMenu) {
- ui::test::EventGenerator* generator = GetEventGenerator();
- std::unique_ptr<views::Widget> widget = CreateTestWidget();
- widget->Show();
- aura::Window* window = widget->GetNativeWindow();
- ShelfID shelf_id("123");
- window->SetProperty(kShelfIDKey, shelf_id.Serialize());
- window->SetProperty(kShelfItemTypeKey, static_cast<int32_t>(TYPE_DIALOG));
- ShelfAppButton* button = GetButtonByID(shelf_id);
- ASSERT_TRUE(button);
- generator->MoveMouseTo(button->GetBoundsInScreen().CenterPoint());
- generator->PressRightButton();
- EXPECT_TRUE(test_api_->CloseMenu());
- }
- // Tests that the drag view is set on left click and not set on right click.
- TEST_P(LtrRtlShelfViewTest, ShelfDragViewAndContextMenu) {
- ui::test::EventGenerator* generator = GetEventGenerator();
- std::unique_ptr<views::Widget> widget = CreateTestWidget();
- widget->Show();
- aura::Window* window = widget->GetNativeWindow();
- ShelfID shelf_id("123");
- window->SetProperty(kShelfIDKey, shelf_id.Serialize());
- window->SetProperty(kShelfItemTypeKey, static_cast<int32_t>(TYPE_DIALOG));
- // Waits for the bounds animation triggered by window property setting to
- // finish.
- test_api_->RunMessageLoopUntilAnimationsDone();
- ShelfAppButton* button = GetButtonByID(shelf_id);
- ASSERT_TRUE(button);
- // Context menu is shown on right button press and no drag view is set.
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- generator->MoveMouseTo(button->GetBoundsInScreen().CenterPoint());
- generator->PressRightButton();
- EXPECT_TRUE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- // Press left button. Menu should close.
- generator->PressLeftButton();
- generator->ReleaseLeftButton();
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- // Press left button. Drag view is set to |button|.
- generator->PressLeftButton();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(shelf_view_->drag_view(), button);
- generator->ReleaseLeftButton();
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_EQ(0, GetHapticTickEventsCount());
- }
- // Tests that context menu show is cancelled if item drag starts during context
- // menu show (while constructing the item menu model).
- TEST_P(LtrRtlShelfViewTest, InProgressItemDragPreventsContextMenuShow) {
- const ShelfID app_id = AddAppShortcut();
- auto item_delegate_owned =
- std::make_unique<AsyncContextMenuShelfItemDelegate>();
- AsyncContextMenuShelfItemDelegate* item_delegate = item_delegate_owned.get();
- model_->ReplaceShelfItemDelegate(app_id, std::move(item_delegate_owned));
- ShelfAppButton* button = GetButtonByID(app_id);
- ASSERT_TRUE(button);
- const gfx::Point location = button->GetBoundsInScreen().CenterPoint();
- ui::test::EventGenerator* generator = GetEventGenerator();
- generator->set_current_screen_location(location);
- generator->PressTouch();
- // Generate long press, which should start context menu request.
- ui::GestureEventDetails event_details(ui::ET_GESTURE_LONG_PRESS);
- ui::GestureEvent long_press(location.x(), location.y(), 0,
- ui::EventTimeForNow(), event_details);
- generator->Dispatch(&long_press);
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(button->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_TRUE(item_delegate->HasPendingContextMenuCallback());
- // Drag the app icon while context menu callback is pending..
- ASSERT_TRUE(button->FireDragTimerForTest());
- generator->MoveTouchBy(0, -10);
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_TRUE(shelf_view_->drag_view());
- EXPECT_TRUE(button->state() & ShelfAppButton::STATE_DRAGGING);
- // Return the context menu model.
- auto menu_model = std::make_unique<ui::SimpleMenuModel>(nullptr);
- menu_model->AddItem(203, u"item");
- ASSERT_TRUE(
- item_delegate->RunPendingContextMenuCallback(std::move(menu_model)));
- // The context menu show is expected to be canceled by the item drag.
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_TRUE(shelf_view_->drag_view());
- EXPECT_TRUE(button->state() & ShelfAppButton::STATE_DRAGGING);
- // Drag state should be cleared when the drag ends.
- generator->ReleaseTouch();
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(button->state() & ShelfAppButton::STATE_DRAGGING);
- // Another long press starts context menu request.
- generator->set_current_screen_location(location);
- generator->PressTouch();
- ui::GestureEventDetails second_press_event_details(ui::ET_GESTURE_LONG_PRESS);
- ui::GestureEvent second_long_press(location.x(), location.y(), 0,
- ui::EventTimeForNow(),
- second_press_event_details);
- generator->Dispatch(&second_long_press);
- EXPECT_TRUE(item_delegate->HasPendingContextMenuCallback());
- }
- // Tests that context menu show is cancelled if item drag starts and ends during
- // context menu show (while constructing the item menu model).
- TEST_P(LtrRtlShelfViewTest, CompletedItemDragPreventsContextMenuShow) {
- const ShelfID app_id = AddAppShortcut();
- auto item_delegate_owned =
- std::make_unique<AsyncContextMenuShelfItemDelegate>();
- AsyncContextMenuShelfItemDelegate* item_delegate = item_delegate_owned.get();
- model_->ReplaceShelfItemDelegate(app_id, std::move(item_delegate_owned));
- ShelfAppButton* button = GetButtonByID(app_id);
- ASSERT_TRUE(button);
- const gfx::Point location = button->GetBoundsInScreen().CenterPoint();
- ui::test::EventGenerator* generator = GetEventGenerator();
- generator->set_current_screen_location(location);
- generator->PressTouch();
- // Generate long press, which should start context menu request.
- ui::GestureEventDetails event_details(ui::ET_GESTURE_LONG_PRESS);
- ui::GestureEvent long_press(location.x(), location.y(), 0,
- ui::EventTimeForNow(), event_details);
- generator->Dispatch(&long_press);
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(button->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_TRUE(item_delegate->HasPendingContextMenuCallback());
- // Drag the app icon while context menu callback is pending.
- ASSERT_TRUE(button->FireDragTimerForTest());
- generator->MoveTouchBy(0, -10);
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_TRUE(shelf_view_->drag_view());
- EXPECT_TRUE(button->state() & ShelfAppButton::STATE_DRAGGING);
- // Drag state should be cleared when the drag ends.
- generator->ReleaseTouch();
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(button->state() & ShelfAppButton::STATE_DRAGGING);
- // Return the context menu model.
- auto menu_model = std::make_unique<ui::SimpleMenuModel>(nullptr);
- menu_model->AddItem(203, u"item");
- ASSERT_TRUE(
- item_delegate->RunPendingContextMenuCallback(std::move(menu_model)));
- // The context menu show is expected to be canceled by the item drag, so it
- // should not be shown even though there is no in-progress drag when the
- // context menu model is received.
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(button->state() & ShelfAppButton::STATE_DRAGGING);
- // Another long press starts context menu request.
- generator->set_current_screen_location(location);
- generator->PressTouch();
- ui::GestureEventDetails second_press_event_details(ui::ET_GESTURE_LONG_PRESS);
- ui::GestureEvent second_long_press(location.x(), location.y(), 0,
- ui::EventTimeForNow(),
- second_press_event_details);
- generator->Dispatch(&second_long_press);
- EXPECT_TRUE(item_delegate->HasPendingContextMenuCallback());
- }
- // Tests that shelf items in always shown shelf can be dragged through gesture
- // events after context menu is shown.
- TEST_P(LtrRtlShelfViewTest, DragAppAfterContextMenuIsShownInAlwaysShownShelf) {
- ASSERT_EQ(SHELF_VISIBLE, GetPrimaryShelf()->GetVisibilityState());
- ui::test::EventGenerator* generator = GetEventGenerator();
- const ShelfID first_app_id = AddAppShortcut();
- const ShelfID second_app_id = AddAppShortcut();
- const int last_index = model_->items().size() - 1;
- ASSERT_TRUE(last_index >= 0);
- ShelfAppButton* button = GetButtonByID(first_app_id);
- ASSERT_TRUE(button);
- auto item_delegate_owned =
- std::make_unique<AsyncContextMenuShelfItemDelegate>();
- AsyncContextMenuShelfItemDelegate* item_delegate = item_delegate_owned.get();
- model_->ReplaceShelfItemDelegate(first_app_id,
- std::move(item_delegate_owned));
- const gfx::Point start = GetButtonCenter(first_app_id);
- // Drag the app long enough to ensure the drag can be triggered.
- const gfx::Point end(start.x() + (IsRtlEnabled() ? -100 : 100), start.y());
- generator->set_current_screen_location(start);
- generator->PressTouch();
- ASSERT_TRUE(button->FireDragTimerForTest());
- button->FireRippleActivationTimerForTest();
- // Generate long press, which should start context menu request.
- ui::GestureEventDetails event_details(ui::ET_GESTURE_LONG_PRESS);
- ui::GestureEvent long_press(start.x(), start.y(), 0, ui::EventTimeForNow(),
- event_details);
- generator->Dispatch(&long_press);
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_TRUE(button->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_TRUE(item_delegate->HasPendingContextMenuCallback());
- auto menu_model = std::make_unique<ui::SimpleMenuModel>(nullptr);
- menu_model->AddItem(203, u"item");
- ASSERT_TRUE(
- item_delegate->RunPendingContextMenuCallback(std::move(menu_model)));
- EXPECT_TRUE(shelf_view_->IsShowingMenu());
- EXPECT_EQ(button, shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_TRUE(button->state() & ShelfAppButton::STATE_DRAGGING);
- generator->GestureScrollSequence(start, end, base::Milliseconds(100), 3);
- generator->ReleaseTouch();
- EXPECT_EQ(0, GetHapticTickEventsCount());
- // |first_add_id| has been moved to the end of the items in the shelf.
- EXPECT_EQ(first_app_id, model_->items()[last_index].id);
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(button->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_FALSE(item_delegate->HasPendingContextMenuCallback());
- }
- // Tests that shelf items in AUTO_HIDE_SHOWN shelf can be dragged through
- // gesture events after context menu is shown.
- TEST_P(LtrRtlShelfViewTest, DragAppAfterContextMenuIsShownInAutoHideShelf) {
- ui::test::EventGenerator* generator = GetEventGenerator();
- const ShelfID first_app_id = AddAppShortcut();
- const ShelfID second_app_id = AddAppShortcut();
- const int last_index = model_->items().size() - 1;
- Shelf* shelf = GetPrimaryShelf();
- std::unique_ptr<views::Widget> widget = CreateTestWidget();
- widget->Show();
- shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
- EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
- EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
- shelf->shelf_widget()->GetFocusCycler()->RotateFocus(FocusCycler::FORWARD);
- EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
- ShelfAppButton* button = GetButtonByID(first_app_id);
- ASSERT_TRUE(button);
- auto item_delegate_owned =
- std::make_unique<AsyncContextMenuShelfItemDelegate>();
- AsyncContextMenuShelfItemDelegate* item_delegate = item_delegate_owned.get();
- model_->ReplaceShelfItemDelegate(first_app_id,
- std::move(item_delegate_owned));
- const gfx::Point start = GetButtonCenter(first_app_id);
- // Drag the app long enough to ensure the drag can be triggered.
- const gfx::Point end(start.x() + (IsRtlEnabled() ? -100 : 100), start.y());
- generator->set_current_screen_location(start);
- generator->PressTouch();
- ASSERT_TRUE(button->FireDragTimerForTest());
- button->FireRippleActivationTimerForTest();
- // Generate long press, which should start context menu request.
- ui::GestureEventDetails event_details(ui::ET_GESTURE_LONG_PRESS);
- ui::GestureEvent long_press(start.x(), start.y(), 0, ui::EventTimeForNow(),
- event_details);
- generator->Dispatch(&long_press);
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_TRUE(button->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_TRUE(item_delegate->HasPendingContextMenuCallback());
- auto menu_model = std::make_unique<ui::SimpleMenuModel>(nullptr);
- menu_model->AddItem(203, u"item");
- ASSERT_TRUE(
- item_delegate->RunPendingContextMenuCallback(std::move(menu_model)));
- EXPECT_TRUE(shelf_view_->IsShowingMenu());
- EXPECT_EQ(button, shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_TRUE(button->state() & ShelfAppButton::STATE_DRAGGING);
- generator->GestureScrollSequence(start, end, base::Milliseconds(100), 3);
- generator->ReleaseTouch();
- EXPECT_EQ(0, GetHapticTickEventsCount());
- // |first_add_id| has been moved to the end of the items in the shelf.
- EXPECT_EQ(first_app_id, model_->items()[last_index].id);
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(button->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_FALSE(item_delegate->HasPendingContextMenuCallback());
- }
- // Tests that the app button returns to normal state after context menu is
- // hidden and touch is released, even if another touch point is added while the
- // context menu is shown.
- TEST_P(LtrRtlShelfViewTest,
- DragStateIsClearedIfAnotherTouchIsAddedWithContextMenu) {
- ASSERT_EQ(SHELF_VISIBLE, GetPrimaryShelf()->GetVisibilityState());
- ui::test::EventGenerator* generator = GetEventGenerator();
- const ShelfID app_id = AddAppShortcut();
- ShelfAppButton* button = GetButtonByID(app_id);
- ASSERT_TRUE(button);
- auto item_delegate_owned =
- std::make_unique<AsyncContextMenuShelfItemDelegate>();
- AsyncContextMenuShelfItemDelegate* item_delegate = item_delegate_owned.get();
- model_->ReplaceShelfItemDelegate(app_id, std::move(item_delegate_owned));
- const gfx::Point location = GetButtonCenter(app_id);
- generator->set_current_screen_location(location);
- generator->PressTouch();
- ASSERT_TRUE(button->FireDragTimerForTest());
- button->FireRippleActivationTimerForTest();
- // Generate long press, which should start context menu request.
- ui::GestureEventDetails event_details(ui::ET_GESTURE_LONG_PRESS);
- ui::GestureEvent long_press(location.x(), location.y(), 0,
- ui::EventTimeForNow(), event_details);
- generator->Dispatch(&long_press);
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_TRUE(button->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_TRUE(item_delegate->HasPendingContextMenuCallback());
- auto menu_model = std::make_unique<ui::SimpleMenuModel>(nullptr);
- menu_model->AddItem(203, u"item");
- ASSERT_TRUE(
- item_delegate->RunPendingContextMenuCallback(std::move(menu_model)));
- EXPECT_TRUE(shelf_view_->IsShowingMenu());
- EXPECT_EQ(button, shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_TRUE(button->state() & ShelfAppButton::STATE_DRAGGING);
- // Add and release touch.
- generator->PressTouchId(2, gfx::Point(10, 10));
- generator->ReleaseTouchId(2);
- EXPECT_TRUE(shelf_view_->IsShowingMenu());
- EXPECT_EQ(button, shelf_view_->GetShelfItemViewWithContextMenu());
- // Another tap to hide the context menu.
- generator->PressTouchId(2, gfx::Point(10, 10));
- generator->ReleaseTouchId(2);
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_FALSE(button->state() & ShelfAppButton::STATE_DRAGGING);
- // Releasing the original touch should not show another menu.
- generator->ReleaseTouch();
- EXPECT_EQ(0, GetHapticTickEventsCount());
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(button->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_FALSE(item_delegate->HasPendingContextMenuCallback());
- }
- // Tests that app button context menu remains shown if touch moves slightly
- // outside the button bounds while the menu is shown (not enough to initiate
- // drag gesture).
- TEST_P(LtrRtlShelfViewTest,
- AppContextMenuRemainsShowingAfterTouchSlightlyMovesOutsideTheButton) {
- ASSERT_EQ(SHELF_VISIBLE, GetPrimaryShelf()->GetVisibilityState());
- ui::test::EventGenerator* generator = GetEventGenerator();
- const ShelfID app_id = AddAppShortcut();
- ShelfAppButton* button = GetButtonByID(app_id);
- ASSERT_TRUE(button);
- auto item_delegate_owned =
- std::make_unique<AsyncContextMenuShelfItemDelegate>();
- AsyncContextMenuShelfItemDelegate* item_delegate = item_delegate_owned.get();
- model_->ReplaceShelfItemDelegate(app_id, std::move(item_delegate_owned));
- // Start near the button edge.
- const gfx::Point location =
- button->GetBoundsInScreen().bottom_right() + gfx::Vector2d(-1, -1);
- generator->set_current_screen_location(location);
- generator->PressTouch();
- ASSERT_TRUE(button->FireDragTimerForTest());
- button->FireRippleActivationTimerForTest();
- // Generate long press, which should start context menu request.
- ui::GestureEventDetails event_details(ui::ET_GESTURE_LONG_PRESS);
- ui::GestureEvent long_press(location.x(), location.y(), 0,
- ui::EventTimeForNow(), event_details);
- generator->Dispatch(&long_press);
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_TRUE(button->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_TRUE(item_delegate->HasPendingContextMenuCallback());
- auto menu_model = std::make_unique<ui::SimpleMenuModel>(nullptr);
- menu_model->AddItem(203, u"item");
- ASSERT_TRUE(
- item_delegate->RunPendingContextMenuCallback(std::move(menu_model)));
- EXPECT_TRUE(shelf_view_->IsShowingMenu());
- EXPECT_EQ(button, shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_TRUE(button->state() & ShelfAppButton::STATE_DRAGGING);
- // Move touch outside the button bounds using small distance - not enough to
- // start a drag operation that would hide the context menu.
- generator->MoveTouch(button->GetBoundsInScreen().bottom_right() +
- gfx::Vector2d(1, -1));
- EXPECT_TRUE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_EQ(button, shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_TRUE(button->state() & ShelfAppButton::STATE_DRAGGING);
- // Release touch - button drag state should be cleared, and the context menu
- // remain visible.
- generator->ReleaseTouch();
- EXPECT_TRUE(shelf_view_->IsShowingMenu());
- EXPECT_TRUE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(button->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_FALSE(item_delegate->HasPendingContextMenuCallback());
- // Tap to close the context menu.
- generator->GestureTapAt(gfx::Point(10, 10));
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(shelf_view_->GetShelfItemViewWithContextMenu());
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(button->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_FALSE(item_delegate->HasPendingContextMenuCallback());
- }
- // Tests that the home button does shows a context menu on right click.
- TEST_P(LtrRtlShelfViewTest, HomeButtonDoesShowContextMenu) {
- ui::test::EventGenerator* generator = GetEventGenerator();
- const HomeButton* home_button =
- GetPrimaryShelf()->navigation_widget()->GetHomeButton();
- generator->MoveMouseTo(home_button->GetBoundsInScreen().CenterPoint());
- generator->PressRightButton();
- EXPECT_TRUE(test_api_->CloseMenu());
- }
- void ExpectWithinOnePixel(int a, int b) {
- EXPECT_TRUE(abs(a - b) <= 1) << "Values " << a << " and " << b
- << " should have a difference no greater than 1";
- }
- TEST_P(LtrRtlShelfViewTest, IconCenteringTest) {
- const display::Display display =
- display::Screen::GetScreen()->GetPrimaryDisplay();
- const int screen_width = display.bounds().width();
- const int screen_center = screen_width / 2;
- // Show the IME panel, to introduce for asymettry with a larger status area.
- Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true);
- // At the start, we have exactly one app icon for the browser. That should
- // be centered on the screen.
- const ShelfAppButton* button1 = GetButtonByID(model_->items()[0].id);
- ExpectWithinOnePixel(screen_center,
- button1->GetBoundsInScreen().CenterPoint().x());
- // Also check that the distance between the icon edge and the screen edge is
- // the same on both sides.
- ExpectWithinOnePixel(button1->GetBoundsInScreen().x(),
- screen_width - button1->GetBoundsInScreen().right());
- const int apps_that_can_easily_fit_at_center_of_screen = 3;
- std::vector<ShelfAppButton*> app_buttons;
- // Start with just the browser app button.
- app_buttons.push_back(GetButtonByID(model_->items()[0].id));
- int n_buttons = 1;
- // Now repeat the same process by adding apps until they can't fit at the
- // center of the screen.
- for (int i = 1; i < apps_that_can_easily_fit_at_center_of_screen; ++i) {
- // Add a new app and add its button to our list.
- app_buttons.push_back(GetButtonByID(AddApp()));
- n_buttons = app_buttons.size();
- if (n_buttons % 2 == 1) {
- // Odd number of apps. Check that the middle app is exactly at the center
- // of the screen.
- ExpectWithinOnePixel(
- screen_center,
- app_buttons[n_buttons / 2]->GetBoundsInScreen().CenterPoint().x());
- }
- // Also check that the first icon is at the same distance from the left
- // screen edge as the last icon is from the right screen edge.
- ExpectWithinOnePixel(
- app_buttons[0]->GetBoundsInScreen().x(),
- screen_width - app_buttons[n_buttons - 1]->GetBoundsInScreen().right());
- }
- }
- TEST_P(LtrRtlShelfViewTest, FirstAndLastVisibleIndex) {
- // At the start, the only visible app on the shelf is the browser app button
- // (index 0).
- ASSERT_EQ(1u, shelf_view_->visible_views_indices().size());
- EXPECT_EQ(0u, shelf_view_->visible_views_indices()[0]);
- // By enabling tablet mode, the back button (index 0) should become visible,
- // but that does not change the first and last visible indices.
- Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
- ASSERT_EQ(1u, shelf_view_->visible_views_indices().size());
- EXPECT_EQ(0u, shelf_view_->visible_views_indices()[0]);
- // Turn tablet mode off again.
- Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
- ASSERT_EQ(1u, shelf_view_->visible_views_indices().size());
- EXPECT_EQ(0u, shelf_view_->visible_views_indices()[0]);
- }
- TEST_P(LtrRtlShelfViewTest, ReplacingDelegateCancelsContextMenu) {
- ui::test::EventGenerator* generator = GetEventGenerator();
- ShelfID app_button_id = AddAppShortcut();
- generator->MoveMouseTo(GetButtonCenter(GetButtonByID(app_button_id)));
- // Right click should open the context menu.
- generator->PressRightButton();
- generator->ReleaseRightButton();
- EXPECT_TRUE(shelf_view_->IsShowingMenu());
- // Replacing the item delegate should close the context menu.
- model_->ReplaceShelfItemDelegate(
- app_button_id, std::make_unique<ShelfItemSelectionTracker>());
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- }
- // Verifies that shelf is shown with the app list in fullscreen mode, and that
- // shelf app buttons are clickable.
- TEST_P(LtrRtlShelfViewTest, ClickItemInFullscreen) {
- ShelfID app_button_id = AddAppShortcut();
- auto selection_tracker_owned = std::make_unique<ShelfItemSelectionTracker>();
- ShelfItemSelectionTracker* selection_tracker = selection_tracker_owned.get();
- model_->ReplaceShelfItemDelegate(app_button_id,
- std::move(selection_tracker_owned));
- // Create a fullscreen widget.
- std::unique_ptr<views::Widget> widget = CreateTestWidget();
- widget->SetFullscreen(true);
- WindowState* window_state = WindowState::Get(widget->GetNativeWindow());
- window_state->SetHideShelfWhenFullscreen(true);
- Shelf* const shelf = Shelf::ForWindow(Shell::GetPrimaryRootWindow());
- EXPECT_EQ(SHELF_HIDDEN, shelf->GetVisibilityState());
- // Show app list, which will bring the shelf up.
- GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
- EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
- EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
- // Verify that clicking a shelf button activates it.
- EXPECT_EQ(0u, selection_tracker->item_selected_count());
- const ShelfAppButton* shelf_button = GetButtonByID(app_button_id);
- GetEventGenerator()->MoveMouseTo(
- shelf_button->GetBoundsInScreen().CenterPoint());
- GetEventGenerator()->ClickLeftButton();
- EXPECT_EQ(1u, selection_tracker->item_selected_count());
- // Shelf gets hidden when the app list is dismissed.
- GetAppListTestHelper()->DismissAndRunLoop();
- EXPECT_EQ(SHELF_HIDDEN, shelf->GetVisibilityState());
- EXPECT_EQ(0, GetHapticTickEventsCount());
- }
- // Verifies that shelf is shown with the app list in fullscreen mode, and that
- // shelf app buttons are tappable.
- TEST_P(LtrRtlShelfViewTest, TapInFullscreen) {
- ShelfID app_button_id = AddAppShortcut();
- auto selection_tracker_owned = std::make_unique<ShelfItemSelectionTracker>();
- ShelfItemSelectionTracker* selection_tracker = selection_tracker_owned.get();
- model_->ReplaceShelfItemDelegate(app_button_id,
- std::move(selection_tracker_owned));
- // Create a fullscreen widget.
- std::unique_ptr<views::Widget> widget = CreateTestWidget();
- widget->SetFullscreen(true);
- WindowState* window_state = WindowState::Get(widget->GetNativeWindow());
- window_state->SetHideShelfWhenFullscreen(true);
- Shelf* const shelf = Shelf::ForWindow(Shell::GetPrimaryRootWindow());
- EXPECT_EQ(SHELF_HIDDEN, shelf->GetVisibilityState());
- // Show app list, which will bring the shelf up.
- GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
- EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
- EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
- // Verify that tapping a shelf button activates it.
- EXPECT_EQ(0u, selection_tracker->item_selected_count());
- const ShelfAppButton* shelf_button = GetButtonByID(app_button_id);
- GetEventGenerator()->GestureTapAt(
- shelf_button->GetBoundsInScreen().CenterPoint());
- EXPECT_EQ(1u, selection_tracker->item_selected_count());
- // Shelf gets hidden when the app list is dismissed.
- GetAppListTestHelper()->DismissAndRunLoop();
- EXPECT_EQ(SHELF_HIDDEN, shelf->GetVisibilityState());
- EXPECT_EQ(0, GetHapticTickEventsCount());
- }
- // Verifies that partying items are hidden from the shelf.
- TEST_P(LtrRtlShelfViewTest, PartyingItemsHiddenFromShelf) {
- AddAppShortcut();
- AddAppShortcut();
- AddApp();
- ShelfItem item = model_->items()[1u];
- item.status = STATUS_RUNNING;
- model_->Set(1, item);
- const gfx::Rect initial_bounds0 = test_api_->GetBoundsByIndex(0);
- const gfx::Rect initial_bounds2 = test_api_->GetBoundsByIndex(2);
- // Start shelf party.
- model_->ToggleShelfParty();
- {
- const std::vector<size_t> not_partying = {1, 3};
- EXPECT_EQ(not_partying, shelf_view_->visible_views_indices());
- }
- test_api_->RunMessageLoopUntilAnimationsDone();
- EXPECT_TRUE(test_api_->GetBoundsByIndex(0).IsEmpty());
- EXPECT_TRUE(test_api_->GetBoundsByIndex(2).IsEmpty());
- // End shelf party.
- model_->ToggleShelfParty();
- {
- const std::vector<size_t> not_partying = {0, 1, 2, 3};
- EXPECT_EQ(not_partying, shelf_view_->visible_views_indices());
- }
- test_api_->RunMessageLoopUntilAnimationsDone();
- EXPECT_EQ(initial_bounds0, test_api_->GetBoundsByIndex(0));
- EXPECT_EQ(initial_bounds2, test_api_->GetBoundsByIndex(2));
- }
- // Test class that tests both context and application menus.
- class ShelfViewMenuTest : public ShelfViewTest,
- public testing::WithParamInterface<bool> {
- public:
- ShelfViewMenuTest() = default;
- ShelfViewMenuTest(const ShelfViewMenuTest&) = delete;
- ShelfViewMenuTest& operator=(const ShelfViewMenuTest&) = delete;
- ~ShelfViewMenuTest() override = default;
- };
- INSTANTIATE_TEST_SUITE_P(All, ShelfViewMenuTest, testing::Bool());
- // Tests that menu anchor points are aligned with the shelf button bounds.
- TEST_P(ShelfViewMenuTest, ShelfViewMenuAnchorPoint) {
- const ShelfAppButton* shelf_button = GetButtonByID(AddApp());
- const bool context_menu = GetParam();
- EXPECT_EQ(ShelfAlignment::kBottom, GetPrimaryShelf()->alignment());
- // Test for bottom shelf.
- EXPECT_EQ(
- shelf_button->GetBoundsInScreen().y(),
- test_api_->GetMenuAnchorRect(*shelf_button, gfx::Point(), context_menu)
- .y());
- // Test for left shelf.
- GetPrimaryShelf()->SetAlignment(ShelfAlignment::kLeft);
- EXPECT_EQ(
- shelf_button->GetBoundsInScreen().x(),
- test_api_->GetMenuAnchorRect(*shelf_button, gfx::Point(), context_menu)
- .x());
- // Test for right shelf.
- GetPrimaryShelf()->SetAlignment(ShelfAlignment::kRight);
- EXPECT_EQ(
- shelf_button->GetBoundsInScreen().x(),
- test_api_->GetMenuAnchorRect(*shelf_button, gfx::Point(), context_menu)
- .x());
- }
- // Tests that an item has a notification badge indicator when the notification
- // is added and removed.
- TEST_F(ShelfViewTest, ItemHasCorrectNotificationBadgeIndicator) {
- const ShelfID item_id = AddApp();
- const ShelfAppButton* shelf_app_button = GetButtonByID(item_id);
- EXPECT_FALSE(GetItemByID(item_id).has_notification);
- EXPECT_FALSE(shelf_app_button->state() & ShelfAppButton::STATE_NOTIFICATION);
- // Add a notification for the new shelf item.
- model_->UpdateItemNotification(item_id.app_id, true /* has_badge */);
- EXPECT_TRUE(GetItemByID(item_id).has_notification);
- EXPECT_TRUE(shelf_app_button->state() & ShelfAppButton::STATE_NOTIFICATION);
- // Remove notification.
- model_->UpdateItemNotification(item_id.app_id, false /* has_badge */);
- EXPECT_FALSE(GetItemByID(item_id).has_notification);
- EXPECT_FALSE(shelf_app_button->state() & ShelfAppButton::STATE_NOTIFICATION);
- }
- class GhostImageShelfViewTest : public ShelfViewTest {
- public:
- GhostImageShelfViewTest() = default;
- GhostImageShelfViewTest(const GhostImageShelfViewTest&) = delete;
- GhostImageShelfViewTest& operator=(const GhostImageShelfViewTest&) = delete;
- ~GhostImageShelfViewTest() override = default;
- void StartDrag(ShelfAppButton* dragged) {
- ASSERT_TRUE(dragged);
- ui::test::EventGenerator* generator = GetEventGenerator();
- generator->set_current_screen_location(
- dragged->GetBoundsInScreen().CenterPoint());
- generator->PressTouch();
- ASSERT_TRUE(dragged->FireDragTimerForTest());
- }
- };
- // Tests that the ghost image shows during a drag operation.
- TEST_F(GhostImageShelfViewTest, ShowGhostImageOnDrag) {
- std::vector<std::pair<ShelfID, views::View*>> id_map;
- SetupForDragTest(&id_map);
- ShelfAppButton* first_app = GetButtonByID(id_map[0].first);
- StartDrag(first_app);
- EXPECT_EQ(0, GetHapticTickEventsCount());
- EXPECT_TRUE(first_app->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(shelf_view_->current_ghost_view_index().has_value());
- ShelfID second_app_id = id_map[1].first;
- GetEventGenerator()->MoveTouch(GetButtonCenter(second_app_id));
- EXPECT_TRUE(first_app->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_TRUE(shelf_view_->drag_view());
- EXPECT_EQ(1u, shelf_view_->current_ghost_view_index());
- GetEventGenerator()->ReleaseTouch();
- EXPECT_EQ(0, GetHapticTickEventsCount());
- EXPECT_FALSE(first_app->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(shelf_view_->current_ghost_view_index().has_value());
- }
- // Tests that the ghost image is removed if the app is dragged outide of the
- // bounds of the shelf.
- TEST_F(GhostImageShelfViewTest, RemoveGhostImageForRipOffDrag) {
- std::vector<std::pair<ShelfID, views::View*>> id_map;
- SetupForDragTest(&id_map);
- ShelfAppButton* first_app = GetButtonByID(id_map[0].first);
- StartDrag(first_app);
- EXPECT_EQ(0, GetHapticTickEventsCount());
- EXPECT_TRUE(first_app->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(shelf_view_->current_ghost_view_index().has_value());
- ShelfID second_app_id = id_map[1].first;
- GetEventGenerator()->MoveTouch(GetButtonCenter(second_app_id));
- EXPECT_TRUE(first_app->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_TRUE(shelf_view_->drag_view());
- EXPECT_EQ(1u, shelf_view_->current_ghost_view_index());
- // The rip off threshold. Taken from |kRipOffDistance| in shelf_view.cc.
- constexpr int kRipOffDistance = 48;
- // Drag off the shelf to trigger rip off drag.
- GetEventGenerator()->MoveTouch(shelf_view_->GetBoundsInScreen().top_center());
- GetEventGenerator()->MoveTouchBy(0, -kRipOffDistance - 1);
- EXPECT_TRUE(first_app->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_TRUE(shelf_view_->drag_view());
- EXPECT_FALSE(shelf_view_->current_ghost_view_index().has_value());
- GetEventGenerator()->ReleaseTouch();
- EXPECT_EQ(0, GetHapticTickEventsCount());
- EXPECT_FALSE(first_app->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(shelf_view_->current_ghost_view_index().has_value());
- }
- // Tests that the ghost image is reinserted if the app is dragged within the
- // bounds of the shelf after a rip off.
- TEST_F(GhostImageShelfViewTest, ReinsertGhostImageAfterRipOffDrag) {
- std::vector<std::pair<ShelfID, views::View*>> id_map;
- SetupForDragTest(&id_map);
- ShelfAppButton* first_app = GetButtonByID(id_map[0].first);
- StartDrag(first_app);
- EXPECT_EQ(0, GetHapticTickEventsCount());
- EXPECT_TRUE(first_app->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(shelf_view_->current_ghost_view_index().has_value());
- ShelfID second_app_id = id_map[1].first;
- GetEventGenerator()->MoveTouch(GetButtonCenter(second_app_id));
- EXPECT_TRUE(first_app->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_TRUE(shelf_view_->drag_view());
- EXPECT_EQ(1u, shelf_view_->current_ghost_view_index());
- // The rip off threshold. Taken from |kRipOffDistance| in shelf_view.cc.
- constexpr int kRipOffDistance = 48;
- // Drag off the shelf to trigger rip off drag.
- GetEventGenerator()->MoveTouch(shelf_view_->GetBoundsInScreen().top_center());
- GetEventGenerator()->MoveTouchBy(0, -kRipOffDistance - 1);
- EXPECT_TRUE(first_app->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_TRUE(shelf_view_->drag_view());
- EXPECT_FALSE(shelf_view_->current_ghost_view_index().has_value());
- GetEventGenerator()->MoveTouch(GetButtonCenter(second_app_id));
- EXPECT_TRUE(first_app->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_TRUE(shelf_view_->drag_view());
- EXPECT_EQ(1u, shelf_view_->current_ghost_view_index());
- GetEventGenerator()->ReleaseTouch();
- EXPECT_EQ(0, GetHapticTickEventsCount());
- EXPECT_FALSE(first_app->state() & ShelfAppButton::STATE_DRAGGING);
- EXPECT_FALSE(shelf_view_->drag_view());
- EXPECT_FALSE(shelf_view_->current_ghost_view_index().has_value());
- }
- class ShelfViewVisibleBoundsTest : public ShelfViewTest,
- public testing::WithParamInterface<bool> {
- public:
- ShelfViewVisibleBoundsTest() : scoped_locale_(GetParam() ? "he" : "") {}
- ShelfViewVisibleBoundsTest(const ShelfViewVisibleBoundsTest&) = delete;
- ShelfViewVisibleBoundsTest& operator=(const ShelfViewVisibleBoundsTest&) =
- delete;
- void CheckAllItemsAreInBounds() {
- gfx::Rect visible_bounds = shelf_view_->GetVisibleItemsBoundsInScreen();
- gfx::Rect shelf_bounds = shelf_view_->GetBoundsInScreen();
- EXPECT_TRUE(shelf_bounds.Contains(visible_bounds));
- for (size_t i = 0; i < test_api_->GetButtonCount(); ++i)
- if (ShelfAppButton* button = test_api_->GetButton(i)) {
- if (button->GetVisible())
- EXPECT_TRUE(visible_bounds.Contains(button->GetBoundsInScreen()));
- }
- }
- private:
- // Restores locale to the default when destructor is called.
- base::test::ScopedRestoreICUDefaultLocale scoped_locale_;
- };
- TEST_P(ShelfViewVisibleBoundsTest, ItemsAreInBounds) {
- // Adding elements leaving some empty space.
- for (int i = 0; i < 3; i++) {
- AddAppShortcut();
- }
- test_api_->RunMessageLoopUntilAnimationsDone();
- CheckAllItemsAreInBounds();
- }
- INSTANTIATE_TEST_SUITE_P(LtrRtl, ShelfViewVisibleBoundsTest, testing::Bool());
- namespace {
- // An InkDrop implementation that wraps another InkDrop instance to keep track
- // of state changes requested on it. Note that this will only track transitions
- // routed through AnimateToState() and not the ones performed directly on the
- // ripple inside the contained |ink_drop|.
- class InkDropSpy : public views::InkDrop {
- public:
- explicit InkDropSpy(std::unique_ptr<views::InkDrop> ink_drop)
- : ink_drop_(std::move(ink_drop)) {}
- InkDropSpy(const InkDropSpy&) = delete;
- InkDropSpy& operator=(const InkDropSpy&) = delete;
- ~InkDropSpy() override = default;
- std::vector<views::InkDropState> GetAndResetRequestedStates() {
- std::vector<views::InkDropState> requested_states;
- requested_states.swap(requested_states_);
- return requested_states;
- }
- // views::InkDrop:
- void HostSizeChanged(const gfx::Size& new_size) override {
- ink_drop_->HostSizeChanged(new_size);
- }
- void HostTransformChanged(const gfx::Transform& new_transform) override {
- ink_drop_->HostTransformChanged(new_transform);
- }
- views::InkDropState GetTargetInkDropState() const override {
- return ink_drop_->GetTargetInkDropState();
- }
- void AnimateToState(views::InkDropState ink_drop_state) override {
- requested_states_.push_back(ink_drop_state);
- ink_drop_->AnimateToState(ink_drop_state);
- }
- void SetHoverHighlightFadeDuration(base::TimeDelta duration) override {
- ink_drop_->SetHoverHighlightFadeDuration(duration);
- }
- void UseDefaultHoverHighlightFadeDuration() override {
- ink_drop_->UseDefaultHoverHighlightFadeDuration();
- }
- void SnapToActivated() override { ink_drop_->SnapToActivated(); }
- void SnapToHidden() override { ink_drop_->SnapToHidden(); }
- void SetHovered(bool is_hovered) override {
- ink_drop_->SetHovered(is_hovered);
- }
- void SetFocused(bool is_focused) override {
- ink_drop_->SetFocused(is_focused);
- }
- bool IsHighlightFadingInOrVisible() const override {
- return ink_drop_->IsHighlightFadingInOrVisible();
- }
- void SetShowHighlightOnHover(bool show_highlight_on_hover) override {
- ink_drop_->SetShowHighlightOnHover(show_highlight_on_hover);
- }
- void SetShowHighlightOnFocus(bool show_highlight_on_focus) override {
- ink_drop_->SetShowHighlightOnFocus(show_highlight_on_focus);
- }
- std::unique_ptr<views::InkDrop> ink_drop_;
- std::vector<views::InkDropState> requested_states_;
- };
- // A ShelfItemDelegate that returns a menu for the shelf item.
- class ListMenuShelfItemDelegate : public ShelfItemDelegate {
- public:
- ListMenuShelfItemDelegate() : ShelfItemDelegate(ShelfID()) {}
- ListMenuShelfItemDelegate(const ListMenuShelfItemDelegate&) = delete;
- ListMenuShelfItemDelegate& operator=(const ListMenuShelfItemDelegate&) =
- delete;
- ~ListMenuShelfItemDelegate() override = default;
- private:
- // ShelfItemDelegate:
- void ItemSelected(std::unique_ptr<ui::Event> event,
- int64_t display_id,
- ShelfLaunchSource source,
- ItemSelectedCallback callback,
- const ItemFilterPredicate& filter_predicate) override {
- // Two items are needed to show a menu; the data in the items is not tested.
- std::move(callback).Run(SHELF_ACTION_NONE, {{}, {}});
- }
- void ExecuteCommand(bool, int64_t, int32_t, int64_t) override {}
- void Close() override {}
- };
- } // namespace
- // Test fixture for testing material design ink drop ripples on shelf.
- class ShelfViewInkDropTest : public ShelfViewTest {
- public:
- ShelfViewInkDropTest() = default;
- ShelfViewInkDropTest(const ShelfViewInkDropTest&) = delete;
- ShelfViewInkDropTest& operator=(const ShelfViewInkDropTest&) = delete;
- ~ShelfViewInkDropTest() override = default;
- protected:
- void InitHomeButtonInkDrop() {
- home_button_ = GetPrimaryShelf()->navigation_widget()->GetHomeButton();
- auto home_button_ink_drop = std::make_unique<InkDropSpy>(
- views::InkDrop::CreateInkDropWithoutAutoHighlight(
- views::InkDrop::Get(home_button_)));
- home_button_ink_drop_ = home_button_ink_drop.get();
- views::test::InkDropHostTestApi(views::InkDrop::Get(home_button_))
- .SetInkDrop(std::move(home_button_ink_drop), false);
- }
- void InitBrowserButtonInkDrop() {
- browser_button_ = test_api_->GetButton(0);
- auto ink_drop_impl = std::make_unique<views::InkDropImpl>(
- views::InkDrop::Get(browser_button_), browser_button_->size(),
- views::InkDropImpl::AutoHighlightMode::NONE);
- browser_button_ink_drop_impl_ = ink_drop_impl.get();
- auto browser_button_ink_drop =
- std::make_unique<InkDropSpy>(std::move(ink_drop_impl));
- browser_button_ink_drop_ = browser_button_ink_drop.get();
- views::test::InkDropHostTestApi(views::InkDrop::Get(browser_button_))
- .SetInkDrop(std::move(browser_button_ink_drop));
- }
- HomeButton* home_button_ = nullptr;
- InkDropSpy* home_button_ink_drop_ = nullptr;
- ShelfAppButton* browser_button_ = nullptr;
- InkDropSpy* browser_button_ink_drop_ = nullptr;
- views::InkDropImpl* browser_button_ink_drop_impl_ = nullptr;
- };
- // Tests that changing visibility of the app list transitions home button's
- // ink drop states correctly.
- TEST_F(ShelfViewInkDropTest, HomeButtonWhenVisibilityChanges) {
- InitHomeButtonInkDrop();
- GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
- EXPECT_EQ(views::InkDropState::ACTIVATED,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTIVATED));
- GetAppListTestHelper()->DismissAndRunLoop();
- EXPECT_EQ(views::InkDropState::HIDDEN,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::DEACTIVATED));
- }
- // Tests that when the app list is hidden, mouse press on the home button,
- // which shows the app list, transitions ink drop states correctly. Also, tests
- // that mouse drag and mouse release does not affect the ink drop state.
- TEST_F(ShelfViewInkDropTest, HomeButtonMouseEventsWhenHidden) {
- InitHomeButtonInkDrop();
- ui::test::EventGenerator* generator = GetEventGenerator();
- generator->MoveMouseTo(home_button_->GetBoundsInScreen().CenterPoint());
- // Mouse press on the button, which shows the app list, should end up in the
- // activated state.
- generator->PressLeftButton();
- GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
- EXPECT_EQ(views::InkDropState::ACTIVATED,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTION_PENDING,
- views::InkDropState::ACTIVATED));
- // Dragging mouse out and back and releasing the button should not change the
- // ink drop state.
- generator->MoveMouseBy(home_button_->width(), 0);
- generator->MoveMouseBy(-home_button_->width(), 0);
- generator->ReleaseLeftButton();
- EXPECT_EQ(views::InkDropState::ACTIVATED,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(), IsEmpty());
- }
- // Tests that when the app list is visible, mouse press on the home button,
- // which dismisses the app list, transitions ink drop states correctly. Also,
- // tests that mouse drag and mouse release does not affect the ink drop state.
- TEST_F(ShelfViewInkDropTest, HomeButtonMouseEventsWhenVisible) {
- InitHomeButtonInkDrop();
- GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
- EXPECT_EQ(views::InkDropState::ACTIVATED,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTIVATED));
- // Mouse press on the button, which dismisses the app list, should end up in
- // the hidden state.
- ui::test::EventGenerator* generator = GetEventGenerator();
- generator->MoveMouseTo(home_button_->GetBoundsInScreen().CenterPoint());
- generator->PressLeftButton();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(views::InkDropState::HIDDEN,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTION_PENDING,
- views::InkDropState::DEACTIVATED));
- // Dragging mouse out and back and releasing the button should not change the
- // ink drop state.
- generator->MoveMouseBy(home_button_->width(), 0);
- generator->MoveMouseBy(-home_button_->width(), 0);
- generator->ReleaseLeftButton();
- EXPECT_EQ(views::InkDropState::HIDDEN,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(), IsEmpty());
- }
- // Tests that when the app list is hidden, tapping on the home button
- // transitions ink drop states correctly.
- TEST_F(ShelfViewInkDropTest, HomeButtonGestureTapWhenHidden) {
- InitHomeButtonInkDrop();
- ui::test::EventGenerator* generator = GetEventGenerator();
- generator->MoveMouseTo(home_button_->GetBoundsInScreen().CenterPoint());
- // Touch press on the button should end up in the pending state.
- generator->PressTouch();
- EXPECT_EQ(views::InkDropState::ACTION_PENDING,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTION_PENDING));
- // Touch release on the button, which shows the app list, should end up in the
- // activated state.
- generator->ReleaseTouch();
- GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
- EXPECT_EQ(views::InkDropState::ACTIVATED,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTION_TRIGGERED,
- views::InkDropState::ACTIVATED));
- }
- // Tests that when the app list is visible, tapping on the home button
- // transitions ink drop states correctly.
- TEST_F(ShelfViewInkDropTest, HomeButtonGestureTapWhenVisible) {
- InitHomeButtonInkDrop();
- GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
- EXPECT_EQ(views::InkDropState::ACTIVATED,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTIVATED));
- // Touch press and release on the button, which dismisses the app list, should
- // end up in the hidden state.
- ui::test::EventGenerator* generator = GetEventGenerator();
- generator->MoveMouseTo(home_button_->GetBoundsInScreen().CenterPoint());
- generator->PressTouch();
- generator->ReleaseTouch();
- GetAppListTestHelper()->WaitUntilIdle();
- EXPECT_EQ(views::InkDropState::HIDDEN,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::DEACTIVATED));
- }
- // Tests that when the app list is hidden, tapping down on the home button
- // and dragging the touch point transitions ink drop states correctly.
- TEST_F(ShelfViewInkDropTest, HomeButtonGestureTapDragWhenHidden) {
- InitHomeButtonInkDrop();
- ui::test::EventGenerator* generator = GetEventGenerator();
- gfx::Point touch_location = home_button_->GetBoundsInScreen().CenterPoint();
- generator->MoveMouseTo(touch_location);
- // Touch press on the button should end up in the pending state.
- generator->PressTouch();
- EXPECT_EQ(views::InkDropState::ACTION_PENDING,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTION_PENDING));
- // Dragging the touch point should hide the pending ink drop.
- touch_location.Offset(home_button_->width(), 0);
- generator->MoveTouch(touch_location);
- EXPECT_EQ(views::InkDropState::HIDDEN,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTION_TRIGGERED));
- // Touch release should not change the ink drop state.
- generator->ReleaseTouch();
- EXPECT_EQ(views::InkDropState::HIDDEN,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(), IsEmpty());
- }
- // Tests that when the app list is visible, tapping down on the home button
- // and dragging the touch point will not change ink drop states.
- TEST_F(ShelfViewInkDropTest, HomeButtonGestureTapDragWhenVisible) {
- InitHomeButtonInkDrop();
- GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
- EXPECT_EQ(views::InkDropState::ACTIVATED,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTIVATED));
- // Touch press on the button, dragging the touch point, and releasing, which
- // will not dismisses the app list, should end up in the |ACTIVATED| state.
- ui::test::EventGenerator* generator = GetEventGenerator();
- gfx::Point touch_location = home_button_->GetBoundsInScreen().CenterPoint();
- generator->MoveMouseTo(touch_location);
- // Touch press on the button should not change the ink drop state.
- generator->PressTouch();
- EXPECT_EQ(views::InkDropState::ACTIVATED,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(), IsEmpty());
- // Dragging the touch point should not hide the pending ink drop.
- touch_location.Offset(home_button_->width(), 0);
- generator->MoveTouch(touch_location);
- EXPECT_EQ(views::InkDropState::ACTIVATED,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(), IsEmpty());
- // Touch release should not change the ink drop state.
- generator->ReleaseTouch();
- EXPECT_EQ(views::InkDropState::ACTIVATED,
- home_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(home_button_ink_drop_->GetAndResetRequestedStates(), IsEmpty());
- }
- // Tests that clicking on a shelf item that does not show a menu transitions ink
- // drop states correctly.
- TEST_F(ShelfViewInkDropTest, ShelfButtonWithoutMenuPressRelease) {
- InitBrowserButtonInkDrop();
- views::Button* button = browser_button_;
- gfx::Point mouse_location = button->GetLocalBounds().CenterPoint();
- ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, mouse_location,
- mouse_location, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMousePressed(press_event);
- EXPECT_EQ(views::InkDropState::ACTION_PENDING,
- browser_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(browser_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTION_PENDING));
- ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, mouse_location,
- mouse_location, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMouseReleased(release_event);
- EXPECT_EQ(views::InkDropState::HIDDEN,
- browser_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(browser_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTION_TRIGGERED));
- }
- // Verifies the shelf view's behavior when opening an empty context menu.
- TEST_F(ShelfViewInkDropTest, ShowEmptyShelfAppContextMenu) {
- InitBrowserButtonInkDrop();
- // Set the shelf item delegate to generate an empty context menu. Note that if
- // we do not specify the shelf item delegate, a default context menu which is
- // non-empty is created.
- const int browser_shortcut_index =
- ShelfModel::Get()->GetItemIndexForType(TYPE_BROWSER_SHORTCUT);
- model_->ReplaceShelfItemDelegate(model_->items()[browser_shortcut_index].id,
- std::make_unique<EmptyContextMenuBuilder>());
- // Right mouse click at the browser button.
- const gfx::Rect button_bounds_in_screen =
- browser_button_->GetBoundsInScreen();
- const gfx::Point button_bounds_center = button_bounds_in_screen.CenterPoint();
- GetEventGenerator()->MoveMouseTo(button_bounds_center);
- GetEventGenerator()->ClickRightButton();
- // Verify that the context menu does not show and the inkdrop is hidden.
- auto* shelf_view = GetPrimaryShelf()->GetShelfViewForTesting();
- EXPECT_FALSE(shelf_view->IsShowingMenu());
- EXPECT_EQ(views::InkDropState::HIDDEN,
- browser_button_ink_drop_->GetTargetInkDropState());
- // Press a point outside of the browser button. Then move the mouse without
- // release.
- gfx::Point press_point(button_bounds_in_screen.right() + 5,
- button_bounds_center.y());
- GetEventGenerator()->MoveMouseTo(press_point);
- GetEventGenerator()->PressLeftButton();
- press_point.Offset(/*x_delta=*/0, /*y_delta=*/-10);
- GetEventGenerator()->MoveMouseTo(press_point);
- // Verify that the browser button is not the mouse handler, which means that
- // the browser button is not under drag.
- EXPECT_FALSE(shelf_view->IsDraggedView(browser_button_));
- }
- // Tests that dragging outside of a shelf item transitions ink drop states
- // correctly.
- TEST_F(ShelfViewInkDropTest, ShelfButtonWithoutMenuPressDragReleaseOutside) {
- InitBrowserButtonInkDrop();
- views::Button* button = browser_button_;
- gfx::Point mouse_location = button->GetLocalBounds().CenterPoint();
- ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, mouse_location,
- mouse_location, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMousePressed(press_event);
- EXPECT_EQ(views::InkDropState::ACTION_PENDING,
- browser_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(browser_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTION_PENDING));
- mouse_location.Offset(test_api_->GetMinimumDragDistance() / 2, 0);
- ui::MouseEvent drag_event_small(ui::ET_MOUSE_DRAGGED, mouse_location,
- mouse_location, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMouseDragged(drag_event_small);
- EXPECT_EQ(views::InkDropState::ACTION_PENDING,
- browser_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(browser_button_ink_drop_->GetAndResetRequestedStates(),
- IsEmpty());
- mouse_location.Offset(test_api_->GetMinimumDragDistance(), 0);
- ui::MouseEvent drag_event_large(ui::ET_MOUSE_DRAGGED, mouse_location,
- mouse_location, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMouseDragged(drag_event_large);
- EXPECT_EQ(views::InkDropState::HIDDEN,
- browser_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(browser_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::HIDDEN));
- ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, mouse_location,
- mouse_location, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMouseReleased(release_event);
- EXPECT_EQ(views::InkDropState::HIDDEN,
- browser_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(browser_button_ink_drop_->GetAndResetRequestedStates(),
- IsEmpty());
- }
- // Tests that dragging outside of a shelf item and back transitions ink drop
- // states correctly.
- TEST_F(ShelfViewInkDropTest, ShelfButtonWithoutMenuPressDragReleaseInside) {
- InitBrowserButtonInkDrop();
- views::Button* button = browser_button_;
- gfx::Point mouse_location = button->GetLocalBounds().CenterPoint();
- ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, mouse_location,
- mouse_location, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMousePressed(press_event);
- EXPECT_EQ(views::InkDropState::ACTION_PENDING,
- browser_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(browser_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTION_PENDING));
- mouse_location.Offset(test_api_->GetMinimumDragDistance() * 2, 0);
- ui::MouseEvent drag_event_outside(ui::ET_MOUSE_DRAGGED, mouse_location,
- mouse_location, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMouseDragged(drag_event_outside);
- EXPECT_EQ(views::InkDropState::HIDDEN,
- browser_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(browser_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::HIDDEN));
- mouse_location.Offset(-test_api_->GetMinimumDragDistance() * 2, 0);
- ui::MouseEvent drag_event_inside(ui::ET_MOUSE_DRAGGED, mouse_location,
- mouse_location, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMouseDragged(drag_event_inside);
- EXPECT_EQ(views::InkDropState::HIDDEN,
- browser_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(browser_button_ink_drop_->GetAndResetRequestedStates(),
- IsEmpty());
- ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, mouse_location,
- mouse_location, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMouseReleased(release_event);
- EXPECT_EQ(views::InkDropState::HIDDEN,
- browser_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(browser_button_ink_drop_->GetAndResetRequestedStates(),
- IsEmpty());
- }
- // Tests that clicking on a shelf item that shows an app list menu transitions
- // ink drop state correctly.
- TEST_F(ShelfViewInkDropTest, ShelfButtonWithMenuPressRelease) {
- InitBrowserButtonInkDrop();
- // Set a delegate for the shelf item that returns an app list menu.
- model_->ReplaceShelfItemDelegate(
- model_->items()[0].id, std::make_unique<ListMenuShelfItemDelegate>());
- views::Button* button = browser_button_;
- gfx::Point mouse_location = button->GetLocalBounds().CenterPoint();
- ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, mouse_location,
- mouse_location, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMousePressed(press_event);
- EXPECT_EQ(views::InkDropState::ACTION_PENDING,
- browser_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(browser_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTION_PENDING));
- // Mouse release will spawn a menu which we will then close.
- ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, mouse_location,
- mouse_location, ui::EventTimeForNow(),
- ui::EF_LEFT_MOUSE_BUTTON, 0);
- button->OnMouseReleased(release_event);
- EXPECT_EQ(views::InkDropState::ACTIVATED,
- browser_button_ink_drop_->GetTargetInkDropState());
- EXPECT_TRUE(test_api_->CloseMenu());
- EXPECT_EQ(views::InkDropState::HIDDEN,
- browser_button_ink_drop_->GetTargetInkDropState());
- EXPECT_THAT(browser_button_ink_drop_->GetAndResetRequestedStates(),
- ElementsAre(views::InkDropState::ACTIVATED,
- views::InkDropState::DEACTIVATED));
- }
- TEST_F(ShelfViewInkDropTest, DismissingMenuWithDoubleClickDoesntShowInkDrop) {
- ui::test::EventGenerator* generator = GetEventGenerator();
- InitBrowserButtonInkDrop();
- views::Button* button = browser_button_;
- // Show a context menu on the home button.
- generator->MoveMouseTo(shelf_view_->shelf_widget()
- ->navigation_widget()
- ->GetHomeButton()
- ->GetBoundsInScreen()
- .CenterPoint());
- generator->PressRightButton();
- generator->ReleaseRightButton();
- EXPECT_TRUE(shelf_view_->IsShowingMenu());
- // Now check that double-clicking on the browser button dismisses the context
- // menu, and does not show an ink drop.
- EXPECT_EQ(views::InkDropState::HIDDEN,
- browser_button_ink_drop_->GetTargetInkDropState());
- generator->MoveMouseTo(button->GetBoundsInScreen().CenterPoint());
- generator->DoubleClickLeftButton();
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_EQ(views::InkDropState::HIDDEN,
- browser_button_ink_drop_->GetTargetInkDropState());
- }
- // Tests that the shelf ink drop transforms when the host transforms. Regression
- // test for https://crbug.com/1097044.
- TEST_F(ShelfViewInkDropTest, ShelfButtonTransformed) {
- InitBrowserButtonInkDrop();
- ASSERT_TRUE(browser_button_ink_drop_impl_);
- auto ink_drop_impl_test_api =
- std::make_unique<views::test::InkDropImplTestApi>(
- browser_button_ink_drop_impl_);
- views::Button* button = browser_button_;
- gfx::Transform transform;
- transform.Translate(10, 0);
- button->SetTransform(transform);
- EXPECT_EQ(transform, ink_drop_impl_test_api->GetRootLayer()->transform());
- button->SetTransform(gfx::Transform());
- EXPECT_EQ(gfx::Transform(),
- ink_drop_impl_test_api->GetRootLayer()->transform());
- }
- class ShelfViewFocusTest : public ShelfViewTest {
- public:
- ShelfViewFocusTest() = default;
- ShelfViewFocusTest(const ShelfViewFocusTest&) = delete;
- ShelfViewFocusTest& operator=(const ShelfViewFocusTest&) = delete;
- ~ShelfViewFocusTest() override = default;
- // AshTestBase:
- void SetUp() override {
- ShelfViewTest::SetUp();
- // Add two app shortcuts for testing.
- AddAppShortcut();
- AddAppShortcut();
- // Focus the home button.
- Shelf* shelf = Shelf::ForWindow(Shell::GetPrimaryRootWindow());
- shelf->shelf_focus_cycler()->FocusNavigation(false /* last_element */);
- }
- void DoTab() {
- ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
- generator.PressKey(ui::KeyboardCode::VKEY_TAB, ui::EF_NONE);
- }
- void DoShiftTab() {
- ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
- generator.PressKey(ui::KeyboardCode::VKEY_TAB, ui::EF_SHIFT_DOWN);
- }
- void DoEnter() {
- ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
- generator.PressKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);
- }
- };
- // Tests that the number of buttons is as expected and the shelf's widget
- // intially has focus.
- TEST_F(ShelfViewFocusTest, Basic) {
- // There are five buttons, including 3 app buttons. The back button and
- // launcher are always there, the browser shortcut is added in
- // ShelfViewTest and the two test apps added in ShelfViewFocusTest.
- EXPECT_EQ(3u, test_api_->GetButtonCount());
- EXPECT_TRUE(GetPrimaryShelf()->navigation_widget()->IsActive());
- // The home button is focused initially because the back button is only
- // visible in tablet mode.
- EXPECT_TRUE(shelf_view_->shelf_widget()
- ->navigation_widget()
- ->GetHomeButton()
- ->HasFocus());
- }
- // Tests that the expected views have focus when cycling through shelf items
- // with tab.
- TEST_F(ShelfViewFocusTest, ForwardCycling) {
- // Pressing tab once should advance focus to the next element after the
- // home button, which is the first app.
- DoTab();
- EXPECT_TRUE(test_api_->GetViewAt(0)->HasFocus());
- DoTab();
- DoTab();
- EXPECT_TRUE(test_api_->GetViewAt(2)->HasFocus());
- }
- // Tests that the expected views have focus when cycling backwards through shelf
- // items with shift tab.
- TEST_F(ShelfViewFocusTest, BackwardCycling) {
- // The first element is currently focused. Let's advance to the last element
- // first.
- EXPECT_TRUE(shelf_view_->shelf_widget()
- ->navigation_widget()
- ->GetHomeButton()
- ->HasFocus());
- DoTab();
- DoTab();
- DoTab();
- EXPECT_TRUE(test_api_->GetViewAt(2)->HasFocus());
- // Pressing shift tab once should advance focus to the previous element.
- DoShiftTab();
- EXPECT_TRUE(test_api_->GetViewAt(1)->HasFocus());
- }
- // Verifies that focus moves as expected between the shelf and the status area.
- TEST_F(ShelfViewFocusTest, FocusCyclingBetweenShelfAndStatusWidget) {
- // The first element of the shelf (the home button) is focused at start.
- EXPECT_TRUE(shelf_view_->shelf_widget()
- ->navigation_widget()
- ->GetHomeButton()
- ->HasFocus());
- // Focus the next few elements.
- DoTab();
- EXPECT_TRUE(test_api_->GetViewAt(0)->HasFocus());
- DoTab();
- EXPECT_TRUE(test_api_->GetViewAt(1)->HasFocus());
- DoTab();
- EXPECT_TRUE(test_api_->GetViewAt(2)->HasFocus());
- // This is the last element. Tabbing once more should go into the status
- // area. If calendar view is enabled it is focusing on the date tray.
- DoTab();
- ExpectNotFocused(shelf_view_);
- ExpectFocused(status_area_);
- // Shift-tab: we should be back at the last element in the shelf.
- DoShiftTab();
- EXPECT_TRUE(test_api_->GetViewAt(2)->HasFocus());
- ExpectNotFocused(status_area_);
- // Go into the status area again.
- DoTab();
- ExpectNotFocused(shelf_view_);
- ExpectFocused(status_area_);
- // If calendar view is enabled, move the focusing ring from the date tray to
- // the unified tray.
- if (features::IsCalendarViewEnabled()) {
- DoTab();
- ExpectNotFocused(shelf_view_);
- ExpectFocused(status_area_);
- }
- // And keep going forward, now we should be cycling back to the first shelf
- // element.
- DoTab();
- EXPECT_TRUE(shelf_view_->shelf_widget()
- ->navigation_widget()
- ->GetHomeButton()
- ->HasFocus());
- ExpectNotFocused(status_area_);
- }
- // Verifies that hitting the Esc key can consistently unfocus the shelf.
- TEST_F(ShelfViewFocusTest, UnfocusWithEsc) {
- // The home button is focused at start.
- EXPECT_TRUE(shelf_view_->shelf_widget()
- ->navigation_widget()
- ->GetHomeButton()
- ->HasFocus());
- // Focus the status area.
- DoShiftTab();
- ExpectNotFocused(shelf_view_);
- ExpectFocused(status_area_);
- // If calendar view is enabled, move the focusing ring from the unified tray
- // to the date tray.
- if (features::IsCalendarViewEnabled()) {
- DoShiftTab();
- ExpectNotFocused(shelf_view_);
- ExpectFocused(status_area_);
- }
- // Advance backwards to the last element of the shelf.
- DoShiftTab();
- ExpectNotFocused(status_area_);
- ExpectFocused(shelf_view_);
- // Press Escape. Nothing should be focused.
- ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, ui::EF_NONE);
- shelf_view_->GetWidget()->OnKeyEvent(&key_event);
- ExpectNotFocused(status_area_);
- ExpectNotFocused(shelf_view_);
- }
- class ShelfViewFocusWithNoShelfNavigationTest : public ShelfViewFocusTest {
- public:
- ShelfViewFocusWithNoShelfNavigationTest() {
- scoped_feature_list_.InitWithFeatures(
- {features::kHideShelfControlsInTabletMode}, {});
- }
- ~ShelfViewFocusWithNoShelfNavigationTest() override = default;
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
- };
- TEST_F(ShelfViewFocusWithNoShelfNavigationTest,
- ShelfWithoutNavigationControls) {
- // The home button is focused at start.
- ASSERT_TRUE(GetPrimaryShelf()->navigation_widget()->GetHomeButton());
- EXPECT_TRUE(shelf_view_->shelf_widget()
- ->navigation_widget()
- ->GetHomeButton()
- ->HasFocus());
- // Switch to tablet mode, which should hide navigation buttons.
- Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
- test_api_->RunMessageLoopUntilAnimationsDone();
- ASSERT_FALSE(GetPrimaryShelf()->navigation_widget()->GetHomeButton());
- ExpectFocused(status_area_);
- // Verify focus cycling skips the navigation widget.
- DoTab();
- ExpectFocused(status_area_);
- DoTab();
- ExpectFocused(shelf_view_);
- DoShiftTab();
- ExpectFocused(status_area_);
- }
- class ShelfViewGestureTapTest : public ShelfViewTest {
- public:
- ShelfViewGestureTapTest()
- : ShelfViewTest(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
- ~ShelfViewGestureTapTest() override = default;
- // ShelfViewTest:
- void SetUp() override {
- ShelfViewTest::SetUp();
- app_icon1_ = GetButtonByID(AddAppShortcut());
- app_icon2_ = GetButtonByID(AddAppShortcut());
- }
- views::InkDropState GetInkDropStateOfAppIcon1() const {
- return views::InkDrop::Get(app_icon1_)
- ->GetInkDrop()
- ->GetTargetInkDropState();
- }
- protected:
- ShelfAppButton* app_icon1_ = nullptr;
- ShelfAppButton* app_icon2_ = nullptr;
- };
- // Verifies the shelf app button's inkdrop behavior when the mouse click
- // occurs after gesture long press but before the end of gesture.
- TEST_F(ShelfViewGestureTapTest, MouseClickInterruptionAfterGestureLongPress) {
- const gfx::Point app_icon1_center_point =
- app_icon1_->GetBoundsInScreen().CenterPoint();
- GetEventGenerator()->PressTouch(app_icon1_center_point);
- // Fast forward to generate the ET_GESTURE_SHOW_PRESS event.
- task_environment()->FastForwardBy(base::Milliseconds(200));
- // Fast forward to generate the ET_GESTURE_LONG_PRESS event to show the
- // context menu.
- task_environment()->FastForwardBy(base::Milliseconds(1000));
- ASSERT_TRUE(shelf_view_->IsShowingMenu());
- // Mouse click at `app_icon2_` while gesture pressing `app_icon1_`.
- GetEventGenerator()->MoveMouseTo(
- app_icon2_->GetBoundsInScreen().CenterPoint());
- GetEventGenerator()->ClickLeftButton();
- // Release the gesture press on `app_icon1_`.
- GetEventGenerator()->set_current_screen_location(app_icon1_center_point);
- GetEventGenerator()->ReleaseTouch();
- // Verify that the context menu shows and `app_icon1_`'s inkdrop is activated.
- EXPECT_TRUE(shelf_view_->IsShowingMenu());
- EXPECT_EQ(views::InkDropState::ACTIVATED, GetInkDropStateOfAppIcon1());
- // Click at the mouse left button at an empty space. Verify that the context
- // menu is closed and the inkdrop is deactivated.
- GetEventGenerator()->MoveMouseTo(GetPrimaryDisplay().bounds().CenterPoint());
- GetEventGenerator()->ClickLeftButton();
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_EQ(views::InkDropState::HIDDEN, GetInkDropStateOfAppIcon1());
- }
- // Verifies that removing an item that is still waiting for the context menu
- // model works as expected.
- TEST_F(ShelfViewGestureTapTest, InterruptContextMenuShowByItemRemoval) {
- // Add two shelf app buttons.
- const ShelfID id1 = AddAppShortcut();
- const ShelfID id2 = AddAppShortcut();
- auto item_delegate_owned =
- std::make_unique<AsyncContextMenuShelfItemDelegate>();
- AsyncContextMenuShelfItemDelegate* item_delegate = item_delegate_owned.get();
- model_->ReplaceShelfItemDelegate(id1, std::move(item_delegate_owned));
- ShelfAppButton* app_button = GetButtonByID(id1);
- GetEventGenerator()->MoveTouch(app_button->GetBoundsInScreen().CenterPoint());
- GetEventGenerator()->PressTouch();
- // Fast forward to generate the ET_GESTURE_SHOW_PRESS event.
- task_environment()->FastForwardBy(base::Milliseconds(200));
- // Fast forward to generate the ET_GESTURE_LONG_PRESS event to show the
- // context menu.
- task_environment()->FastForwardBy(base::Milliseconds(1000));
- EXPECT_TRUE(item_delegate->HasPendingContextMenuCallback());
- // Remove the shelf item indexed by `id` before handling the pending context
- // menu model request.
- const int index = ShelfModel::Get()->ItemIndexByID(id1);
- ShelfModel::Get()->RemoveItemAt(index);
- EXPECT_FALSE(shelf_view_->drag_view());
- // Initialize the mouse drag on the shelf app button specified by `id2`.
- ShelfAppButton* app_button2 = GetButtonByID(id2);
- GetEventGenerator()->MoveMouseTo(
- app_button2->GetBoundsInScreen().CenterPoint());
- GetEventGenerator()->PressLeftButton();
- task_environment()->FastForwardBy(base::Milliseconds(200));
- // Move the mouse. Verify that the shelf view has a view under drag.
- GetEventGenerator()->MoveMouseBy(0, -100);
- EXPECT_TRUE(shelf_view_->drag_view());
- }
- TEST_F(ShelfViewGestureTapTest,
- PressEscapeKeyBeforeReleaseLongPressOnAppButton) {
- const ShelfID id = AddAppShortcut();
- auto item_delegate_owned =
- std::make_unique<AsyncContextMenuShelfItemDelegate>();
- AsyncContextMenuShelfItemDelegate* item_delegate = item_delegate_owned.get();
- model_->ReplaceShelfItemDelegate(id, std::move(item_delegate_owned));
- ShelfAppButton* app_button = GetButtonByID(id);
- GetEventGenerator()->MoveTouch(app_button->GetBoundsInScreen().CenterPoint());
- GetEventGenerator()->PressTouch();
- // Fast forward to generate the ET_GESTURE_SHOW_PRESS event.
- task_environment()->FastForwardBy(base::Milliseconds(200));
- // Fast forward to generate the ET_GESTURE_LONG_PRESS event to show the
- // context menu.
- task_environment()->FastForwardBy(base::Milliseconds(1000));
- EXPECT_TRUE(item_delegate->HasPendingContextMenuCallback());
- // Build a dummy context menu and show it.
- {
- auto menu_model = std::make_unique<ui::SimpleMenuModel>(nullptr);
- menu_model->AddItem(203, u"item");
- item_delegate->RunPendingContextMenuCallback(std::move(menu_model));
- EXPECT_TRUE(shelf_view_->IsShowingMenuForView(app_button));
- }
- // Press Escape. The context menu should be closed.
- GetEventGenerator()->PressAndReleaseKey(ui::VKEY_ESCAPE);
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_FALSE(item_delegate->HasPendingContextMenuCallback());
- // Release the gesture press. The context menu should show again.
- GetEventGenerator()->ReleaseTouch();
- task_environment()->FastForwardBy(base::Milliseconds(1000));
- EXPECT_TRUE(item_delegate->HasPendingContextMenuCallback());
- {
- auto menu_model = std::make_unique<ui::SimpleMenuModel>(nullptr);
- menu_model->AddItem(203, u"item");
- item_delegate->RunPendingContextMenuCallback(std::move(menu_model));
- EXPECT_TRUE(shelf_view_->IsShowingMenuForView(app_button));
- }
- // Verify that the ink drop of the app button for which the context menu shows
- // for is activated.
- EXPECT_EQ(
- views::InkDropState::ACTIVATED,
- views::InkDrop::Get(app_button)->GetInkDrop()->GetTargetInkDropState());
- }
- // Verifies the shelf app button's inkdrop behavior when the mouse click
- // occurs before gesture long press.
- TEST_F(ShelfViewGestureTapTest, MouseClickInterruptionBeforeGestureLongPress) {
- const gfx::Point app_icon1_center_point =
- app_icon1_->GetBoundsInScreen().CenterPoint();
- GetEventGenerator()->PressTouch(app_icon1_center_point);
- // Fast forward to generate the ET_GESTURE_SHOW_PRESS event.
- task_environment()->FastForwardBy(base::Milliseconds(200));
- // Mouse click at `app_icon2_` while gesture pressing `app_icon1_`. Note that
- // we do not need to release the touch on `app_icon1_` because the gesture
- // is interrupted by the mouse click.
- GetEventGenerator()->MoveMouseTo(
- app_icon2_->GetBoundsInScreen().CenterPoint());
- GetEventGenerator()->ClickLeftButton();
- // Fast forward until the callback is executed.
- task_environment()->FastForwardBy(base::Milliseconds(200));
- EXPECT_FALSE(shelf_view_->IsShowingMenu());
- EXPECT_EQ(views::InkDropState::HIDDEN, GetInkDropStateOfAppIcon1());
- }
- } // namespace ash
|