123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443 |
- // Copyright 2022 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/accessibility/accessibility_controller_impl.h"
- #include "ash/accessibility/autoclick/autoclick_controller.h"
- #include "ash/capture_mode/capture_mode_bar_view.h"
- #include "ash/capture_mode/capture_mode_button.h"
- #include "ash/capture_mode/capture_mode_camera_controller.h"
- #include "ash/capture_mode/capture_mode_camera_preview_view.h"
- #include "ash/capture_mode/capture_mode_constants.h"
- #include "ash/capture_mode/capture_mode_controller.h"
- #include "ash/capture_mode/capture_mode_menu_group.h"
- #include "ash/capture_mode/capture_mode_metrics.h"
- #include "ash/capture_mode/capture_mode_session.h"
- #include "ash/capture_mode/capture_mode_session_test_api.h"
- #include "ash/capture_mode/capture_mode_settings_test_api.h"
- #include "ash/capture_mode/capture_mode_settings_view.h"
- #include "ash/capture_mode/capture_mode_test_util.h"
- #include "ash/capture_mode/capture_mode_toast_controller.h"
- #include "ash/capture_mode/capture_mode_toggle_button.h"
- #include "ash/capture_mode/capture_mode_types.h"
- #include "ash/capture_mode/capture_mode_util.h"
- #include "ash/capture_mode/fake_camera_device.h"
- #include "ash/capture_mode/fake_folder_selection_dialog_factory.h"
- #include "ash/capture_mode/fake_video_source_provider.h"
- #include "ash/capture_mode/test_capture_mode_delegate.h"
- #include "ash/display/window_tree_host_manager.h"
- #include "ash/public/cpp/capture_mode/capture_mode_test_api.h"
- #include "ash/public/cpp/window_properties.h"
- #include "ash/resources/vector_icons/vector_icons.h"
- #include "ash/shell.h"
- #include "ash/strings/grit/ash_strings.h"
- #include "ash/style/ash_color_provider.h"
- #include "ash/system/accessibility/autoclick_menu_bubble_controller.h"
- #include "ash/system/unified/unified_system_tray.h"
- #include "ash/test/ash_test_base.h"
- #include "ash/wm/window_state.h"
- #include "base/strings/stringprintf.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/system/system_monitor.h"
- #include "base/test/bind.h"
- #include "base/test/metrics/histogram_tester.h"
- #include "base/timer/timer.h"
- #include "cc/paint/skia_paint_canvas.h"
- #include "media/base/video_facing.h"
- #include "media/base/video_frame.h"
- #include "media/renderers/paint_canvas_video_renderer.h"
- #include "third_party/skia/include/core/SkBitmap.h"
- #include "ui/base/l10n/l10n_util.h"
- #include "ui/base/ui_base_types.h"
- #include "ui/compositor/compositor_switches.h"
- #include "ui/compositor/layer.h"
- #include "ui/gfx/geometry/point.h"
- #include "ui/gfx/geometry/rect.h"
- #include "ui/gfx/geometry/size.h"
- #include "ui/gfx/geometry/vector2d.h"
- #include "ui/gfx/image/image_unittest_util.h"
- #include "ui/gfx/paint_vector_icon.h"
- #include "ui/views/view.h"
- #include "ui/views/view_observer.h"
- #include "ui/views/widget/widget.h"
- #include "ui/wm/core/coordinate_conversion.h"
- #include "ui/wm/core/window_util.h"
- namespace ash {
- namespace {
- constexpr char kDefaultCameraDeviceId[] = "/dev/videoX";
- constexpr char kDefaultCameraDisplayName[] = "Default Cam";
- constexpr char kDefaultCameraModelId[] = "0def:c000";
- TestCaptureModeDelegate* GetTestDelegate() {
- return static_cast<TestCaptureModeDelegate*>(
- CaptureModeController::Get()->delegate_for_testing());
- }
- CaptureModeCameraController* GetCameraController() {
- return CaptureModeController::Get()->camera_controller();
- }
- // Returns the current root window where the current capture activities are
- // hosted in.
- aura::Window* GetCurrentRoot() {
- auto* controller = CaptureModeController::Get();
- if (controller->IsActive())
- return controller->capture_mode_session()->current_root();
- if (controller->is_recording_in_progress()) {
- return controller->video_recording_watcher_for_testing()
- ->window_being_recorded()
- ->GetRootWindow();
- }
- return Shell::GetPrimaryRootWindow();
- }
- bool IsWindowStackedRightBelow(aura::Window* window, aura::Window* sibling) {
- DCHECK_EQ(window->parent(), sibling->parent());
- const auto& children = window->parent()->children();
- const int sibling_index =
- std::find(children.begin(), children.end(), sibling) - children.begin();
- return sibling_index > 0 && children[sibling_index - 1] == window;
- }
- // Defines a waiter for the camera devices change notifications.
- class CameraDevicesChangeWaiter : public CaptureModeCameraController::Observer {
- public:
- CameraDevicesChangeWaiter() { GetCameraController()->AddObserver(this); }
- CameraDevicesChangeWaiter(const CameraDevicesChangeWaiter&) = delete;
- CameraDevicesChangeWaiter& operator=(const CameraDevicesChangeWaiter&) =
- delete;
- ~CameraDevicesChangeWaiter() override {
- GetCameraController()->RemoveObserver(this);
- }
- int camera_change_event_count() const { return camera_change_event_count_; }
- int selected_camera_change_event_count() const {
- return selected_camera_change_event_count_;
- }
- void Wait() { loop_.Run(); }
- // CaptureModeCameraController::Observer:
- void OnAvailableCamerasChanged(const CameraInfoList& cameras) override {
- ++camera_change_event_count_;
- loop_.Quit();
- }
- void OnSelectedCameraChanged(const CameraId& camera_id) override {
- ++selected_camera_change_event_count_;
- }
- private:
- base::RunLoop loop_;
- // Tracks the number of times the observer call `OnAvailableCamerasChanged()`
- // was triggered.
- int camera_change_event_count_ = 0;
- // Tracks the number of times `OnSelectedCameraChanged()` was triggered.
- int selected_camera_change_event_count_ = 0;
- };
- // Defines a waiter to observe the visibility change of the view.
- class ViewVisibilityChangeWaiter : public views::ViewObserver {
- public:
- explicit ViewVisibilityChangeWaiter(views::View* view) : view_(view) {
- view_->AddObserver(this);
- }
- ~ViewVisibilityChangeWaiter() override { view_->RemoveObserver(this); }
- void Wait() { wait_loop_.Run(); }
- // views::ViewObserver:
- void OnViewVisibilityChanged(views::View* observed_view,
- views::View* starting_view) override {
- wait_loop_.Quit();
- }
- private:
- views::View* const view_;
- base::RunLoop wait_loop_;
- };
- gfx::Rect GetTooSmallToFitCameraRegion() {
- return {100, 100,
- capture_mode::kMinCaptureSurfaceShortSideLengthForVisibleCamera - 1,
- capture_mode::kMinCaptureSurfaceShortSideLengthForVisibleCamera - 1};
- }
- } // namespace
- class CaptureModeCameraTest : public AshTestBase {
- public:
- CaptureModeCameraTest() = default;
- CaptureModeCameraTest(const CaptureModeCameraTest&) = delete;
- CaptureModeCameraTest& operator=(const CaptureModeCameraTest&) = delete;
- ~CaptureModeCameraTest() override = default;
- // AshTestBase:
- void SetUp() override {
- AshTestBase::SetUp();
- FakeFolderSelectionDialogFactory::Start();
- window_ = CreateTestWindow(gfx::Rect(30, 40, 600, 500));
- }
- void TearDown() override {
- window_.reset();
- FakeFolderSelectionDialogFactory::Stop();
- AshTestBase::TearDown();
- }
- aura::Window* window() const { return window_.get(); }
- void StartRecordingFromSource(CaptureModeSource source) {
- auto* controller = CaptureModeController::Get();
- controller->SetSource(source);
- switch (source) {
- case CaptureModeSource::kFullscreen:
- case CaptureModeSource::kRegion:
- break;
- case CaptureModeSource::kWindow:
- GetEventGenerator()->MoveMouseTo(
- window_->GetBoundsInScreen().CenterPoint());
- break;
- }
- CaptureModeTestApi().PerformCapture();
- WaitForRecordingToStart();
- EXPECT_TRUE(controller->is_recording_in_progress());
- }
- void AddFakeCamera(const std::string& device_id,
- const std::string& display_name,
- const std::string& model_id,
- media::VideoFacingMode camera_facing_mode =
- media::MEDIA_VIDEO_FACING_NONE) {
- CameraDevicesChangeWaiter waiter;
- GetTestDelegate()->video_source_provider()->AddFakeCamera(
- device_id, display_name, model_id, camera_facing_mode);
- waiter.Wait();
- }
- void RemoveFakeCamera(const std::string& device_id) {
- CameraDevicesChangeWaiter waiter;
- GetTestDelegate()->video_source_provider()->RemoveFakeCamera(device_id);
- waiter.Wait();
- }
- void AddDefaultCamera() {
- AddFakeCamera(kDefaultCameraDeviceId, kDefaultCameraDisplayName,
- kDefaultCameraModelId);
- }
- void RemoveDefaultCamera() { RemoveFakeCamera(kDefaultCameraDeviceId); }
- // Adds the default camera, sets it as the selected camera, then removes it,
- // which triggers the camera disconnection grace period. Returns a pointer to
- // the `CaptureModeCameraController`.
- CaptureModeCameraController* AddAndRemoveCameraAndTriggerGracePeriod() {
- AddDefaultCamera();
- auto* camera_controller = GetCameraController();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- RemoveDefaultCamera();
- return camera_controller;
- }
- void OpenSettingsView() {
- CaptureModeSession* session =
- CaptureModeController::Get()->capture_mode_session();
- DCHECK(session);
- ClickOnView(CaptureModeSessionTestApi(session)
- .GetCaptureModeBarView()
- ->settings_button(),
- GetEventGenerator());
- }
- void DragPreviewToPoint(views::Widget* preview_widget,
- const gfx::Point& screen_location,
- bool by_touch_gestures = false,
- bool drop = true) {
- DCHECK(preview_widget);
- auto* event_generator = GetEventGenerator();
- event_generator->set_current_screen_location(
- preview_widget->GetWindowBoundsInScreen().CenterPoint());
- if (by_touch_gestures) {
- event_generator->PressTouch();
- // Move the touch by an enough amount in X to make sure it generates a
- // serial of gesture scroll events instead of a fling event.
- event_generator->MoveTouchBy(50, 0);
- event_generator->MoveTouch(screen_location);
- if (drop)
- event_generator->ReleaseTouch();
- } else {
- event_generator->PressLeftButton();
- event_generator->MoveMouseTo(screen_location);
- if (drop)
- event_generator->ReleaseLeftButton();
- }
- }
- CaptureModeButton* GetPreviewResizeButton() const {
- return GetCameraController()->camera_preview_view()->resize_button();
- }
- // Verifies that the camera preview is placed on the correct position based on
- // current preview snap position and the given `confine_bounds_in_screen`.
- void VerifyPreviewAlignment(const gfx::Rect& confine_bounds_in_screen) {
- auto* camera_controller = GetCameraController();
- const auto* preview_widget = camera_controller->camera_preview_widget();
- DCHECK(preview_widget);
- const gfx::Rect camera_preview_bounds =
- preview_widget->GetWindowBoundsInScreen();
- switch (camera_controller->camera_preview_snap_position()) {
- case CameraPreviewSnapPosition::kTopLeft: {
- gfx::Point expect_origin = confine_bounds_in_screen.origin();
- expect_origin.Offset(capture_mode::kSpaceBetweenCameraPreviewAndEdges,
- capture_mode::kSpaceBetweenCameraPreviewAndEdges);
- EXPECT_EQ(expect_origin, camera_preview_bounds.origin());
- break;
- }
- case CameraPreviewSnapPosition::kBottomLeft: {
- const gfx::Point expect_bottom_left =
- gfx::Point(confine_bounds_in_screen.x() +
- capture_mode::kSpaceBetweenCameraPreviewAndEdges,
- confine_bounds_in_screen.bottom() -
- capture_mode::kSpaceBetweenCameraPreviewAndEdges);
- EXPECT_EQ(expect_bottom_left, camera_preview_bounds.bottom_left());
- break;
- }
- case CameraPreviewSnapPosition::kBottomRight: {
- const gfx::Point expect_bottom_right =
- gfx::Point(confine_bounds_in_screen.right() -
- capture_mode::kSpaceBetweenCameraPreviewAndEdges,
- confine_bounds_in_screen.bottom() -
- capture_mode::kSpaceBetweenCameraPreviewAndEdges);
- EXPECT_EQ(expect_bottom_right, camera_preview_bounds.bottom_right());
- break;
- }
- case CameraPreviewSnapPosition::kTopRight: {
- const gfx::Point expect_top_right =
- gfx::Point(confine_bounds_in_screen.right() -
- capture_mode::kSpaceBetweenCameraPreviewAndEdges,
- confine_bounds_in_screen.y() +
- capture_mode::kSpaceBetweenCameraPreviewAndEdges);
- EXPECT_EQ(expect_top_right, camera_preview_bounds.top_right());
- break;
- }
- }
- }
- // Verifies that the icon image and the tooltip of the resize button gets
- // updated correctly when pressed.
- void VerifyResizeButton(bool is_collapsed, CaptureModeButton* resize_button) {
- SkColor color = AshColorProvider::Get()->GetContentLayerColor(
- AshColorProvider::ContentLayerType::kIconColorPrimary);
- const gfx::ImageSkia collapse_icon_image =
- gfx::CreateVectorIcon(kCaptureModeCameraPreviewCollapseIcon, color);
- const gfx::ImageSkia expand_icon_image =
- gfx::CreateVectorIcon(kCaptureModeCameraPreviewExpandIcon, color);
- const SkBitmap* expected_icon = is_collapsed ? expand_icon_image.bitmap()
- : collapse_icon_image.bitmap();
- const SkBitmap* actual_icon =
- resize_button->GetImage(views::ImageButton::ButtonState::STATE_NORMAL)
- .bitmap();
- EXPECT_TRUE(gfx::test::AreBitmapsEqual(*actual_icon, *expected_icon));
- const auto expected_tooltip_text = l10n_util::GetStringUTF16(
- is_collapsed ? IDS_ASH_SCREEN_CAPTURE_TOOLTIP_EXPAND_SELFIE_CAMERA
- : IDS_ASH_SCREEN_CAPTURE_TOOLTIP_COLLAPSE_SELFIE_CAMERA);
- EXPECT_EQ(resize_button->GetTooltipText(), expected_tooltip_text);
- }
- // Select capture region by pressing and dragging the mouse.
- void SelectCaptureRegion(const gfx::Rect& region, bool release_mouse = true) {
- auto* controller = CaptureModeController::Get();
- ASSERT_TRUE(controller->IsActive());
- ASSERT_EQ(CaptureModeSource::kRegion, controller->source());
- auto* event_generator = GetEventGenerator();
- event_generator->set_current_screen_location(region.origin());
- event_generator->PressLeftButton();
- event_generator->MoveMouseTo(region.bottom_right());
- if (release_mouse)
- event_generator->ReleaseLeftButton();
- EXPECT_EQ(region, controller->user_capture_region());
- }
- void ConvertToPipWindow(aura::Window* pip_window) {
- WindowState* window_state = WindowState::Get(pip_window);
- DCHECK(!window_state->IsPip());
- views::Widget::GetWidgetForNativeWindow(pip_window)
- ->SetZOrderLevel(ui::ZOrderLevel::kFloatingWindow);
- pip_window->SetProperty(kWindowPipTypeKey, true);
- DCHECK(window_state->IsPip());
- }
- private:
- std::unique_ptr<aura::Window> window_;
- };
- TEST_F(CaptureModeCameraTest, SizeSpecsBigEnoughRegion) {
- gfx::Size confine_bounds_size(800, 700);
- {
- auto specs = capture_mode_util::CalculateCameraPreviewSizeSpecs(
- confine_bounds_size,
- /*is_collapsed=*/false);
- EXPECT_TRUE(specs.is_collapsible);
- EXPECT_TRUE(specs.should_be_visible);
- EXPECT_EQ(specs.size.width(), specs.size.height());
- EXPECT_EQ(specs.size.width(),
- 700 / capture_mode::kCaptureSurfaceShortSideDivider);
- }
- // Transposing the confine bounds (e.g. due to rotation) should have no effect
- // since we always consider the shorter side.
- confine_bounds_size.Transpose();
- {
- auto specs = capture_mode_util::CalculateCameraPreviewSizeSpecs(
- confine_bounds_size,
- /*is_collapsed=*/false);
- EXPECT_TRUE(specs.is_collapsible);
- EXPECT_TRUE(specs.should_be_visible);
- EXPECT_EQ(specs.size.width(),
- 700 / capture_mode::kCaptureSurfaceShortSideDivider);
- }
- {
- auto specs = capture_mode_util::CalculateCameraPreviewSizeSpecs(
- confine_bounds_size,
- /*is_collapsed=*/true);
- EXPECT_TRUE(specs.is_collapsible);
- EXPECT_TRUE(specs.should_be_visible);
- EXPECT_EQ(specs.size.width(), capture_mode::kMinCameraPreviewDiameter);
- }
- }
- TEST_F(CaptureModeCameraTest, SizeSpecsNotCollapsible) {
- gfx::Size confine_bounds_size(800, 500);
- auto specs = capture_mode_util::CalculateCameraPreviewSizeSpecs(
- confine_bounds_size,
- /*is_collapsed=*/false);
- EXPECT_FALSE(specs.is_collapsible);
- EXPECT_TRUE(specs.should_be_visible);
- EXPECT_EQ(specs.size.width(), specs.size.height());
- EXPECT_EQ(specs.size.width(),
- 500 / capture_mode::kCaptureSurfaceShortSideDivider);
- EXPECT_FALSE(specs.is_surface_too_small);
- }
- TEST_F(CaptureModeCameraTest, SizeSpecsHiddenPreview) {
- gfx::Size confine_bounds_size(800, 170);
- auto specs = capture_mode_util::CalculateCameraPreviewSizeSpecs(
- confine_bounds_size,
- /*is_collapsed=*/false);
- EXPECT_FALSE(specs.is_collapsible);
- EXPECT_FALSE(specs.should_be_visible);
- EXPECT_EQ(specs.size.width(), specs.size.height());
- EXPECT_EQ(specs.size.width(), capture_mode::kMinCameraPreviewDiameter);
- EXPECT_TRUE(specs.is_surface_too_small);
- }
- TEST_F(CaptureModeCameraTest, CameraDevicesChanges) {
- auto* camera_controller = GetCameraController();
- ASSERT_TRUE(camera_controller);
- EXPECT_TRUE(camera_controller->available_cameras().empty());
- EXPECT_FALSE(camera_controller->selected_camera().is_valid());
- EXPECT_FALSE(camera_controller->should_show_preview());
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- const std::string device_id = "/dev/video0";
- const std::string display_name = "Integrated Webcam";
- const std::string model_id = "0123:4567";
- AddFakeCamera(device_id, display_name, model_id);
- EXPECT_EQ(1u, camera_controller->available_cameras().size());
- EXPECT_TRUE(camera_controller->available_cameras()[0].camera_id.is_valid());
- EXPECT_EQ(model_id, camera_controller->available_cameras()[0]
- .camera_id.model_id_or_display_name());
- EXPECT_EQ(1, camera_controller->available_cameras()[0].camera_id.number());
- EXPECT_EQ(device_id, camera_controller->available_cameras()[0].device_id);
- EXPECT_EQ(display_name,
- camera_controller->available_cameras()[0].display_name);
- EXPECT_FALSE(camera_controller->should_show_preview());
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- RemoveFakeCamera(device_id);
- EXPECT_TRUE(camera_controller->available_cameras().empty());
- EXPECT_FALSE(camera_controller->should_show_preview());
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- }
- TEST_F(CaptureModeCameraTest, CameraRemovedWhileWaitingForCameraDevices) {
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- EXPECT_EQ(1u, camera_controller->available_cameras().size());
- // The system monitor can trigger several notifications about devices changes
- // for the same camera addition event. We will simulate a camera getting
- // removed right while we're still waiting for the video source provider to
- // send us the list. https://crbug.com/1295377.
- auto* video_source_provider = GetTestDelegate()->video_source_provider();
- {
- base::RunLoop loop;
- video_source_provider->set_on_replied_with_source_infos(
- base::BindLambdaForTesting([&]() { loop.Quit(); }));
- base::SystemMonitor::Get()->ProcessDevicesChanged(
- base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
- loop.Run();
- }
- RemoveDefaultCamera();
- EXPECT_TRUE(camera_controller->available_cameras().empty());
- }
- TEST_F(CaptureModeCameraTest, SelectingUnavailableCamera) {
- StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- // Selecting a camera that doesn't exist in the list shouldn't show its
- // preview.
- camera_controller->SetSelectedCamera(CameraId("model", 1));
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- }
- TEST_F(CaptureModeCameraTest, SelectingAvailableCamera) {
- StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- AddDefaultCamera();
- EXPECT_EQ(1u, camera_controller->available_cameras().size());
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- // Selecting an available camera while showing the preview is allowed should
- // result in creating the preview widget.
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- EXPECT_TRUE(camera_controller->camera_preview_widget());
- }
- TEST_F(CaptureModeCameraTest, SelectedCameraBecomesAvailable) {
- StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- // The selected camera becomes available while `should_show_preview_` is still
- // true. The preview should show in this case.
- AddDefaultCamera();
- EXPECT_TRUE(camera_controller->camera_preview_widget());
- // Clearing the selected camera should hide the preview.
- camera_controller->SetSelectedCamera(CameraId());
- EXPECT_FALSE(camera_controller->selected_camera().is_valid());
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- }
- TEST_F(CaptureModeCameraTest, SelectingDifferentCameraCreatesNewPreviewWidget) {
- AddDefaultCamera();
- const std::string device_id = "/dev/video0";
- const std::string display_name = "Integrated Webcam";
- const std::string model_id = "0123:4567";
- AddFakeCamera(device_id, display_name, model_id);
- StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* current_preview_widget = camera_controller->camera_preview_widget();
- EXPECT_TRUE(current_preview_widget);
- // Selecting a different camera should result in the recreation of the preview
- // widget.
- camera_controller->SetSelectedCamera(CameraId(model_id, 1));
- EXPECT_TRUE(camera_controller->camera_preview_widget());
- EXPECT_NE(current_preview_widget, camera_controller->camera_preview_widget());
- }
- TEST_F(CaptureModeCameraTest, MultipleCamerasOfTheSameModel) {
- auto* camera_controller = GetCameraController();
- const std::string device_id_1 = "/dev/video0";
- const std::string display_name = "Integrated Webcam";
- const std::string model_id = "0123:4567";
- AddFakeCamera(device_id_1, display_name, model_id);
- const auto& available_cameras = camera_controller->available_cameras();
- EXPECT_EQ(1u, available_cameras.size());
- EXPECT_EQ(1, available_cameras[0].camera_id.number());
- EXPECT_EQ(model_id,
- available_cameras[0].camera_id.model_id_or_display_name());
- // Adding a new camera of the same model should be correctly tracked with a
- // different ID.
- const std::string device_id_2 = "/dev/video1";
- AddFakeCamera(device_id_2, display_name, model_id);
- EXPECT_EQ(2u, available_cameras.size());
- EXPECT_EQ(2, available_cameras[1].camera_id.number());
- EXPECT_EQ(model_id,
- available_cameras[1].camera_id.model_id_or_display_name());
- EXPECT_NE(available_cameras[0].camera_id, available_cameras[1].camera_id);
- }
- TEST_F(CaptureModeCameraTest, MissingCameraModelId) {
- auto* camera_controller = GetCameraController();
- const std::string device_id = "/dev/video0";
- const std::string display_name = "Integrated Webcam";
- AddFakeCamera(device_id, display_name, /*model_id=*/"");
- // The camera's display name should be used instead of a model ID when it's
- // missing.
- const auto& available_cameras = camera_controller->available_cameras();
- EXPECT_EQ(1u, available_cameras.size());
- EXPECT_TRUE(available_cameras[0].camera_id.is_valid());
- EXPECT_EQ(1, available_cameras[0].camera_id.number());
- EXPECT_EQ(display_name,
- available_cameras[0].camera_id.model_id_or_display_name());
- // If the SystemMonitor triggered a device change alert for some reason, but
- // the actual list of cameras didn't change, observers should never be
- // notified again.
- {
- base::RunLoop loop;
- camera_controller->SetOnCameraListReceivedForTesting(loop.QuitClosure());
- CameraDevicesChangeWaiter observer;
- base::SystemMonitor::Get()->ProcessDevicesChanged(
- base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
- loop.Run();
- EXPECT_EQ(0, observer.camera_change_event_count());
- }
- }
- TEST_F(CaptureModeCameraTest, CameraFramesFlipping) {
- StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- int index = 0;
- for (const auto facing_mode :
- {media::MEDIA_VIDEO_FACING_NONE, media::MEDIA_VIDEO_FACING_USER,
- media::MEDIA_VIDEO_FACING_ENVIRONMENT}) {
- const std::string device_id = base::StringPrintf("/dev/video%d", index);
- const std::string display_name = base::StringPrintf("Camera %d", index);
- AddFakeCamera(device_id, display_name, display_name, facing_mode);
- camera_controller->SetSelectedCamera(CameraId(display_name, 1));
- EXPECT_TRUE(camera_controller->camera_preview_widget());
- const bool should_be_flipped =
- facing_mode != media::MEDIA_VIDEO_FACING_ENVIRONMENT;
- EXPECT_EQ(should_be_flipped, camera_controller->camera_preview_view()
- ->should_flip_frames_horizontally())
- << "Failed for facing mode: " << facing_mode;
- ++index;
- }
- }
- TEST_F(CaptureModeCameraTest, DisconnectSelectedCamera) {
- AddDefaultCamera();
- auto* camera_controller = GetCameraController();
- const CameraId camera_id(kDefaultCameraModelId, 1);
- camera_controller->SetSelectedCamera(camera_id);
- // Disconnect a selected camera, and expect that the grace period timer is
- // running.
- RemoveDefaultCamera();
- base::OneShotTimer* timer =
- camera_controller->camera_reconnect_timer_for_test();
- EXPECT_TRUE(timer->IsRunning());
- EXPECT_EQ(camera_id, camera_controller->selected_camera());
- // When the timer fires before the camera gets reconnected, the selected
- // camera ID is cleared.
- timer->FireNow();
- EXPECT_FALSE(camera_controller->selected_camera().is_valid());
- EXPECT_FALSE(timer->IsRunning());
- }
- TEST_F(CaptureModeCameraTest, SelectUnavailableCameraDuringGracePeriod) {
- auto* camera_controller = AddAndRemoveCameraAndTriggerGracePeriod();
- base::OneShotTimer* timer =
- camera_controller->camera_reconnect_timer_for_test();
- EXPECT_TRUE(timer->IsRunning());
- // Selecting an unavailable camera during the grace period should keep the
- // timer running for another grace period.
- const CameraId new_camera_id("Different Camera", 1);
- camera_controller->SetSelectedCamera(new_camera_id);
- EXPECT_TRUE(timer->IsRunning());
- EXPECT_EQ(new_camera_id, camera_controller->selected_camera());
- // Once the timer fires the new ID will also be cleared.
- timer->FireNow();
- EXPECT_FALSE(camera_controller->selected_camera().is_valid());
- EXPECT_FALSE(timer->IsRunning());
- }
- TEST_F(CaptureModeCameraTest, SelectAvailableCameraDuringGracePeriod) {
- const std::string device_id = "/dev/video0";
- const std::string display_name = "Integrated Webcam";
- const CameraId available_camera_id(display_name, 1);
- AddFakeCamera(device_id, display_name, /*model_id=*/"");
- // This adds the default camera as the selected one, and removes it triggering
- // a grace period.
- auto* camera_controller = AddAndRemoveCameraAndTriggerGracePeriod();
- base::OneShotTimer* timer =
- camera_controller->camera_reconnect_timer_for_test();
- EXPECT_TRUE(timer->IsRunning());
- // Selecting the available camera during the grace period should stop the
- // timer immediately.
- camera_controller->SetSelectedCamera(available_camera_id);
- EXPECT_FALSE(timer->IsRunning());
- EXPECT_EQ(available_camera_id, camera_controller->selected_camera());
- }
- // This tests simulates a flaky camera connection.
- TEST_F(CaptureModeCameraTest, ReconnectDuringGracePeriod) {
- StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
- auto* camera_controller = AddAndRemoveCameraAndTriggerGracePeriod();
- base::OneShotTimer* timer =
- camera_controller->camera_reconnect_timer_for_test();
- EXPECT_TRUE(timer->IsRunning());
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- // Re-add the camera during the grace period, the timer should stop, and the
- // preview should reshow.
- AddDefaultCamera();
- EXPECT_FALSE(timer->IsRunning());
- EXPECT_TRUE(camera_controller->camera_preview_widget());
- }
- // Tests a flaky camera that disconnects before recording begins and reconnects
- // during recording within the grace period.
- TEST_F(CaptureModeCameraTest, ReconnectDuringGracePeriodAfterRecordingStarts) {
- StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
- auto* camera_controller = AddAndRemoveCameraAndTriggerGracePeriod();
- base::OneShotTimer* timer =
- camera_controller->camera_reconnect_timer_for_test();
- EXPECT_TRUE(timer->IsRunning());
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- // Start recording, and expect that `should_show_preview_` will change to
- // false.
- EXPECT_TRUE(camera_controller->should_show_preview());
- StartVideoRecordingImmediately();
- EXPECT_FALSE(camera_controller->should_show_preview());
- // Re-add the camera during the grace period, the timer should stop, but the
- // preview should not be recreated.
- AddDefaultCamera();
- EXPECT_FALSE(timer->IsRunning());
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- }
- TEST_F(CaptureModeCameraTest, SelectedCameraChangedObserver) {
- AddDefaultCamera();
- auto* camera_controller = GetCameraController();
- const CameraId camera_id(kDefaultCameraModelId, 1);
- CameraDevicesChangeWaiter observer;
- camera_controller->SetSelectedCamera(camera_id);
- EXPECT_EQ(1, observer.selected_camera_change_event_count());
- // Selecting the same camera ID again should not trigger an observer call.
- camera_controller->SetSelectedCamera(camera_id);
- EXPECT_EQ(1, observer.selected_camera_change_event_count());
- // Clearing the ID should.
- camera_controller->SetSelectedCamera(CameraId());
- EXPECT_EQ(2, observer.selected_camera_change_event_count());
- }
- TEST_F(CaptureModeCameraTest, ShouldShowPreviewTest) {
- auto* controller = CaptureModeController::Get();
- auto* camera_controller = GetCameraController();
- controller->SetSource(CaptureModeSource::kFullscreen);
- controller->SetType(CaptureModeType::kVideo);
- controller->Start(CaptureModeEntryType::kQuickSettings);
- // should_show_preview() should return true when CaptureModeSession is started
- // in video recording mode.
- EXPECT_TRUE(camera_controller->should_show_preview());
- // Switch to image capture mode, should_show_preview() should return false.
- controller->SetType(CaptureModeType::kImage);
- EXPECT_FALSE(camera_controller->should_show_preview());
- // Stop an existing capture session, should_show_preview() should return
- // false.
- controller->Stop();
- EXPECT_FALSE(camera_controller->should_show_preview());
- EXPECT_FALSE(controller->IsActive());
- // Start another capture session and start video recording,
- // should_show_preview() should return false when video recording ends.
- controller->SetType(CaptureModeType::kVideo);
- controller->Start(CaptureModeEntryType::kQuickSettings);
- EXPECT_TRUE(camera_controller->should_show_preview());
- controller->StartVideoRecordingImmediatelyForTesting();
- EXPECT_TRUE(camera_controller->should_show_preview());
- controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
- EXPECT_FALSE(camera_controller->should_show_preview());
- }
- TEST_F(CaptureModeCameraTest, ManagedByPolicyCameraOptions) {
- GetTestDelegate()->set_is_camera_disabled_by_policy(true);
- StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
- OpenSettingsView();
- // At this moment, there are no camera devices connected. The camera menu
- // group should be hidden.
- CaptureModeSettingsTestApi test_api;
- CaptureModeMenuGroup* camera_menu_group = test_api.GetCameraMenuGroup();
- ASSERT_TRUE(camera_menu_group);
- EXPECT_FALSE(camera_menu_group->GetVisible());
- // Camera addition/removal are still observed even when managed by policy, but
- // once a camera is added, the group becomes visible, but shows only a dimmed
- // "Off" option.
- AddDefaultCamera();
- EXPECT_TRUE(camera_menu_group->GetVisible());
- EXPECT_TRUE(camera_menu_group->IsOptionChecked(kCameraOff));
- EXPECT_FALSE(camera_menu_group->IsOptionEnabled(kCameraOff));
- EXPECT_FALSE(test_api.GetCameraOption(kCameraDevicesBegin));
- // Selecting a camera will be ignored.
- auto* camera_controller = GetCameraController();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- EXPECT_FALSE(camera_controller->selected_camera().is_valid());
- EXPECT_TRUE(camera_menu_group->IsOptionChecked(kCameraOff));
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- // Removing the existing camera should hide the camera menu group and remove
- // all its options.
- RemoveDefaultCamera();
- EXPECT_FALSE(camera_menu_group->GetVisible());
- EXPECT_FALSE(test_api.GetCameraOption(kCameraOff));
- }
- // Tests that the options on camera menu are shown and checked correctly when
- // adding or removing cameras. Also tests that `selected_camera_` is updated
- // correspondently.
- TEST_F(CaptureModeCameraTest, CheckCameraOptions) {
- auto* camera_controller = GetCameraController();
- const std::string device_id_1 = "/dev/video0";
- const std::string display_name_1 = "Integrated Webcam";
- const std::string device_id_2 = "/dev/video1";
- const std::string display_name_2 = "Integrated Webcam 1";
- AddFakeCamera(device_id_1, display_name_1, display_name_1);
- AddFakeCamera(device_id_2, display_name_2, display_name_2);
- StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
- OpenSettingsView();
- // Check camera settings is shown. `Off` option is checked. Two camera options
- // are not checked.
- CaptureModeSettingsTestApi test_api;
- CaptureModeMenuGroup* camera_menu_group = test_api.GetCameraMenuGroup();
- EXPECT_TRUE(camera_menu_group && camera_menu_group->GetVisible());
- EXPECT_TRUE(camera_menu_group->IsOptionChecked(kCameraOff));
- EXPECT_FALSE(camera_menu_group->IsOptionChecked(kCameraDevicesBegin));
- EXPECT_FALSE(camera_menu_group->IsOptionChecked(kCameraDevicesBegin + 1));
- EXPECT_FALSE(camera_controller->selected_camera().is_valid());
- // Click the option for camera device 1, check its display name matches with
- // the camera device 1 display name and it's checked. Also check the selected
- // camera is valid now.
- ClickOnView(test_api.GetCameraOption(kCameraDevicesBegin),
- GetEventGenerator());
- EXPECT_FALSE(camera_menu_group->IsOptionChecked(kCameraOff));
- EXPECT_EQ(base::UTF16ToUTF8(camera_menu_group->GetOptionLabelForTesting(
- kCameraDevicesBegin)),
- display_name_1);
- EXPECT_TRUE(camera_menu_group->IsOptionChecked(kCameraDevicesBegin));
- EXPECT_TRUE(camera_controller->selected_camera().is_valid());
- // Now disconnect camera device 1.
- RemoveFakeCamera(device_id_1);
- // Check the camera device 1 is removed from the camera menu. There's only a
- // camera option for camera device 2. Selected camera is still valid. `Off`
- // option and option for camera device 2 are not checked.
- EXPECT_TRUE(test_api.GetCameraOption(kCameraDevicesBegin));
- EXPECT_FALSE(test_api.GetCameraOption(kCameraDevicesBegin + 1));
- EXPECT_EQ(base::UTF16ToUTF8(camera_menu_group->GetOptionLabelForTesting(
- kCameraDevicesBegin)),
- display_name_2);
- EXPECT_FALSE(camera_menu_group->IsOptionChecked(kCameraOff));
- EXPECT_FALSE(camera_menu_group->IsOptionChecked(kCameraDevicesBegin));
- EXPECT_TRUE(camera_controller->selected_camera().is_valid());
- // Now connect the camera device 1 again.
- AddFakeCamera(device_id_1, display_name_1, display_name_1);
- // Check the camera device 1 is added back to the camera menu and it's checked
- // automatically. Check the selected option's label matches with the camera
- // device 1's display name.
- // Note that `device_id_1` ("/dev/video0") comes before `device_id_2`
- // ("/dev/video1") in sort order, so it will be added first in the menu.
- EXPECT_TRUE(test_api.GetCameraOption(kCameraDevicesBegin));
- EXPECT_TRUE(test_api.GetCameraOption(kCameraDevicesBegin + 1));
- EXPECT_FALSE(camera_menu_group->IsOptionChecked(kCameraOff));
- EXPECT_TRUE(camera_menu_group->IsOptionChecked(kCameraDevicesBegin));
- EXPECT_FALSE(camera_menu_group->IsOptionChecked(kCameraDevicesBegin + 1));
- EXPECT_EQ(base::UTF16ToUTF8(camera_menu_group->GetOptionLabelForTesting(
- kCameraDevicesBegin)),
- display_name_1);
- EXPECT_EQ(base::UTF16ToUTF8(camera_menu_group->GetOptionLabelForTesting(
- kCameraDevicesBegin + 1)),
- display_name_2);
- EXPECT_TRUE(camera_controller->selected_camera().is_valid());
- }
- TEST_F(CaptureModeCameraTest, CameraPreviewWidgetStackingInFullscreen) {
- StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- const auto* camera_preview_widget =
- camera_controller->camera_preview_widget();
- EXPECT_TRUE(camera_preview_widget);
- auto* preview_window = camera_preview_widget->GetNativeWindow();
- const auto* menu_container = preview_window->GetRootWindow()->GetChildById(
- kShellWindowId_MenuContainer);
- auto* parent = preview_window->parent();
- // Parent of the preview should be the MenuContainer when capture mode
- // session is active with `kFullscreen` type. And the preview window should
- // be the bottom-most child of it.
- EXPECT_EQ(parent, menu_container);
- EXPECT_EQ(menu_container->children().front(), preview_window);
- StartRecordingFromSource(CaptureModeSource::kFullscreen);
- // Parent of the preview should be the MenuContainer when video recording
- // in progress with `kFullscreen` type. And the preview window should be the
- // top-most child of it.
- preview_window = camera_preview_widget->GetNativeWindow();
- parent = preview_window->parent();
- EXPECT_EQ(parent, menu_container);
- EXPECT_EQ(menu_container->children().back(), preview_window);
- }
- TEST_F(CaptureModeCameraTest, CameraPreviewWidgetStackingInRegion) {
- auto* controller =
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- const auto* camera_preview_widget =
- camera_controller->camera_preview_widget();
- EXPECT_TRUE(camera_preview_widget);
- auto* preview_window = camera_preview_widget->GetNativeWindow();
- // Parent of the preview should be the UnparentedContainer when the user
- // capture region is not set.
- EXPECT_TRUE(controller->user_capture_region().IsEmpty());
- EXPECT_EQ(preview_window->parent(),
- preview_window->GetRootWindow()->GetChildById(
- kShellWindowId_UnparentedContainer));
- EXPECT_FALSE(camera_preview_widget->IsVisible());
- controller->SetUserCaptureRegion(gfx::Rect(10, 20, 80, 60),
- /*by_user=*/true);
- StartRecordingFromSource(CaptureModeSource::kRegion);
- const auto* menu_container = preview_window->GetRootWindow()->GetChildById(
- kShellWindowId_MenuContainer);
- // Parent of the preview should be the MenuContainer when video recording
- // in progress with `kRegion` type. And the preview window should be the
- // top-most child of it.
- ASSERT_EQ(preview_window->parent(), menu_container);
- EXPECT_EQ(menu_container->children().back(), preview_window);
- }
- // Tests that camera preview widget is shown, hidden and parented correctly
- // while moving, dragging and updating the user selection region.
- TEST_F(CaptureModeCameraTest, CameraPreviewWhileUpdatingCaptureRegion) {
- UpdateDisplay("800x700");
- auto* controller =
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- auto* capture_session = controller->capture_mode_session();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- const auto* camera_preview_widget =
- camera_controller->camera_preview_widget();
- EXPECT_TRUE(camera_preview_widget);
- auto* preview_window = camera_preview_widget->GetNativeWindow();
- const int min_region_length =
- capture_mode::kMinCaptureSurfaceShortSideLengthForVisibleCamera;
- const gfx::Rect capture_region(10, 20, min_region_length, min_region_length);
- controller->SetUserCaptureRegion(capture_region, /*by_user=*/true);
- // After user capture region is set, parent of the preview should be the
- // MenuContainer.
- const auto* menu_container = preview_window->GetRootWindow()->GetChildById(
- kShellWindowId_MenuContainer);
- ASSERT_EQ(preview_window->parent(), menu_container);
- EXPECT_TRUE(camera_preview_widget->IsVisible());
- EXPECT_TRUE(preview_window->IsVisible());
- // Press the bottom right of selection region. Verify preview is hidden and
- // it's still parented to `menu_container`.
- auto* event_generator = GetEventGenerator();
- event_generator->set_current_screen_location(capture_region.bottom_right());
- event_generator->PressLeftButton();
- EXPECT_FALSE(camera_preview_widget->IsVisible());
- EXPECT_FALSE(preview_window->IsVisible());
- ASSERT_EQ(preview_window->parent(), menu_container);
- // Move mouse to update the selection region. Verify preview is still
- // hidden.
- const gfx::Vector2d delta(15, 20);
- event_generator->MoveMouseTo(capture_region.bottom_right() + delta);
- EXPECT_TRUE(capture_session->is_drag_in_progress());
- EXPECT_FALSE(camera_preview_widget->IsVisible());
- EXPECT_FALSE(preview_window->IsVisible());
- ASSERT_EQ(preview_window->parent(), menu_container);
- // Now release the drag to end selection region update. Verify preview is
- // shown and parent of the preview should be MenuContainer.
- event_generator->ReleaseLeftButton();
- EXPECT_FALSE(capture_session->is_drag_in_progress());
- EXPECT_TRUE(camera_preview_widget->IsVisible());
- EXPECT_TRUE(preview_window->IsVisible());
- EXPECT_EQ(preview_window->parent(), menu_container);
- // Press in the selection region to move it around. Since in the
- // use case, selection region is not updated, preview should not be hidden.
- const gfx::Point current_position(capture_region.origin() + delta);
- event_generator->set_current_screen_location(current_position);
- event_generator->PressLeftButton();
- EXPECT_TRUE(camera_preview_widget->IsVisible());
- EXPECT_EQ(preview_window->parent(), menu_container);
- // Move mouse to move selection region around. Verify preview is shown.
- event_generator->MoveMouseTo(current_position + delta);
- EXPECT_TRUE(camera_preview_widget->IsVisible());
- EXPECT_EQ(preview_window->parent(), menu_container);
- // Now release the move to end moving selection region. Verify preview is
- // shown.
- event_generator->ReleaseLeftButton();
- EXPECT_TRUE(camera_preview_widget->IsVisible());
- EXPECT_EQ(preview_window->parent(), menu_container);
- }
- TEST_F(CaptureModeCameraTest, CameraPreviewWidgetStackingInWindow) {
- auto* controller =
- StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- const auto* camera_preview_widget =
- camera_controller->camera_preview_widget();
- EXPECT_TRUE(camera_preview_widget);
- auto* preview_window = camera_preview_widget->GetNativeWindow();
- // The parent of the preview should be the UnparentedContainer when selected
- // window is not set.
- ASSERT_FALSE(controller->capture_mode_session()->GetSelectedWindow());
- EXPECT_EQ(preview_window->parent(),
- preview_window->GetRootWindow()->GetChildById(
- kShellWindowId_UnparentedContainer));
- EXPECT_FALSE(camera_preview_widget->IsVisible());
- StartRecordingFromSource(CaptureModeSource::kWindow);
- // Parent of the preview widget should be the window being recorded when video
- // recording in progress with `kWindow` type. And the preview window should be
- // the top-most child of it.
- const auto* parent = preview_window->parent();
- const auto* window_being_recorded =
- controller->video_recording_watcher_for_testing()
- ->window_being_recorded();
- ASSERT_EQ(parent, window_being_recorded);
- EXPECT_EQ(window_being_recorded->children().back(), preview_window);
- }
- // Tests the visibility of camera menu when there's no camera connected.
- TEST_F(CaptureModeCameraTest, CheckCameraMenuVisibility) {
- StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
- OpenSettingsView();
- // Check camera menu is hidden.
- CaptureModeSettingsTestApi test_api;
- CaptureModeMenuGroup* camera_menu_group = test_api.GetCameraMenuGroup();
- EXPECT_TRUE(camera_menu_group && !camera_menu_group->GetVisible());
- // Connect a camera.
- AddDefaultCamera();
- // Check the camera menu is shown. And there's an `Off` option and an option
- // for the connected camera.
- camera_menu_group = test_api.GetCameraMenuGroup();
- EXPECT_TRUE(camera_menu_group && camera_menu_group->GetVisible());
- EXPECT_TRUE(test_api.GetCameraOption(kCameraOff));
- EXPECT_TRUE(test_api.GetCameraOption(kCameraDevicesBegin));
- // Now disconnect the camera.
- RemoveDefaultCamera();
- // Check the menu group is hidden again and all options has been removed from
- // the menu.
- camera_menu_group = test_api.GetCameraMenuGroup();
- EXPECT_TRUE(camera_menu_group && !camera_menu_group->GetVisible());
- EXPECT_FALSE(test_api.GetCameraOption(kCameraOff));
- EXPECT_FALSE(test_api.GetCameraOption(kCameraDevicesBegin));
- }
- TEST_F(CaptureModeCameraTest, CameraPreviewWidgetBounds) {
- auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
- CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- ASSERT_EQ(CameraPreviewSnapPosition::kBottomRight,
- camera_controller->camera_preview_snap_position());
- const auto* preview_widget = camera_controller->camera_preview_widget();
- EXPECT_TRUE(preview_widget);
- // Verifies the camera preview's alignment with `kBottomRight` snap position
- // and `kFullscreen` capture source.
- const auto* capture_mode_session = controller->capture_mode_session();
- const gfx::Rect work_area =
- display::Screen::GetScreen()
- ->GetDisplayNearestWindow(capture_mode_session->current_root())
- .work_area();
- VerifyPreviewAlignment(work_area);
- // Switching to `kRegion` without capture region set, the preview widget
- // should not be shown.
- controller->SetSource(CaptureModeSource::kRegion);
- EXPECT_TRUE(controller->user_capture_region().IsEmpty());
- EXPECT_FALSE(preview_widget->IsVisible());
- // Verifies the camera preview's alignment with `kBottomRight` snap position
- // and `kRegion` capture source.
- const gfx::Rect capture_region(10, 20, 300, 200);
- controller->SetUserCaptureRegion(capture_region, /*by_user=*/true);
- VerifyPreviewAlignment(capture_region);
- // Verifies the camera preview's alignment after switching back to
- // `kFullscreen.`
- controller->SetSource(CaptureModeSource::kFullscreen);
- VerifyPreviewAlignment(work_area);
- // Verifies the camera preview's alignment with `kBottomLeft` snap position
- // and `kRegion` capture source.
- controller->SetSource(CaptureModeSource::kRegion);
- camera_controller->SetCameraPreviewSnapPosition(
- CameraPreviewSnapPosition::kBottomLeft);
- VerifyPreviewAlignment(capture_region);
- // Verifies the camera preview's alignment with `kTopLeft` snap position
- // and `kRegion` capture source.
- camera_controller->SetCameraPreviewSnapPosition(
- CameraPreviewSnapPosition::kTopLeft);
- VerifyPreviewAlignment(capture_region);
- // Verifies the camera preview's alignment with `kTopRight` snap position
- // and `kRegion` capture source.
- camera_controller->SetCameraPreviewSnapPosition(
- CameraPreviewSnapPosition::kTopRight);
- VerifyPreviewAlignment(capture_region);
- // Set capture region to empty, the preview should be hidden again.
- controller->SetUserCaptureRegion(gfx::Rect(), /*by_user=*/true);
- EXPECT_FALSE(preview_widget->IsVisible());
- // Verifies the camera preview's alignment with `kTopRight` snap position and
- // `kWindow` capture source.
- StartRecordingFromSource(CaptureModeSource::kWindow);
- const auto* window_being_recorded =
- controller->video_recording_watcher_for_testing()
- ->window_being_recorded();
- DCHECK(window_being_recorded);
- VerifyPreviewAlignment(window_being_recorded->GetBoundsInScreen());
- }
- TEST_F(CaptureModeCameraTest, MultiDisplayCameraPreviewWidgetBounds) {
- UpdateDisplay("800x700,801+0-800x700");
- const gfx::Point point_in_second_display = gfx::Point(1000, 500);
- auto* event_generator = GetEventGenerator();
- MoveMouseToAndUpdateCursorDisplay(point_in_second_display, event_generator);
- // Start the capture session in the second display.
- auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
- CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- const gfx::Rect second_display_bounds(801, 0, 800, 700);
- // The camera preview should reside inside the second display when we start
- // capture session in the second display.
- const auto* preview_widget = camera_controller->camera_preview_widget();
- EXPECT_TRUE(second_display_bounds.Contains(
- preview_widget->GetWindowBoundsInScreen()));
- // Move the capture session to the primary display should move the camera
- // preview to the primary display as well.
- MoveMouseToAndUpdateCursorDisplay(gfx::Point(10, 20), event_generator);
- EXPECT_TRUE(gfx::Rect(0, 0, 800, 700)
- .Contains(preview_widget->GetWindowBoundsInScreen()));
- // Move back to the second display, switch to `kRegion` and set the capture
- // region. The camera preview should be moved back to the second display and
- // inside the capture region.
- MoveMouseToAndUpdateCursorDisplay(point_in_second_display, event_generator);
- controller->SetSource(CaptureModeSource::kRegion);
- // The capture region set through `controller` is in root coordinate.
- const gfx::Rect capture_region(100, 0, 400, 550);
- controller->SetUserCaptureRegion(capture_region, /*by_user=*/true);
- const gfx::Rect capture_region_in_screen(901, 0, 400, 550);
- const gfx::Rect preview_bounds = preview_widget->GetWindowBoundsInScreen();
- EXPECT_TRUE(second_display_bounds.Contains(preview_bounds));
- EXPECT_TRUE(capture_region_in_screen.Contains(preview_bounds));
- // Start the window recording inside the second display, the camera preview
- // should be inside the window that is being recorded inside the second
- // display.
- window()->SetBoundsInScreen(
- gfx::Rect(900, 0, 600, 500),
- display::Screen::GetScreen()->GetDisplayNearestWindow(
- Shell::GetAllRootWindows()[1]));
- StartRecordingFromSource(CaptureModeSource::kWindow);
- const auto* window_being_recorded =
- controller->video_recording_watcher_for_testing()
- ->window_being_recorded();
- EXPECT_TRUE(window_being_recorded->GetBoundsInScreen().Contains(
- preview_widget->GetWindowBoundsInScreen()));
- }
- // Tests that switching from `kImage` to `kVideo` with capture source `kWindow`,
- // and capture window is already selected before the switch, the camera preview
- // widget should be positioned and parented correctly.
- TEST_F(CaptureModeCameraTest, CameraPreviewWidgetAfterTypeSwitched) {
- auto* controller =
- StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kImage);
- auto* camera_controller = GetCameraController();
- GetEventGenerator()->MoveMouseToCenterOf(window());
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- controller->SetType(CaptureModeType::kVideo);
- const auto* camera_preview_widget =
- camera_controller->camera_preview_widget();
- EXPECT_TRUE(camera_preview_widget);
- auto* camera_preview_window = camera_preview_widget->GetNativeWindow();
- const auto* selected_window =
- controller->capture_mode_session()->GetSelectedWindow();
- ASSERT_EQ(camera_preview_window->parent(), selected_window);
- // Verify that camera preview is at the bottom right corner of the window.
- VerifyPreviewAlignment(selected_window->GetBoundsInScreen());
- // `camera_preview_window` should not have a transient parent.
- EXPECT_FALSE(wm::GetTransientParent(camera_preview_window));
- }
- // Tests that audio and camera menu groups should be hidden from the settings
- // menu when there's a video recording in progress.
- TEST_F(CaptureModeCameraTest,
- AudioAndCameraMenuGroupsAreHiddenWhenVideoRecordingInProgress) {
- auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
- CaptureModeType::kVideo);
- auto* camera_controller = controller->camera_controller();
- StartVideoRecordingImmediately();
- EXPECT_TRUE(controller->is_recording_in_progress());
- // Verify there's no camera preview created, since we don't select any camera.
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- // Check capture session is shut down after the video recording starts.
- EXPECT_FALSE(controller->IsActive());
- // Start a new session, check the type should be switched automatically to
- // kImage.
- controller->Start(CaptureModeEntryType::kQuickSettings);
- EXPECT_EQ(CaptureModeType::kImage, controller->type());
- // Verify there's no camera preview created after a new session started.
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- OpenSettingsView();
- // Check the audio and camera menu groups are hidden from the settings.
- CaptureModeSettingsTestApi test_api_new;
- EXPECT_FALSE(test_api_new.GetCameraMenuGroup());
- EXPECT_FALSE(test_api_new.GetAudioInputMenuGroup());
- EXPECT_TRUE(test_api_new.GetSaveToMenuGroup());
- }
- // Verify that starting a new capture session and updating capture source won't
- // affect the current camera preview when there's a video recording is progress.
- TEST_F(CaptureModeCameraTest,
- CameraPreviewNotChangeWhenVideoRecordingInProgress) {
- auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
- CaptureModeType::kVideo);
- auto* camera_controller = controller->camera_controller();
- AddDefaultCamera();
- OpenSettingsView();
- // Select the default camera for video recording.
- CaptureModeSettingsTestApi test_api;
- ClickOnView(test_api.GetCameraOption(kCameraDevicesBegin),
- GetEventGenerator());
- StartVideoRecordingImmediately();
- // Check that the camera preview is created.
- const auto* camera_preview_widget =
- camera_controller->camera_preview_widget();
- EXPECT_TRUE(camera_preview_widget);
- auto* preview_window = camera_preview_widget->GetNativeWindow();
- auto* parent = preview_window->parent();
- // Start a new capture session, and set capture source to `kFullscreen`,
- // verify the camera preview and its parent are not changed.
- controller->Start(CaptureModeEntryType::kQuickSettings);
- controller->SetSource(CaptureModeSource::kFullscreen);
- EXPECT_EQ(preview_window,
- camera_controller->camera_preview_widget()->GetNativeWindow());
- EXPECT_EQ(
- parent,
- camera_controller->camera_preview_widget()->GetNativeWindow()->parent());
- // Update capture source to `kRegion` and set the user capture region, verify
- // the camera preview and its parent are not changed.
- controller->SetSource(CaptureModeSource::kRegion);
- controller->SetUserCaptureRegion({100, 100, 200, 300}, /*by_user=*/true);
- EXPECT_EQ(preview_window,
- camera_controller->camera_preview_widget()->GetNativeWindow());
- EXPECT_EQ(
- parent,
- camera_controller->camera_preview_widget()->GetNativeWindow()->parent());
- // Update capture source to `kWindow` and move mouse on top the `window`,
- // verify that the camera preview and its parent are not changed.
- controller->SetSource(CaptureModeSource::kWindow);
- auto* event_generator = GetEventGenerator();
- event_generator->MoveMouseToCenterOf(window());
- EXPECT_EQ(preview_window,
- camera_controller->camera_preview_widget()->GetNativeWindow());
- EXPECT_EQ(
- parent,
- camera_controller->camera_preview_widget()->GetNativeWindow()->parent());
- }
- // Tests that changing the folder while there's a video recording in progress
- // doesn't change the folder where the video being recorded will be saved to.
- // It will only affect the image to be captured.
- TEST_F(CaptureModeCameraTest, ChangeFolderWhileVideoRecordingInProgress) {
- auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
- CaptureModeType::kVideo);
- StartVideoRecordingImmediately();
- // While the video recording is in progress, start a new capture session and
- // update the save-to folder to the custom folder.
- controller->Start(CaptureModeEntryType::kQuickSettings);
- controller->SetCustomCaptureFolder(
- CreateCustomFolderInUserDownloadsPath("test"));
- // Perform the image capture. Verify that the image is saved to the custom
- // folder.
- controller->PerformCapture();
- const base::FilePath& saved_image_file = WaitForCaptureFileToBeSaved();
- EXPECT_EQ(controller->GetCustomCaptureFolder(), saved_image_file.DirName());
- // End the video recoring and verify the video is still saved to the default
- // downloads folder.
- controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
- const base::FilePath& saved_video_file = WaitForCaptureFileToBeSaved();
- EXPECT_EQ(controller->delegate_for_testing()->GetUserDefaultDownloadsFolder(),
- saved_video_file.DirName());
- }
- // Tests multiple scenarios to trigger selected window updates at located
- // position. Camera preview's native window should be added to the ignore
- // windows and no crash should happen in these cases.
- TEST_F(CaptureModeCameraTest,
- UpdateSelectedWindowAtPositionWithCameraPreviewIgnored) {
- auto* controller =
- StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
- AddDefaultCamera();
- auto* camera_controller = GetCameraController();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* event_generator = GetEventGenerator();
- event_generator->MoveMouseToCenterOf(window());
- EXPECT_TRUE(camera_controller->camera_preview_widget());
- // No camera preview when it is in `kImage`.
- controller->SetType(CaptureModeType::kImage);
- event_generator->MoveMouseToCenterOf(window());
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- // The native window of camera preview widget should be ignored from the
- // candidates of the selected window. So moving the mouse to be on top of the
- // camera preview should not cause any crash or selected window changes.
- controller->SetType(CaptureModeType::kVideo);
- const auto* camera_preview_widget =
- camera_controller->camera_preview_widget();
- const auto* capture_mode_session = controller->capture_mode_session();
- event_generator->MoveMouseToCenterOf(
- camera_preview_widget->GetNativeWindow());
- EXPECT_EQ(window(), capture_mode_session->GetSelectedWindow());
- EXPECT_TRUE(window()->IsVisible());
- EXPECT_TRUE(camera_preview_widget->IsVisible());
- // Hide `window_` with camera preview on should not cause any crash and
- // selected window should be updated to nullptr.
- window()->Hide();
- EXPECT_FALSE(window()->IsVisible());
- EXPECT_FALSE(camera_preview_widget->IsVisible());
- EXPECT_FALSE(capture_mode_session->GetSelectedWindow());
- // Reshow `window_` without hovering over it should not set the selected
- // window. Camera preview should still be hidden as its parent hasn't been set
- // to `window_` yet.
- const auto* preview_native_window = camera_preview_widget->GetNativeWindow();
- window()->Show();
- EXPECT_TRUE(window()->IsVisible());
- EXPECT_FALSE(camera_preview_widget->IsVisible());
- EXPECT_FALSE(capture_mode_session->GetSelectedWindow());
- EXPECT_EQ(preview_native_window->parent(),
- preview_native_window->GetRootWindow()->GetChildById(
- kShellWindowId_UnparentedContainer));
- // Hovering over `window_` should set it to the selected window, camera
- // preview widget should be reparented to it as well. And the camera preview
- // widget should be visible now.
- event_generator->MoveMouseToCenterOf(window());
- EXPECT_EQ(preview_native_window->parent(),
- capture_mode_session->GetSelectedWindow());
- EXPECT_TRUE(camera_preview_widget->IsVisible());
- EXPECT_EQ(window(), capture_mode_session->GetSelectedWindow());
- }
- // Tests that capture label's opacity changes accordingly when it's overlapped
- // or it's not overlapped with camera preview. Also tests that when located
- // events is or is not on capture label, its opacity is updated accordingly.
- TEST_F(CaptureModeCameraTest,
- CaptureLabelOpacityChangeWhenOverlappingWithCameraPreview) {
- auto* controller =
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- auto* capture_session = controller->capture_mode_session();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- const auto* camera_preview_widget =
- camera_controller->camera_preview_widget();
- const auto* capture_label_widget = capture_session->capture_label_widget();
- const ui::Layer* capture_label_layer = capture_label_widget->GetLayer();
- // Set capture region big enough to make capture label not overlapping with
- // camera preview. Verify capture label is fully opaque.
- const gfx::Rect capture_region(100, 100, 700, 700);
- SelectCaptureRegion(capture_region);
- EXPECT_FALSE(capture_label_widget->GetWindowBoundsInScreen().Intersects(
- camera_preview_widget->GetWindowBoundsInScreen()));
- EXPECT_EQ(capture_label_layer->GetTargetOpacity(), 1.f);
- // Update capture region smaller to make capture label overlap with camera
- // preview. Verify capture label is `kOverlapOpacity`.
- // Make sure to resize the region to a value that won't cause the camera to be
- // hidden according to the camera size specs.
- const int delta_x =
- capture_mode::kMinCaptureSurfaceShortSideLengthForVisibleCamera -
- capture_region.width();
- const int delta_y =
- capture_mode::kMinCaptureSurfaceShortSideLengthForVisibleCamera -
- capture_region.height();
- const gfx::Vector2d delta(delta_x, delta_y);
- auto* event_generator = GetEventGenerator();
- event_generator->set_current_screen_location(capture_region.bottom_right());
- event_generator->PressLeftButton();
- event_generator->MoveMouseTo(capture_region.bottom_right() + delta);
- event_generator->ReleaseLeftButton();
- EXPECT_TRUE(capture_label_widget->GetWindowBoundsInScreen().Intersects(
- camera_preview_widget->GetWindowBoundsInScreen()));
- EXPECT_EQ(capture_label_layer->GetTargetOpacity(),
- capture_mode::kCaptureUiOverlapOpacity);
- // Move mouse on top of capture label, verify it's updated to fully opaque
- // even it's still overlapped with camera preview.
- const gfx::Rect capture_lable_bounds =
- capture_label_widget->GetWindowBoundsInScreen();
- event_generator->MoveMouseTo(capture_lable_bounds.CenterPoint());
- EXPECT_TRUE(capture_lable_bounds.Intersects(
- camera_preview_widget->GetWindowBoundsInScreen()));
- EXPECT_EQ(capture_label_layer->GetTargetOpacity(), 1.0f);
- // Move mouse to the outside of capture label, verify it's updated to
- // `kOverlapOpacity`.
- const gfx::Vector2d delta1(50, 50);
- event_generator->MoveMouseTo(capture_lable_bounds.bottom_right() + delta1);
- EXPECT_EQ(capture_label_layer->GetTargetOpacity(),
- capture_mode::kCaptureUiOverlapOpacity);
- // Click on the outside of the capture region to reset it, verify capture
- // label is updated to fully opaque.
- const gfx::Rect current_capture_region = controller->user_capture_region();
- event_generator->MoveMouseTo(current_capture_region.bottom_right() + delta1);
- event_generator->ClickLeftButton();
- EXPECT_EQ(capture_label_layer->GetTargetOpacity(), 1.0f);
- }
- TEST_F(CaptureModeCameraTest,
- CaptureBarOpacityChangeWhenOverlappingWithCameraPreview) {
- // Update display size and update window with customized size to make sure
- // camera preview overlap with capture bar with capture source `kWindow`.
- UpdateDisplay("1366x768");
- window()->SetBounds({0, 195, 903, 492});
- auto* controller =
- StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
- auto* capture_session = controller->capture_mode_session();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- const auto* camera_preview_widget =
- camera_controller->camera_preview_widget();
- const auto* capture_bar_widget = capture_session->capture_mode_bar_widget();
- const ui::Layer* capture_bar_layer = capture_bar_widget->GetLayer();
- // Move mouse on top of `window` to set the selected window. Verify capture
- // bar is `kOverlapOpacity`.
- auto* event_generator = GetEventGenerator();
- event_generator->MoveMouseTo(window()->GetBoundsInScreen().CenterPoint());
- EXPECT_EQ(capture_session->GetSelectedWindow(), window());
- EXPECT_TRUE(capture_bar_widget->GetWindowBoundsInScreen().Intersects(
- camera_preview_widget->GetWindowBoundsInScreen()));
- EXPECT_EQ(capture_bar_layer->GetTargetOpacity(),
- capture_mode::kCaptureUiOverlapOpacity);
- // Move mouse on top of capture bar. Verify capture bar is updated to fully
- // opaque.
- event_generator->MoveMouseTo(
- capture_bar_widget->GetWindowBoundsInScreen().CenterPoint());
- EXPECT_TRUE(capture_bar_widget->GetWindowBoundsInScreen().Intersects(
- camera_preview_widget->GetWindowBoundsInScreen()));
- EXPECT_EQ(capture_bar_layer->GetTargetOpacity(), 1.0f);
- // Mouse mouse to the outside of capture bar, verify it's updated to
- // `kOverlapOpacity`.
- const gfx::Point capture_bar_origin =
- capture_bar_widget->GetWindowBoundsInScreen().origin();
- event_generator->MoveMouseTo(capture_bar_origin.x() - 10,
- capture_bar_origin.y() - 10);
- EXPECT_EQ(capture_bar_layer->GetTargetOpacity(),
- capture_mode::kCaptureUiOverlapOpacity);
- }
- TEST_F(CaptureModeCameraTest, CaptureBarOpacityChangeOnDisplayRotation) {
- // Update display size and update window with customized size to make sure
- // camera preview overlap with capture bar with capture source `kWindow`.
- UpdateDisplay("1366x768");
- window()->SetBounds({0, 195, 903, 492});
- auto* controller =
- StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
- auto* capture_session = controller->capture_mode_session();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- const auto* camera_preview_widget =
- camera_controller->camera_preview_widget();
- const auto* capture_bar_widget = capture_session->capture_mode_bar_widget();
- const ui::Layer* capture_bar_layer = capture_bar_widget->GetLayer();
- // Move mouse on top of `window` to set the selected window. Verify capture
- // bar is `kOverlapOpacity`.
- auto* event_generator = GetEventGenerator();
- event_generator->MoveMouseTo(window()->GetBoundsInScreen().CenterPoint());
- EXPECT_EQ(capture_session->GetSelectedWindow(), window());
- EXPECT_TRUE(capture_bar_widget->GetWindowBoundsInScreen().Intersects(
- camera_preview_widget->GetWindowBoundsInScreen()));
- EXPECT_EQ(capture_bar_layer->GetTargetOpacity(),
- capture_mode::kCaptureUiOverlapOpacity);
- // Rotate the primary display by 90 degrees. Verify that capture bar no longer
- // overlaps with camera preview and it's updated to fully opaque.
- Shell::Get()->display_manager()->SetDisplayRotation(
- WindowTreeHostManager::GetPrimaryDisplayId(), display::Display::ROTATE_90,
- display::Display::RotationSource::USER);
- EXPECT_FALSE(capture_bar_widget->GetWindowBoundsInScreen().Intersects(
- camera_preview_widget->GetWindowBoundsInScreen()));
- EXPECT_EQ(capture_bar_layer->GetTargetOpacity(), 1.0f);
- // Rotate the primary display by 180 degrees. Verify that capture bar is
- // overlapped with camera preview and it's updated to `kOverlapOpacity`.
- Shell::Get()->display_manager()->SetDisplayRotation(
- WindowTreeHostManager::GetPrimaryDisplayId(),
- display::Display::ROTATE_180, display::Display::RotationSource::USER);
- EXPECT_TRUE(capture_bar_widget->GetWindowBoundsInScreen().Intersects(
- camera_preview_widget->GetWindowBoundsInScreen()));
- EXPECT_EQ(capture_bar_layer->GetTargetOpacity(),
- capture_mode::kCaptureUiOverlapOpacity);
- }
- TEST_F(CaptureModeCameraTest, CaptureLabelOpacityChangeOnCaptureSourceChange) {
- UpdateDisplay("800x600");
- auto* controller =
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- auto* capture_session = controller->capture_mode_session();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* camera_preview_widget = camera_controller->camera_preview_widget();
- auto* capture_label_widget = capture_session->capture_label_widget();
- ui::Layer* capture_label_layer = capture_label_widget->GetLayer();
- // Select capture region to make sure capture label is overlapped with
- // camera preview. Verify capture label is `kOverlapOpacity`.
- const int min_region_length =
- capture_mode::kMinCaptureSurfaceShortSideLengthForVisibleCamera;
- SelectCaptureRegion({100, 100, min_region_length, min_region_length});
- EXPECT_TRUE(capture_label_widget->GetWindowBoundsInScreen().Intersects(
- camera_preview_widget->GetWindowBoundsInScreen()));
- EXPECT_EQ(capture_label_layer->GetTargetOpacity(),
- capture_mode::kCaptureUiOverlapOpacity);
- // Change the capture source from `kRegion` to `kFullscreen`, verify capture
- // label is updated to fully opaque.
- controller->SetSource(CaptureModeSource::kFullscreen);
- EXPECT_EQ(capture_label_layer->GetTargetOpacity(), 1.0f);
- }
- TEST_F(CaptureModeCameraTest,
- CaptureLabelOpacityChangeWhileVideoRecordingInProgress) {
- auto* controller =
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* camera_preview_widget = camera_controller->camera_preview_widget();
- const int min_region_length =
- capture_mode::kMinCaptureSurfaceShortSideLengthForVisibleCamera;
- controller->SetUserCaptureRegion(
- {100, 100, min_region_length, min_region_length}, /*by_user=*/true);
- StartVideoRecordingImmediately();
- EXPECT_FALSE(controller->IsActive());
- // Start a new capture session, verify even capture label is overlapped with
- // camera preview, it's still fully opaque since camera preview does not
- // belong to the new capture session.
- controller->Start(CaptureModeEntryType::kQuickSettings);
- EXPECT_EQ(CaptureModeSource::kRegion, controller->source());
- auto* capture_session = controller->capture_mode_session();
- const auto* capture_label_widget = capture_session->capture_label_widget();
- EXPECT_TRUE(capture_label_widget->GetWindowBoundsInScreen().Intersects(
- camera_preview_widget->GetWindowBoundsInScreen()));
- EXPECT_EQ(capture_label_widget->GetLayer()->GetTargetOpacity(), 1.0f);
- }
- TEST_F(CaptureModeCameraTest, FocusableCameraPreviewInFullscreen) {
- UpdateDisplay("800x700");
- auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
- CaptureModeType::kVideo);
- AddDefaultCamera();
- auto* camera_controller = GetCameraController();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* event_generator = GetEventGenerator();
- using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
- CaptureModeSessionTestApi test_api(controller->capture_mode_session());
- // Tests that the camera preview is focusable in fullscreen capture.
- auto* camera_preview_view = camera_controller->camera_preview_view();
- auto* resize_button = GetPreviewResizeButton();
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/6);
- EXPECT_EQ(FocusGroup::kCameraPreview, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(camera_preview_view->has_focus());
- // Press tab again should advance the focus on the resize button. And the
- // resize button should be invisible before and visible after being focused.
- EXPECT_FALSE(resize_button->GetVisible());
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(1u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(resize_button->has_focus());
- EXPECT_TRUE(resize_button->GetVisible());
- // Press space when the resize button is focused should collapse the camera
- // preview.
- EXPECT_TRUE(resize_button->has_focus());
- EXPECT_FALSE(camera_controller->is_camera_preview_collapsed());
- SendKey(ui::VKEY_SPACE, event_generator);
- EXPECT_TRUE(camera_controller->is_camera_preview_collapsed());
- // Press space again should expand the camera preview.
- SendKey(ui::VKEY_SPACE, event_generator);
- EXPECT_FALSE(camera_controller->is_camera_preview_collapsed());
- // When the resize button inside the camera preview is focused, press tab
- // should advance to focus on the settings button.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- // The resize button should fade out and become invisible in
- // `kResizeButtonShowDuration` after removing focus from it.
- base::OneShotTimer* hide_timer =
- camera_preview_view->resize_button_hide_timer_for_test();
- EXPECT_FALSE(resize_button->has_focus());
- EXPECT_TRUE(hide_timer->IsRunning());
- EXPECT_EQ(hide_timer->GetCurrentDelay(),
- capture_mode::kResizeButtonShowDuration);
- {
- ViewVisibilityChangeWaiter waiter(resize_button);
- EXPECT_TRUE(resize_button->GetVisible());
- hide_timer->FireNow();
- waiter.Wait();
- EXPECT_FALSE(resize_button->GetVisible());
- }
- // Shift tab should advance the focus from the settings button back to the
- // resize button inside the camera preview.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_EQ(FocusGroup::kCameraPreview, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(1u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(resize_button->has_focus());
- // The resize button should keep visible when it is focused, even trigger
- // `resize_button_hide_timer_` to refresh its visibility.
- hide_timer = camera_preview_view->resize_button_hide_timer_for_test();
- EXPECT_TRUE(hide_timer->IsRunning());
- EXPECT_TRUE(resize_button->GetVisible());
- hide_timer->FireNow();
- EXPECT_TRUE(resize_button->GetVisible());
- // Continue shift tab should move the focus from the resize button to the
- // camera preview.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(camera_preview_view->has_focus());
- // The resize button should fade out and become invisible again in
- // `kResizeButtonShowDuration` after removing focus from it.
- hide_timer = camera_preview_view->resize_button_hide_timer_for_test();
- EXPECT_FALSE(resize_button->has_focus());
- EXPECT_TRUE(hide_timer->IsRunning());
- EXPECT_EQ(hide_timer->GetCurrentDelay(),
- capture_mode::kResizeButtonShowDuration);
- {
- ViewVisibilityChangeWaiter waiter(resize_button);
- EXPECT_TRUE(resize_button->GetVisible());
- hide_timer->FireNow();
- waiter.Wait();
- EXPECT_FALSE(resize_button->GetVisible());
- }
- // Tests moving the camera preview through the keyboard when it is focused.
- EXPECT_TRUE(camera_controller->camera_preview_view()->has_focus());
- EXPECT_EQ(CameraPreviewSnapPosition::kBottomRight,
- camera_controller->camera_preview_snap_position());
- // Press control+right should not move the camera preview, as it is currently
- // at the right.
- SendKey(ui::VKEY_RIGHT, event_generator, ui::EF_CONTROL_DOWN);
- EXPECT_EQ(CameraPreviewSnapPosition::kBottomRight,
- camera_controller->camera_preview_snap_position());
- // Press control+down should not move the camera preview either, as it is
- // currently at the bottom.
- SendKey(ui::VKEY_DOWN, event_generator, ui::EF_CONTROL_DOWN);
- EXPECT_EQ(CameraPreviewSnapPosition::kBottomRight,
- camera_controller->camera_preview_snap_position());
- // Press control+left should move the camera preview from bottom right to
- // bottom left.
- SendKey(ui::VKEY_LEFT, event_generator, ui::EF_CONTROL_DOWN);
- EXPECT_EQ(CameraPreviewSnapPosition::kBottomLeft,
- camera_controller->camera_preview_snap_position());
- // Press control+right now should work to move the camera preview from bottom
- // left to bottom right.
- SendKey(ui::VKEY_RIGHT, event_generator, ui::EF_CONTROL_DOWN);
- EXPECT_EQ(CameraPreviewSnapPosition::kBottomRight,
- camera_controller->camera_preview_snap_position());
- // Press control+up should move the camera preview from bottom right to top
- // right.
- SendKey(ui::VKEY_UP, event_generator, ui::EF_CONTROL_DOWN);
- EXPECT_EQ(CameraPreviewSnapPosition::kTopRight,
- camera_controller->camera_preview_snap_position());
- // Shift tab again should advance the focus from the camera preview back to
- // the window capture source button.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_EQ(FocusGroup::kTypeSource, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(4u, test_api.GetCurrentFocusIndex());
- }
- TEST_F(CaptureModeCameraTest, FocusableCameraPreviewInRegion) {
- UpdateDisplay("1366x768");
- auto* controller = CaptureModeController::Get();
- controller->SetUserCaptureRegion(gfx::Rect(10, 10, 800, 700),
- /*by_user=*/true);
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- AddDefaultCamera();
- auto* camera_controller = GetCameraController();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* event_generator = GetEventGenerator();
- using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
- CaptureModeSessionTestApi test_api(controller->capture_mode_session());
- // Tests that the camera preview is focusable in region capture.
- auto* camera_preview_view = camera_controller->camera_preview_view();
- auto* resize_button = GetPreviewResizeButton();
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/15);
- EXPECT_EQ(FocusGroup::kCameraPreview, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(camera_preview_view->has_focus());
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(1u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(resize_button->has_focus());
- // When the resize button inside camera preview is focused, press tab should
- // advance to focus on the capture button.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(FocusGroup::kCaptureButton, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- // Press tab again to advance focus on the settings button.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- // Shift tab should advance the focus from the settings button back to the
- // capture button.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_EQ(FocusGroup::kCaptureButton, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- // Shift tab again should advance the focus from the capture button back to
- // the resize button inside the camera preview.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_EQ(FocusGroup::kCameraPreview, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(1u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(resize_button->has_focus());
- // Continue shift tab should move the focus from the resize button to the
- // camera preview.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(camera_preview_view->has_focus());
- // Shift tab to advance the focus back to the window capture source button.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN, /*count=*/10);
- EXPECT_EQ(FocusGroup::kTypeSource, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(4u, test_api.GetCurrentFocusIndex());
- // Update the capture region to test when the resize button is not focusable.
- controller->SetUserCaptureRegion(gfx::Rect(10, 10, 400, 550),
- /*by_user=*/true);
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/10);
- EXPECT_EQ(FocusGroup::kCameraPreview, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(camera_preview_view->has_focus());
- // Press tab should advance the focus on the capture button instead of the
- // resize button. As the resize button is forced to be hidden, which is not
- // focusable in this case.
- EXPECT_FALSE(camera_preview_view->is_collapsible());
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(FocusGroup::kCaptureButton, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- }
- TEST_F(CaptureModeCameraTest, FocusableCameraPreviewInWindow) {
- UpdateDisplay("1366x768");
- // Create one more window besides `window_`.
- std::unique_ptr<aura::Window> window2(
- CreateTestWindow(gfx::Rect(150, 50, 800, 700)));
- window()->SetBounds(gfx::Rect(30, 40, 800, 700));
- auto* controller =
- StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
- AddDefaultCamera();
- auto* camera_controller = GetCameraController();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* event_generator = GetEventGenerator();
- using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
- auto* capture_mode_session = controller->capture_mode_session();
- CaptureModeSessionTestApi test_api(capture_mode_session);
- const auto* preview_window =
- camera_controller->camera_preview_widget()->GetNativeWindow();
- // Tab to focus on `window2`, which is the most recently used window. It
- // should be set to the current selected window, and the camera preview should
- // be shown inside it.
- auto* camera_preview_view = camera_controller->camera_preview_view();
- auto* resize_button = GetPreviewResizeButton();
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/6);
- EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(test_api.GetHighlightableWindow(window2.get())->has_focus());
- EXPECT_EQ(window2.get(), capture_mode_session->GetSelectedWindow());
- EXPECT_EQ(window2.get(), preview_window->parent());
- // Press tab should advance to focus on the camera preview inside. But the
- // FocusGroup should not change, as the camera preview is treated as part of
- // the selected window in this case.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(1u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(camera_preview_view->has_focus());
- // Press tab should focus on the resize button inside the camera preview.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(2u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(resize_button->has_focus());
- EXPECT_FALSE(camera_controller->camera_preview_view()->has_focus());
- // Press tab again should advance focus and set another window `window_` to be
- // the current selected window. The camera preview should be shown inside it
- // now.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(3u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(test_api.GetHighlightableWindow(window())->has_focus());
- EXPECT_EQ(window(), capture_mode_session->GetSelectedWindow());
- EXPECT_EQ(window(), preview_window->parent());
- // Press tab should advance to focus on the camera preview that inside
- // `window_` now.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(4u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(camera_preview_view->has_focus());
- // Press tab to advance the focus on the resize button inside the camera
- // preview.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(5u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(resize_button->has_focus());
- EXPECT_FALSE(camera_preview_view->has_focus());
- // Press tab again should advance to focus on the settings button.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- EXPECT_FALSE(resize_button->has_focus());
- EXPECT_FALSE(camera_preview_view->has_focus());
- // Shift tab when the settings button is focused should advance back to focus
- // on the resize button inside the camera preview. And the camera preview
- // should now be shown inside `window_`, which is the current selected window.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(5u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(resize_button->has_focus());
- EXPECT_FALSE(camera_preview_view->has_focus());
- EXPECT_EQ(window(), capture_mode_session->GetSelectedWindow());
- EXPECT_EQ(window(), preview_window->parent());
- // Shift tab again should move the focus from the resize button to the camera
- // preview.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(4u, test_api.GetCurrentFocusIndex());
- EXPECT_FALSE(resize_button->has_focus());
- EXPECT_TRUE(camera_preview_view->has_focus());
- // Shift tab again should focus on the `window_`
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(3u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(test_api.GetHighlightableWindow(window())->has_focus());
- EXPECT_FALSE(resize_button->has_focus());
- EXPECT_FALSE(camera_preview_view->has_focus());
- EXPECT_EQ(window(), capture_mode_session->GetSelectedWindow());
- // Continue shift tab should advance back to focus on the resize button inside
- // the camera preview. And the camera preview should now inside `window2`,
- // which is the current selected window.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(2u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(resize_button->has_focus());
- EXPECT_FALSE(camera_preview_view->has_focus());
- EXPECT_EQ(window2.get(), capture_mode_session->GetSelectedWindow());
- EXPECT_EQ(window2.get(), preview_window->parent());
- // Continue shift tab should move the focus from the resize button to the
- // camera preview.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_EQ(1u, test_api.GetCurrentFocusIndex());
- EXPECT_FALSE(resize_button->has_focus());
- EXPECT_TRUE(camera_preview_view->has_focus());
- // Continue shift tab should focus on the `window2`.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(test_api.GetHighlightableWindow(window2.get())->has_focus());
- EXPECT_FALSE(resize_button->has_focus());
- EXPECT_FALSE(camera_preview_view->has_focus());
- EXPECT_EQ(window2.get(), capture_mode_session->GetSelectedWindow());
- // Continue shift tab should advance back to the window capture source button.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_EQ(FocusGroup::kTypeSource, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(4u, test_api.GetCurrentFocusIndex());
- // Destroy a window and test that the destroyed window will not be included in
- // the keyboard focus navigation.
- window2.reset();
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(test_api.GetHighlightableWindow(window())->has_focus());
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(1u, test_api.GetCurrentFocusIndex());
- EXPECT_TRUE(camera_preview_view->has_focus());
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(2u, test_api.GetCurrentFocusIndex());
- EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
- EXPECT_TRUE(resize_button->has_focus());
- // Continue tab after focusing on the resize button should advance the focus
- // to settings close button.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- }
- TEST_F(CaptureModeCameraTest,
- FocusableCameraPreviewInVideoRecordingWithFullscreenCapture) {
- UpdateDisplay("800x700");
- StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
- AddDefaultCamera();
- auto* camera_controller = GetCameraController();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* event_generator = GetEventGenerator();
- auto* camera_preview_view = camera_controller->camera_preview_view();
- auto* resize_button = GetPreviewResizeButton();
- StartVideoRecordingImmediately();
- EXPECT_TRUE(camera_preview_view->is_collapsible());
- EXPECT_FALSE(camera_controller->is_camera_preview_collapsed());
- // Press shortcut "Search+Alt+S" should focus the camera preview.
- SendKey(ui::VKEY_S, event_generator, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN);
- EXPECT_TRUE(camera_preview_view->has_focus());
- EXPECT_FALSE(resize_button->has_focus());
- EXPECT_FALSE(resize_button->GetVisible());
- // Press tab should fade in the resize button and advance the focus on it.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_FALSE(camera_preview_view->has_focus());
- EXPECT_TRUE(resize_button->has_focus());
- EXPECT_TRUE(resize_button->GetVisible());
- // Shift tab should advance the focus back to the camera preview view. But the
- // resize button will be kept as visible as it will be fade out in a few
- // seconds.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_TRUE(camera_preview_view->has_focus());
- EXPECT_FALSE(resize_button->has_focus());
- EXPECT_TRUE(resize_button->GetVisible());
- // Press tab again to focus on the resize button.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_FALSE(camera_preview_view->has_focus());
- EXPECT_TRUE(resize_button->has_focus());
- EXPECT_TRUE(resize_button->GetVisible());
- // Press space key when the resize button is focused should be able to expand
- // or collapse the camera preview.
- SendKey(ui::VKEY_SPACE, event_generator);
- EXPECT_TRUE(camera_controller->is_camera_preview_collapsed());
- EXPECT_TRUE(resize_button->has_focus());
- SendKey(ui::VKEY_SPACE, event_generator);
- EXPECT_FALSE(camera_controller->is_camera_preview_collapsed());
- EXPECT_TRUE(resize_button->has_focus());
- // Press escape key should remove the focus from the camera preview, either
- // the camera preview view or the resize button.
- SendKey(ui::VKEY_ESCAPE, event_generator);
- EXPECT_FALSE(camera_preview_view->has_focus());
- EXPECT_FALSE(resize_button->has_focus());
- // Press shortcut "Search+Alt+S" should not focus the camera preview when
- // capture session is active even though video recording is in progress.
- auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
- CaptureModeType::kImage);
- EXPECT_TRUE(controller->IsActive());
- EXPECT_TRUE(controller->is_recording_in_progress());
- SendKey(ui::VKEY_S, event_generator, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN);
- EXPECT_FALSE(camera_preview_view->has_focus());
- // Press tab should still able to focus the camera preview view and the resize
- // button.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/5);
- EXPECT_TRUE(camera_preview_view->has_focus());
- EXPECT_FALSE(resize_button->has_focus());
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_FALSE(camera_preview_view->has_focus());
- EXPECT_TRUE(resize_button->has_focus());
- // Continue tab should be able to advance the focus on the settings button.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_FALSE(camera_preview_view->has_focus());
- EXPECT_FALSE(resize_button->has_focus());
- EXPECT_TRUE(CaptureModeSessionTestApi(controller->capture_mode_session())
- .GetCaptureModeBarView()
- ->settings_button()
- ->has_focus());
- }
- TEST_F(CaptureModeCameraTest,
- FocusableCameraPreviewInVideoRecordingWithRegionCapture) {
- auto* controller = CaptureModeController::Get();
- controller->SetUserCaptureRegion(gfx::Rect(10, 10, 400, 550),
- /*by_user=*/true);
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- AddDefaultCamera();
- auto* camera_controller = GetCameraController();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* event_generator = GetEventGenerator();
- auto* camera_preview_view = camera_controller->camera_preview_view();
- auto* resize_button = GetPreviewResizeButton();
- StartVideoRecordingImmediately();
- EXPECT_FALSE(camera_controller->is_camera_preview_collapsed());
- EXPECT_FALSE(camera_preview_view->is_collapsible());
- // Press shortcut "Search+Alt+S" should focus the camera preview.
- SendKey(ui::VKEY_S, event_generator, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN);
- EXPECT_TRUE(camera_preview_view->has_focus());
- EXPECT_FALSE(resize_button->has_focus());
- EXPECT_FALSE(resize_button->GetVisible());
- // Press tab nothing will happen. As the camera preview is not collapsible,
- // which means the camera preview is the only focusable item. Focus will not
- // be moved to the resize button and it will continue to be hidden.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_TRUE(camera_preview_view->has_focus());
- EXPECT_FALSE(resize_button->has_focus());
- EXPECT_FALSE(resize_button->GetVisible());
- // Mouse pressing outside of the camera preview should remove the focus from
- // the camera preview.
- const gfx::Point origin = camera_preview_view->GetBoundsInScreen().origin();
- const gfx::Vector2d delta(-50, -50);
- event_generator->MoveMouseTo(origin + delta);
- event_generator->ClickLeftButton();
- EXPECT_FALSE(camera_preview_view->has_focus());
- EXPECT_FALSE(resize_button->has_focus());
- }
- TEST_F(CaptureModeCameraTest,
- FocusableCameraPreviewInVideoRecordingWithWindowCapture) {
- UpdateDisplay("1366x768");
- window()->SetBounds(gfx::Rect(30, 40, 800, 700));
- auto* controller =
- StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
- AddDefaultCamera();
- auto* camera_controller = GetCameraController();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* event_generator = GetEventGenerator();
- auto* camera_preview_view = camera_controller->camera_preview_view();
- auto* resize_button = GetPreviewResizeButton();
- event_generator->MoveMouseTo(window()->GetBoundsInScreen().origin());
- EXPECT_EQ(controller->capture_mode_session()->GetSelectedWindow(), window());
- StartVideoRecordingImmediately();
- EXPECT_FALSE(camera_controller->is_camera_preview_collapsed());
- EXPECT_TRUE(camera_preview_view->is_collapsible());
- // Press shortcut "Search+Alt+S" should focus the camera preview.
- SendKey(ui::VKEY_S, event_generator, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN);
- EXPECT_TRUE(camera_preview_view->has_focus());
- EXPECT_FALSE(resize_button->has_focus());
- // Press tab should fade in the resize button and advance the focus on it.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_FALSE(camera_preview_view->has_focus());
- EXPECT_TRUE(resize_button->has_focus());
- EXPECT_TRUE(resize_button->GetVisible());
- // Shift tab should advance the focus back to the camera preview view. But the
- // resize button will be kept as visible as it will be fade out in a few
- // seconds.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
- EXPECT_TRUE(camera_preview_view->has_focus());
- EXPECT_FALSE(resize_button->has_focus());
- }
- TEST_F(CaptureModeCameraTest, CaptureBarOpacityChangeOnKeyboardNavigation) {
- using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
- // Update display size and update window with customized size to make sure
- // camera preview overlap with capture bar with capture source `kWindow`.
- UpdateDisplay("1366x768");
- window()->SetBounds({0, 0, 903, 700});
- auto* controller =
- StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
- CaptureModeSessionTestApi test_api(controller->capture_mode_session());
- auto* capture_session = controller->capture_mode_session();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- const auto* camera_preview_widget =
- camera_controller->camera_preview_widget();
- const auto* capture_bar_widget = capture_session->capture_mode_bar_widget();
- const ui::Layer* capture_bar_layer = capture_bar_widget->GetLayer();
- // Move mouse on top of `window` to set the selected window. Verify capture
- // bar is `kOverlapOpacity`.
- auto* event_generator = GetEventGenerator();
- event_generator->MoveMouseTo(window()->GetBoundsInScreen().CenterPoint());
- EXPECT_EQ(capture_session->GetSelectedWindow(), window());
- EXPECT_TRUE(capture_bar_widget->GetWindowBoundsInScreen().Intersects(
- camera_preview_widget->GetWindowBoundsInScreen()));
- EXPECT_EQ(capture_bar_layer->GetTargetOpacity(),
- capture_mode::kCaptureUiOverlapOpacity);
- // Now tab through the capture bar, verify that as long as the focus is on
- // capture bar or capture settings menu, capture bar is updated to full
- // opaque.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(capture_bar_layer->GetTargetOpacity(), 1.0f);
- // Tab four times to focus the last source button (window mode button). Verify
- // capture bar is still fully opaque.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/4);
- EXPECT_EQ(FocusGroup::kTypeSource, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(4u, test_api.GetCurrentFocusIndex());
- EXPECT_EQ(capture_bar_layer->GetTargetOpacity(), 1.0f);
- // Tab once to focus on the window to be captured, verify that capture bar is
- // `kOverlapOpacity` since the focus is removed from capture bar.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(capture_bar_layer->GetTargetOpacity(),
- capture_mode::kCaptureUiOverlapOpacity);
- // Tab three times to focus on the settings button, verify capture bar is
- // updated to fully opaque again.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/3);
- EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
- EXPECT_EQ(capture_bar_layer->GetTargetOpacity(), 1.0f);
- // Now enter space to open the settings menu. Verify capture bar is still full
- // opaque.
- SendKey(ui::VKEY_SPACE, event_generator);
- EXPECT_EQ(FocusGroup::kPendingSettings, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(capture_bar_layer->GetTargetOpacity(), 1.0f);
- // Tab once to focus on the settings menu. Verify capture bar is still full
- // opaque.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(FocusGroup::kSettingsMenu, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(capture_bar_layer->GetTargetOpacity(), 1.0f);
- }
- TEST_F(CaptureModeCameraTest, CaptureLabelOpacityChangeOnKeyboardNavigation) {
- UpdateDisplay("800x600");
- using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
- auto* controller =
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- CaptureModeSessionTestApi test_api(controller->capture_mode_session());
- auto* capture_session = controller->capture_mode_session();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* camera_preview_widget = camera_controller->camera_preview_widget();
- auto* capture_label_widget = capture_session->capture_label_widget();
- ui::Layer* capture_label_layer = capture_label_widget->GetLayer();
- // Select capture region to make sure capture label is overlapped with
- // camera preview. Verify capture label is `kOverlapOpacity`.
- const int min_region_length =
- capture_mode::kMinCaptureSurfaceShortSideLengthForVisibleCamera;
- SelectCaptureRegion({100, 100, min_region_length, min_region_length});
- EXPECT_TRUE(capture_label_widget->GetWindowBoundsInScreen().Intersects(
- camera_preview_widget->GetWindowBoundsInScreen()));
- EXPECT_EQ(capture_label_layer->GetTargetOpacity(),
- capture_mode::kCaptureUiOverlapOpacity);
- auto* event_generator = GetEventGenerator();
- // Tab four times to focus on the region capture source, verify capture label
- // is still `kOverlapOpacity`.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/4);
- EXPECT_EQ(FocusGroup::kTypeSource, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(3u, test_api.GetCurrentFocusIndex());
- EXPECT_EQ(capture_label_layer->GetTargetOpacity(),
- capture_mode::kCaptureUiOverlapOpacity);
- // Tab twice to focus on `kSelection`, verify capture label is still
- // `kOverlapOpacity`.
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/2);
- EXPECT_EQ(FocusGroup::kSelection, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(capture_label_layer->GetTargetOpacity(),
- capture_mode::kCaptureUiOverlapOpacity);
- // Tab eleven times to focus on cpature label, verify capture label is updated
- // to fully opaque.
- EXPECT_FALSE(camera_controller->camera_preview_view()->is_collapsible());
- SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/10);
- EXPECT_EQ(FocusGroup::kCaptureButton, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(capture_label_layer->GetTargetOpacity(), 1.0f);
- // Tab once to focus on the setting button on capture bar, verify capture
- // lable's opacity is updated to `kOverlapOpacity`.
- SendKey(ui::VKEY_TAB, event_generator);
- EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
- EXPECT_EQ(capture_label_layer->GetTargetOpacity(),
- capture_mode::kCaptureUiOverlapOpacity);
- }
- // Tests that when switching capture source from `kRegion` to `kFullscreen`,
- // camera preview should be shown.
- // Regression test for https://crbug.com/1316911.
- TEST_F(CaptureModeCameraTest, CameraPreviewVisibilityOnCaptureSourceChanged) {
- StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
- AddDefaultCamera();
- CaptureModeTestApi().SelectCameraAtIndex(0);
- auto* camera_preview_widget = GetCameraController()->camera_preview_widget();
- auto* preview_window = camera_preview_widget->GetNativeWindow();
- // Verify that camera preview is visible.
- EXPECT_EQ(preview_window->parent(),
- preview_window->GetRootWindow()->GetChildById(
- kShellWindowId_MenuContainer));
- EXPECT_TRUE(camera_preview_widget->IsVisible());
- EXPECT_TRUE(preview_window->TargetVisibility());
- // Click on the region source button, verify that camera preview is parented
- // to UnparentedContainer and becomes invisible.
- auto* event_generator = GetEventGenerator();
- ClickOnView(GetRegionToggleButton(), event_generator);
- EXPECT_EQ(preview_window->parent(),
- preview_window->GetRootWindow()->GetChildById(
- kShellWindowId_UnparentedContainer));
- EXPECT_FALSE(camera_preview_widget->IsVisible());
- // Now switch capture source to `kFullscreen`, verify that camera preview is
- // parented to MenuContainer and becomes visible again.
- ClickOnView(GetFullscreenToggleButton(), event_generator);
- EXPECT_EQ(preview_window->parent(),
- preview_window->GetRootWindow()->GetChildById(
- kShellWindowId_MenuContainer));
- EXPECT_TRUE(preview_window->TargetVisibility());
- EXPECT_TRUE(camera_preview_widget->IsVisible());
- }
- // Tests that the recording starts with camera metrics are recorded correctly
- // both in clamshell and tablet mode.
- TEST_F(CaptureModeCameraTest, RecordingStartsWithCameraHistogramTest) {
- base::HistogramTester histogram_tester;
- constexpr char kHistogramNameBase[] =
- "Ash.CaptureModeController.RecordingStartsWithCamera";
- AddDefaultCamera();
- struct {
- bool tablet_enabled;
- bool camera_on;
- } kTestCases[] = {
- {false, false},
- {false, true},
- {true, false},
- {true, true},
- };
- for (const auto test_case : kTestCases) {
- if (test_case.tablet_enabled) {
- SwitchToTabletMode();
- EXPECT_TRUE(Shell::Get()->IsInTabletMode());
- } else {
- EXPECT_FALSE(Shell::Get()->IsInTabletMode());
- }
- histogram_tester.ExpectBucketCount(
- GetCaptureModeHistogramName(kHistogramNameBase), test_case.camera_on,
- 0);
- auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
- CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- camera_controller->SetSelectedCamera(
- test_case.camera_on ? CameraId(kDefaultCameraModelId, 1) : CameraId());
- StartVideoRecordingImmediately();
- EXPECT_TRUE(controller->is_recording_in_progress());
- controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
- WaitForCaptureFileToBeSaved();
- histogram_tester.ExpectBucketCount(
- GetCaptureModeHistogramName(kHistogramNameBase), test_case.camera_on,
- 1);
- }
- }
- // Tests that the number of camera disconnections happens during recording is
- // recorded correctly both in clamshell and tablet mode.
- TEST_F(CaptureModeCameraTest,
- RecordCameraDisconnectionsDuringRecordingsHistogramTest) {
- constexpr char kHistogramNameBase[] =
- "Ash.CaptureModeController.CameraDisconnectionsDuringRecordings";
- base::HistogramTester histogram_tester;
- auto* camera_controller = GetCameraController();
- auto disconnect_and_reconnect_camera_n_times = [&](int n) {
- for (int i = 0; i < n; i++) {
- AddAndRemoveCameraAndTriggerGracePeriod();
- camera_controller->camera_reconnect_timer_for_test()->FireNow();
- }
- };
- for (const bool tablet_enabled : {false, true}) {
- if (tablet_enabled) {
- SwitchToTabletMode();
- EXPECT_TRUE(Shell::Get()->IsInTabletMode());
- } else {
- EXPECT_FALSE(Shell::Get()->IsInTabletMode());
- }
- auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
- CaptureModeType::kVideo);
- controller->StartVideoRecordingImmediatelyForTesting();
- // Disconnect the camera, exhaust the timer and reconnect three times. The
- // metric should record accordingly.
- disconnect_and_reconnect_camera_n_times(3);
- controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
- WaitForCaptureFileToBeSaved();
- histogram_tester.ExpectBucketCount(
- GetCaptureModeHistogramName(kHistogramNameBase), 3, 1);
- }
- }
- // Tests that the number of connected cameras to the device is recorded whenever
- // the number changes.
- TEST_F(CaptureModeCameraTest, RecordNumberOfConnectedCamerasHistogramTest) {
- constexpr char kHistogramNameBase[] =
- "Ash.CaptureModeController.NumberOfConnectedCameras";
- base::HistogramTester histogram_tester;
- // Make sure the device change alert triggered by the SystemMonitor is handled
- // before we connect a camera device.
- {
- base::RunLoop loop;
- GetCameraController()->SetOnCameraListReceivedForTesting(
- loop.QuitClosure());
- base::SystemMonitor::Get()->ProcessDevicesChanged(
- base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
- loop.Run();
- }
- // Verify that before we connect any camera device, there's 0 cameras and it
- // has been recorded.
- histogram_tester.ExpectBucketCount(kHistogramNameBase, 0, 1);
- // Connect one camera, verify that the number of one camera device has been
- // recorded once.
- AddFakeCamera("/dev/video", "fake cam ", "model 1");
- histogram_tester.ExpectBucketCount(kHistogramNameBase, 1, 1);
- // Connect the second camera, verify that the number of two camera devices has
- // been recorded once.
- AddFakeCamera("/dev/video1", "fake cam 2", "model 2");
- histogram_tester.ExpectBucketCount(kHistogramNameBase, 2, 1);
- // Disconnect the second camera, now the number of connected cameres drops
- // back to one, verify that the number of one camera device has been recorded
- // twice.
- RemoveFakeCamera("/dev/video1");
- histogram_tester.ExpectBucketCount(kHistogramNameBase, 1, 2);
- // Connect the third camera, now the number of connected cameras is two again,
- // verify that the number of two camera devices has been recorded twice.
- AddFakeCamera("/dev/video2", "fake cam 3", "model 3");
- histogram_tester.ExpectBucketCount(kHistogramNameBase, 2, 2);
- }
- // Tests that the duration for disconnected camera to become available again is
- // recorded correctly both in clamshell and tablet mode.
- TEST_F(CaptureModeCameraTest, RecordCameraReconnectDurationHistogramTest) {
- constexpr char kHistogramNameBase[] =
- "Ash.CaptureModeController.CameraReconnectDuration";
- base::HistogramTester histogram_tester;
- for (const bool tablet_enabled : {false, true}) {
- if (tablet_enabled) {
- SwitchToTabletMode();
- EXPECT_TRUE(Shell::Get()->IsInTabletMode());
- } else {
- EXPECT_FALSE(Shell::Get()->IsInTabletMode());
- }
- AddAndRemoveCameraAndTriggerGracePeriod();
- WaitForSeconds(1);
- AddDefaultCamera();
- histogram_tester.ExpectBucketCount(
- GetCaptureModeHistogramName(kHistogramNameBase), 1, 1);
- RemoveDefaultCamera();
- }
- }
- // Tests that the camera size on start is recorded correctly in the metrics both
- // in clamshell and tablet mode.
- TEST_F(CaptureModeCameraTest, RecordingCameraSizeOnStartHistogramTest) {
- UpdateDisplay("1366x768");
- constexpr char kHistogramNameBase[] =
- "Ash.CaptureModeController.RecordingCameraSizeOnStart";
- base::HistogramTester histogram_tester;
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- for (const bool tablet_enabled : {false, true}) {
- if (tablet_enabled) {
- SwitchToTabletMode();
- EXPECT_TRUE(Shell::Get()->IsInTabletMode());
- } else {
- EXPECT_FALSE(Shell::Get()->IsInTabletMode());
- }
- for (const bool collapsed : {false, true}) {
- const auto sample = collapsed ? CaptureModeCameraSize::kCollapsed
- : CaptureModeCameraSize::kExpanded;
- histogram_tester.ExpectBucketCount(
- GetCaptureModeHistogramName(kHistogramNameBase), sample, 0);
- auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
- CaptureModeType::kVideo);
- auto* event_generator = GetEventGenerator();
- // Resize button is hidden by default, click/tap on the preview to make
- // it visible.
- ClickOrTapView(camera_controller->camera_preview_view(), tablet_enabled,
- event_generator);
- auto* resize_button = GetPreviewResizeButton();
- DCHECK(resize_button);
- if (collapsed) {
- if (!camera_controller->is_camera_preview_collapsed())
- ClickOrTapView(resize_button, tablet_enabled, event_generator);
- EXPECT_TRUE(camera_controller->is_camera_preview_collapsed());
- } else {
- if (camera_controller->is_camera_preview_collapsed())
- ClickOrTapView(resize_button, tablet_enabled, event_generator);
- EXPECT_FALSE(camera_controller->is_camera_preview_collapsed());
- }
- StartVideoRecordingImmediately();
- controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
- WaitForCaptureFileToBeSaved();
- histogram_tester.ExpectBucketCount(
- GetCaptureModeHistogramName(kHistogramNameBase), sample, 1);
- }
- }
- }
- // Tests that the camera position on start is recorded correctly in the metrics
- // both in clamshell and tablet mode.
- TEST_F(CaptureModeCameraTest, RecordingCameraPositionOnStartHistogramTest) {
- constexpr char kHistogramName[] =
- "Ash.CaptureModeController.RecordingCameraPositionOnStart";
- base::HistogramTester histogram_tester;
- StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
- AddDefaultCamera();
- auto* camera_controller = GetCameraController();
- const CameraId camera_id(kDefaultCameraModelId, 1);
- camera_controller->SetSelectedCamera(camera_id);
- const CameraPreviewSnapPosition kCameraPositionTestCases[]{
- CameraPreviewSnapPosition::kTopLeft,
- CameraPreviewSnapPosition::kBottomLeft,
- CameraPreviewSnapPosition::kTopRight,
- CameraPreviewSnapPosition::kBottomRight};
- for (const bool tablet_enabled : {false, true}) {
- if (tablet_enabled) {
- SwitchToTabletMode();
- EXPECT_TRUE(Shell::Get()->IsInTabletMode());
- } else {
- EXPECT_FALSE(Shell::Get()->IsInTabletMode());
- }
- for (const auto camera_position : kCameraPositionTestCases) {
- histogram_tester.ExpectBucketCount(
- GetCaptureModeHistogramName(kHistogramName), camera_position, 0);
- auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
- CaptureModeType::kVideo);
- DCHECK(camera_controller->camera_preview_widget());
- camera_controller->SetCameraPreviewSnapPosition(camera_position);
- StartVideoRecordingImmediately();
- controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
- WaitForCaptureFileToBeSaved();
- histogram_tester.ExpectBucketCount(
- GetCaptureModeHistogramName(kHistogramName), camera_position, 1);
- }
- }
- }
- TEST_F(CaptureModeCameraTest, ToastVisibilityChangeOnCaptureRegionUpdated) {
- UpdateDisplay("800x600");
- auto* controller =
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- auto* capture_session = controller->capture_mode_session();
- auto* camera_controller = GetCameraController();
- auto* capture_toast_controller = capture_session->capture_toast_controller();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- // Set capture region big enough to fit the camera preview. Verify the
- // current capture toast is `kUserNudge`.
- const gfx::Rect capture_region(100, 100, 300, 300);
- SelectCaptureRegion(capture_region);
- auto* capture_toast_widget = capture_toast_controller->capture_toast_widget();
- EXPECT_TRUE(capture_toast_widget);
- ASSERT_TRUE(capture_toast_controller->current_toast_type());
- EXPECT_EQ(*(capture_toast_controller->current_toast_type()),
- CaptureToastType::kUserNudge);
- // Update capture region small enough to not fit the camera preview. Verify
- // that the capture toast is updated to `kCameraPreview` and the user nudge is
- // dismissed forever.
- const int delta_x =
- capture_mode::kMinCaptureSurfaceShortSideLengthForVisibleCamera - 30 -
- capture_region.width();
- const int delta_y =
- capture_mode::kMinCaptureSurfaceShortSideLengthForVisibleCamera - 30 -
- capture_region.height();
- const gfx::Vector2d delta(delta_x, delta_y);
- auto* event_generator = GetEventGenerator();
- event_generator->set_current_screen_location(capture_region.bottom_right());
- event_generator->PressLeftButton();
- // Verify that when drag starts, the capture toast is hidden.
- EXPECT_FALSE(capture_toast_widget->IsVisible());
- event_generator->MoveMouseTo(capture_region.bottom_right() + delta);
- event_generator->ReleaseLeftButton();
- EXPECT_EQ(*(capture_toast_controller->current_toast_type()),
- CaptureToastType::kCameraPreview);
- EXPECT_TRUE(capture_toast_widget->IsVisible());
- EXPECT_FALSE(GetUserNudgeController());
- // Start dragging the capture region again to update it, but make it still
- // small enough to not fit the camera preview. Verify at the beginning of the
- // drag, preview toast is hidden. After the drag is released, preview toast is
- // shown again.
- const gfx::Vector2d delta1(delta_x + 10, delta_y + 10);
- event_generator->set_current_screen_location(capture_region.bottom_right());
- event_generator->PressLeftButton();
- // Verify that when drag starts, the capture toast is hidden.
- EXPECT_FALSE(capture_toast_widget->IsVisible());
- event_generator->MoveMouseTo(capture_region.bottom_right() + delta1);
- event_generator->ReleaseLeftButton();
- ASSERT_TRUE(capture_toast_controller->current_toast_type());
- EXPECT_EQ(*(capture_toast_controller->current_toast_type()),
- CaptureToastType::kCameraPreview);
- EXPECT_TRUE(capture_toast_widget->IsVisible());
- // Update capture region big enough to show the camera preview. Verify the
- // preview toast is hidden.
- event_generator->set_current_screen_location(capture_region.origin());
- event_generator->PressLeftButton();
- // Verify that when drag starts, the capture toast is hidden.
- EXPECT_FALSE(capture_toast_widget->IsVisible());
- event_generator->MoveMouseTo(capture_region.bottom_right());
- event_generator->ReleaseLeftButton();
- // Verify that since the capture toast is dismissed, current toast type is
- // reset.
- EXPECT_FALSE(capture_toast_controller->current_toast_type());
- EXPECT_FALSE(capture_toast_widget->IsVisible());
- }
- // Tests that the capture toast will be faded out on time out when there are no
- // actions taken.
- TEST_F(CaptureModeCameraTest, ToastVisibilityChangeOnTimeOut) {
- UpdateDisplay("800x600");
- auto* controller =
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- auto* capture_session = controller->capture_mode_session();
- auto* camera_controller = GetCameraController();
- auto* capture_toast_controller = capture_session->capture_toast_controller();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- // Set capture region small enough to not fit the camera preview. Verify the
- // current capture toast is `kCameraPreview`.
- const gfx::Rect capture_region = GetTooSmallToFitCameraRegion();
- SelectCaptureRegion(capture_region);
- auto* capture_toast_widget = capture_toast_controller->capture_toast_widget();
- EXPECT_TRUE(capture_toast_widget->IsVisible());
- ASSERT_TRUE(capture_toast_controller->current_toast_type());
- EXPECT_EQ(*(capture_toast_controller->current_toast_type()),
- CaptureToastType::kCameraPreview);
- // Verify the timer is running after the toast is shown and when the timer is
- // fired, the capture toast is hidden.
- base::OneShotTimer* timer =
- capture_toast_controller->capture_toast_dismiss_timer_for_test();
- EXPECT_TRUE(timer->IsRunning());
- timer->FireNow();
- EXPECT_FALSE(capture_toast_widget->IsVisible());
- }
- TEST_F(CaptureModeCameraTest, ToastVisibilityChangeOnSettingsMenuOpen) {
- UpdateDisplay("800x600");
- auto* controller =
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- auto* capture_session = controller->capture_mode_session();
- auto* camera_controller = GetCameraController();
- auto* capture_toast_controller = capture_session->capture_toast_controller();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- // Set capture region small enough to not fit the camera preview. Verify the
- // current capture toast is `kCameraPreview`.
- const gfx::Rect capture_region = GetTooSmallToFitCameraRegion();
- SelectCaptureRegion(capture_region);
- auto* capture_toast_widget = capture_toast_controller->capture_toast_widget();
- EXPECT_TRUE(capture_toast_widget->IsVisible());
- ASSERT_TRUE(capture_toast_controller->current_toast_type());
- EXPECT_EQ(*(capture_toast_controller->current_toast_type()),
- CaptureToastType::kCameraPreview);
- // Now open settings menu, verify that preview toast is dismissed immediately
- // on settings menu open.
- OpenSettingsView();
- EXPECT_FALSE(capture_toast_widget->IsVisible());
- }
- TEST_F(CaptureModeCameraTest, ToastVisibilityChangeOnCaptureRegionMoved) {
- UpdateDisplay("800x600");
- auto* controller =
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- auto* capture_session = controller->capture_mode_session();
- auto* camera_controller = GetCameraController();
- auto* capture_toast_controller = capture_session->capture_toast_controller();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- // Set capture region small enough to not fit the camera preview. Verify the
- // current capture toast is `kCameraPreview`.
- const gfx::Rect capture_region = GetTooSmallToFitCameraRegion();
- SelectCaptureRegion(capture_region);
- auto* capture_toast_widget = capture_toast_controller->capture_toast_widget();
- EXPECT_TRUE(capture_toast_widget->IsVisible());
- ASSERT_TRUE(capture_toast_controller->current_toast_type());
- EXPECT_EQ(*(capture_toast_controller->current_toast_type()),
- CaptureToastType::kCameraPreview);
- // Start moving the capture region, verify the preview toast is hidden at the
- // beginning of the move and is shown once the move is done.
- const gfx::Vector2d delta(20, 20);
- auto* event_generator = GetEventGenerator();
- event_generator->MoveMouseTo(capture_region.origin() + delta);
- event_generator->PressLeftButton();
- EXPECT_FALSE(capture_toast_widget->IsVisible());
- event_generator->MoveMouseTo(capture_region.CenterPoint());
- event_generator->ReleaseLeftButton();
- EXPECT_TRUE(capture_toast_widget->IsVisible());
- }
- // Tests that the preview toast shows correctly when capture mode is turned on
- // through quick settings which keeps the configurations) from the previous
- // session.
- TEST_F(CaptureModeCameraTest, ToastVisibilityChangeOnCaptureModeTurnedOn) {
- UpdateDisplay("800x600");
- auto* controller =
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- auto* capture_session = controller->capture_mode_session();
- auto* camera_controller = GetCameraController();
- auto* capture_toast_controller = capture_session->capture_toast_controller();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- // Set capture region small enough to not fit the camera preview. Verify the
- // current capture toast is `kCameraPreview`.
- const gfx::Rect capture_region = GetTooSmallToFitCameraRegion();
- SelectCaptureRegion(capture_region);
- auto* capture_toast_widget = capture_toast_controller->capture_toast_widget();
- EXPECT_TRUE(capture_toast_widget->IsVisible());
- ASSERT_TRUE(capture_toast_controller->current_toast_type());
- EXPECT_EQ(*(capture_toast_controller->current_toast_type()),
- CaptureToastType::kCameraPreview);
- // Close capture mode.
- controller->Stop();
- // Turn on capture mode again through the quick settings, verify that toast
- // preview is visible.
- controller->Start(CaptureModeEntryType::kQuickSettings);
- capture_session = controller->capture_mode_session();
- capture_toast_controller = capture_session->capture_toast_controller();
- EXPECT_TRUE(capture_toast_controller->capture_toast_widget()->IsVisible());
- ASSERT_TRUE(capture_toast_controller->current_toast_type());
- EXPECT_EQ(*(capture_toast_controller->current_toast_type()),
- CaptureToastType::kCameraPreview);
- }
- TEST_F(CaptureModeCameraTest, ToastStackingOrderChangeOnCaptureModeTurnedOn) {
- auto* controller =
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- // Set capture region small enough to make capture toast shown.
- const gfx::Rect capture_region = GetTooSmallToFitCameraRegion();
- SelectCaptureRegion(capture_region);
- // Close capture mode.
- controller->Stop();
- // Turn on capture mode again through the quick settings, verify that the
- // stacking order for capture toast relative to other capture UIs is correct.
- controller->Start(CaptureModeEntryType::kQuickSettings);
- auto* capture_session = controller->capture_mode_session();
- auto* capture_toast_controller = capture_session->capture_toast_controller();
- auto* capture_toast_widget = capture_toast_controller->capture_toast_widget();
- auto* capture_toast_window = capture_toast_widget->GetNativeWindow();
- auto* capture_label_window =
- capture_session->capture_label_widget()->GetNativeWindow();
- auto* capture_bar_window =
- capture_session->capture_mode_bar_widget()->GetNativeWindow();
- auto* camera_preview_window =
- camera_controller->camera_preview_widget()->GetNativeWindow();
- EXPECT_TRUE(
- IsWindowStackedRightBelow(capture_label_window, capture_bar_window));
- EXPECT_TRUE(
- IsWindowStackedRightBelow(capture_toast_window, capture_label_window));
- EXPECT_TRUE(
- IsWindowStackedRightBelow(camera_preview_window, capture_toast_window));
- EXPECT_TRUE(IsLayerStackedRightBelow(capture_session->layer(),
- camera_preview_window->layer()));
- }
- TEST_F(CaptureModeCameraTest, ToastVisibilityChangeOnPerformingCapture) {
- UpdateDisplay("800x600");
- auto* controller =
- StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
- auto* capture_session = controller->capture_mode_session();
- auto* camera_controller = GetCameraController();
- auto* capture_toast_controller = capture_session->capture_toast_controller();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- // Set capture region small enough to not fit the camera preview. Verify the
- // current capture toast is `kCameraPreview`.
- const gfx::Rect capture_region = GetTooSmallToFitCameraRegion();
- SelectCaptureRegion(capture_region);
- auto* capture_toast_widget = capture_toast_controller->capture_toast_widget();
- EXPECT_TRUE(capture_toast_widget->IsVisible());
- ASSERT_TRUE(capture_toast_controller->current_toast_type());
- EXPECT_EQ(*(capture_toast_controller->current_toast_type()),
- CaptureToastType::kCameraPreview);
- // Perform the screen recording, verify that the capture toast is going to be
- // faded out.
- controller->PerformCapture();
- EXPECT_EQ(capture_toast_widget->GetLayer()->GetTargetOpacity(), 0.f);
- }
- TEST_F(CaptureModeCameraTest, ToastVisibilityChangeOnMultiDisplays) {
- UpdateDisplay("800x700,801+0-800x700");
- const gfx::Rect first_display_bounds(0, 0, 800, 700);
- const gfx::Rect second_display_bounds(801, 0, 800, 700);
- // Set the window's bounds small enough to not fit the camera preview.
- window()->SetBoundsInScreen(
- gfx::Rect(600, 500, 100, 100),
- display::Screen::GetScreen()->GetDisplayNearestWindow(
- Shell::GetAllRootWindows()[0]));
- // Create a window in the second display and set its bounds small enough to
- // not fit the camera preview.
- std::unique_ptr<aura::Window> window1(CreateTestWindow());
- window1->SetBoundsInScreen(
- gfx::Rect(1400, 500, 100, 100),
- display::Screen::GetScreen()->GetDisplayNearestWindow(
- Shell::GetAllRootWindows()[1]));
- // Start the capture session.
- auto* controller =
- StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
- auto* camera_controller = GetCameraController();
- auto* capture_session = controller->capture_mode_session();
- auto* capture_toast_controller = capture_session->capture_toast_controller();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- // Move the mouse on top of `window` to select it, since it's too small to fit
- // the camera preview, verify the preview toast shows and it's on the first
- // display.
- auto* event_generator = GetEventGenerator();
- event_generator->MoveMouseTo(window()->GetBoundsInScreen().CenterPoint());
- EXPECT_EQ(capture_session->GetSelectedWindow(), window());
- auto* capture_toast_widget = capture_toast_controller->capture_toast_widget();
- EXPECT_TRUE(capture_toast_widget->IsVisible());
- ASSERT_TRUE(capture_toast_controller->current_toast_type());
- EXPECT_EQ(*(capture_toast_controller->current_toast_type()),
- CaptureToastType::kCameraPreview);
- first_display_bounds.Contains(
- capture_toast_widget->GetWindowBoundsInScreen());
- // Now move the mouse to the top of `window1`, since it's also too small to
- // fit the camera preview, verify the preview toast still shows. Since
- // `window1` is on the second display, verify the preview toast also shows up
- // on the second display.
- event_generator->MoveMouseTo(window1->GetBoundsInScreen().CenterPoint());
- EXPECT_EQ(capture_session->GetSelectedWindow(), window1.get());
- EXPECT_TRUE(capture_toast_widget->IsVisible());
- ASSERT_TRUE(capture_toast_controller->current_toast_type());
- EXPECT_EQ(*(capture_toast_controller->current_toast_type()),
- CaptureToastType::kCameraPreview);
- second_display_bounds.Contains(
- capture_toast_widget->GetWindowBoundsInScreen());
- // Move mouse to the outside of `window1`, verify that preview toast is
- // dismissed since there's no window selected for now.
- event_generator->MoveMouseTo({1300, 500});
- EXPECT_FALSE(capture_toast_widget->IsVisible());
- // Update the bounds of `window` big enough to fit the camera preview.
- window()->SetBoundsInScreen(
- gfx::Rect(100, 200, 300, 300),
- display::Screen::GetScreen()->GetDisplayNearestWindow(
- Shell::GetAllRootWindows()[0]));
- // Now move the mouse to the top of `window` again, verify that preview toast
- // is not shown, since the window is big enough to show the camera preview.
- event_generator->MoveMouseTo(window()->GetBoundsInScreen().CenterPoint());
- EXPECT_EQ(capture_session->GetSelectedWindow(), window());
- EXPECT_FALSE(capture_toast_widget->IsVisible());
- }
- class CaptureModeCameraPreviewTest
- : public CaptureModeCameraTest,
- public testing::WithParamInterface<CaptureModeSource> {
- public:
- enum class CameraPreviewState {
- // The camera preview is shown inside an area that makes its expanded size
- // big enough so it can collapse to a smaller size.
- kCollapsible,
- // The camera preview is shown inside an area that is small enough to
- // disable its collapsability without causing it to hide.
- kNotCollapsible,
- // The camera preview is shown inside an area that is too small for it to
- // show at all.
- kHidden,
- };
- CaptureModeCameraPreviewTest() = default;
- CaptureModeCameraPreviewTest(const CaptureModeCameraPreviewTest&) = delete;
- CaptureModeCameraPreviewTest& operator=(const CaptureModeCameraPreviewTest&) =
- delete;
- ~CaptureModeCameraPreviewTest() override = default;
- void StartCaptureSessionWithParam() {
- auto* controller = CaptureModeController::Get();
- const gfx::Rect capture_region(10, 20, 1300, 750);
- controller->SetUserCaptureRegion(capture_region, /*by_user=*/true);
- // Set the window's bounds big enough here to make sure after display
- // rotation, the event is located on top of `window_`.
- // TODO(conniekxu): investigate why the position of the event received is
- // different than the position we pass.
- window()->SetBounds({30, 40, 1300, 750});
- StartCaptureSession(GetParam(), CaptureModeType::kVideo);
- if (GetParam() == CaptureModeSource::kWindow)
- GetEventGenerator()->MoveMouseToCenterOf(window());
- }
- gfx::Size GetMinSurfaceSizeForCollapsibleCamera() const {
- const int min_length = capture_mode::kMinCollapsibleCameraPreviewDiameter *
- capture_mode::kCaptureSurfaceShortSideDivider;
- return gfx::Size(min_length, min_length);
- }
- gfx::Size GetMinSurfaceSizeSoCameraBecomes(
- CameraPreviewState preview_state) const {
- gfx::Size min_size = GetMinSurfaceSizeForCollapsibleCamera();
- switch (preview_state) {
- case CameraPreviewState::kCollapsible:
- min_size.Enlarge(10, 20);
- break;
- case CameraPreviewState::kNotCollapsible:
- min_size.Enlarge(-10, -20);
- break;
- case CameraPreviewState::kHidden:
- const int length_for_hidden =
- capture_mode::kMinCaptureSurfaceShortSideLengthForVisibleCamera - 5;
- min_size.SetSize(length_for_hidden, length_for_hidden - 5);
- break;
- }
- return min_size;
- }
- void ResizeDisplaySoCameraPreviewBecomes(CameraPreviewState preview_state) {
- gfx::Size min_size = GetMinSurfaceSizeSoCameraBecomes(preview_state);
- const int shelf_size = ShelfConfig::Get()->shelf_size();
- min_size.Enlarge(shelf_size, shelf_size);
- UpdateDisplay(min_size.ToString());
- }
- void ResizeRegionSoCameraPreviewBecomes(CameraPreviewState preview_state) {
- CaptureModeController::Get()->SetUserCaptureRegion(
- gfx::Rect(GetMinSurfaceSizeSoCameraBecomes(preview_state)),
- /*by_user=*/true);
- }
- void ResizeWindowSoCameraPreviewBecomes(CameraPreviewState preview_state) {
- window()->SetBounds(
- gfx::Rect(GetMinSurfaceSizeSoCameraBecomes(preview_state)));
- }
- void ResizeSurfaceSoCameraPreviewBecomes(CameraPreviewState preview_state) {
- switch (GetParam()) {
- case CaptureModeSource::kFullscreen:
- ResizeDisplaySoCameraPreviewBecomes(preview_state);
- break;
- case CaptureModeSource::kRegion:
- ResizeRegionSoCameraPreviewBecomes(preview_state);
- break;
- case CaptureModeSource::kWindow:
- ResizeWindowSoCameraPreviewBecomes(preview_state);
- break;
- }
- }
- // Based on the `CaptureModeSource`, it returns the current capture region's
- // bounds in screen.
- gfx::Rect GetCaptureBoundsInScreen() const {
- auto* controller = CaptureModeController::Get();
- auto* root = GetCurrentRoot();
- switch (GetParam()) {
- case CaptureModeSource::kFullscreen:
- return display::Screen::GetScreen()
- ->GetDisplayNearestWindow(root)
- .work_area();
- case CaptureModeSource::kRegion: {
- auto* recording_watcher =
- controller->video_recording_watcher_for_testing();
- gfx::Rect capture_region =
- controller->is_recording_in_progress()
- ? recording_watcher->GetEffectivePartialRegionBounds()
- : controller->user_capture_region();
- wm::ConvertRectToScreen(root, &capture_region);
- return capture_region;
- }
- case CaptureModeSource::kWindow:
- return window()->GetBoundsInScreen();
- }
- }
- gfx::Size GetExpectedPreviewSize(bool collapsed) const {
- return capture_mode_util::CalculateCameraPreviewSizeSpecs(
- GetCaptureBoundsInScreen().size(), collapsed)
- .size;
- }
- // Returns the cursor type when cursor is on top of the current capture
- // surface.
- ui::mojom::CursorType GetCursorTypeOnCaptureSurface() const {
- DCHECK(CaptureModeController::Get()->IsActive());
- switch (GetParam()) {
- case CaptureModeSource::kFullscreen:
- case CaptureModeSource::kWindow:
- return ui::mojom::CursorType::kCustom;
- case CaptureModeSource::kRegion:
- return ui::mojom::CursorType::kMove;
- }
- }
- };
- TEST_P(CaptureModeCameraPreviewTest, PreviewVisibilityWhileFolderSelection) {
- AddDefaultCamera();
- StartCaptureSessionWithParam();
- CaptureModeTestApi().SelectCameraAtIndex(0);
- // The camera preview should be initially visible.
- auto* controller = CaptureModeController::Get();
- ASSERT_TRUE(controller->IsActive());
- auto* preview_widget = GetCameraController()->camera_preview_widget();
- ASSERT_TRUE(preview_widget);
- EXPECT_TRUE(preview_widget->IsVisible());
- // Click on the settings button, the settings menu should open, and the camera
- // preview should remain visible.
- CaptureModeSessionTestApi session_test_api(
- controller->capture_mode_session());
- auto* settings_button =
- session_test_api.GetCaptureModeBarView()->settings_button();
- auto* event_generator = GetEventGenerator();
- ClickOnView(settings_button, event_generator);
- ASSERT_TRUE(session_test_api.GetCaptureModeSettingsWidget());
- EXPECT_TRUE(preview_widget->IsVisible());
- // Click on the "Select folder ..." option, the folder selection dialog should
- // open, all capture UIs should hide, including the camera preview.
- CaptureModeSettingsTestApi settings_test_api;
- ClickOnView(settings_test_api.GetSelectFolderMenuItem(), event_generator);
- EXPECT_TRUE(session_test_api.IsFolderSelectionDialogShown());
- EXPECT_FALSE(session_test_api.IsAllUisVisible());
- EXPECT_FALSE(preview_widget->IsVisible());
- // Dismiss the folder selection dialog, all capture UIs should show again,
- // including the camera preview.
- FakeFolderSelectionDialogFactory::Get()->CancelDialog();
- EXPECT_FALSE(session_test_api.IsFolderSelectionDialogShown());
- EXPECT_TRUE(session_test_api.IsAllUisVisible());
- EXPECT_TRUE(preview_widget->IsVisible());
- }
- // Tests that camera preview's bounds is updated after display rotations with
- // two use cases, when capture session is active and when there's a video
- // recording in progress.
- TEST_P(CaptureModeCameraPreviewTest, DisplayRotation) {
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- // Verify that the camera preview should be at the bottom right corner of
- // capture bounds.
- VerifyPreviewAlignment(GetCaptureBoundsInScreen());
- // Rotate the primary display by 90 degrees. Verify that the camera preview
- // is still at the bottom right corner of capture bounds.
- Shell::Get()->display_manager()->SetDisplayRotation(
- WindowTreeHostManager::GetPrimaryDisplayId(), display::Display::ROTATE_90,
- display::Display::RotationSource::USER);
- VerifyPreviewAlignment(GetCaptureBoundsInScreen());
- // Start video recording, verify camera preview's bounds is updated after
- // display rotations when there's a video recording in progress.
- StartVideoRecordingImmediately();
- EXPECT_FALSE(CaptureModeController::Get()->IsActive());
- // Rotate the primary display by 180 degrees. Verify that the camera preview
- // is still at the bottom right corner of capture bounds.
- Shell::Get()->display_manager()->SetDisplayRotation(
- WindowTreeHostManager::GetPrimaryDisplayId(),
- display::Display::ROTATE_180, display::Display::RotationSource::USER);
- VerifyPreviewAlignment(GetCaptureBoundsInScreen());
- // Rotate the primary display by 270 degrees. Verify that the camera preview
- // is still at the bottom right corner of capture bounds.
- Shell::Get()->display_manager()->SetDisplayRotation(
- WindowTreeHostManager::GetPrimaryDisplayId(),
- display::Display::ROTATE_270, display::Display::RotationSource::USER);
- VerifyPreviewAlignment(GetCaptureBoundsInScreen());
- }
- // Tests that when camera preview is being dragged, at the end of the drag, it
- // should be snapped to the correct snap position. It tests two use cases,
- // when capture session is active and when there's a video recording in
- // progress including drag to snap by mouse and by touch.
- TEST_P(CaptureModeCameraPreviewTest, CameraPreviewDragToSnap) {
- UpdateDisplay("1600x800");
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* preview_widget = camera_controller->camera_preview_widget();
- const gfx::Point capture_bounds_center_point =
- GetCaptureBoundsInScreen().CenterPoint();
- // Verify that by default the snap position should be `kBottomRight` and
- // camera preview is placed at the correct position.
- EXPECT_EQ(CameraPreviewSnapPosition::kBottomRight,
- camera_controller->camera_preview_snap_position());
- VerifyPreviewAlignment(GetCaptureBoundsInScreen());
- // Drag the camera preview for a small distance. Tests that even though the
- // snap position does not change, the preview should be snapped back to its
- // previous position.
- DragPreviewToPoint(preview_widget, {capture_bounds_center_point.x() + 20,
- capture_bounds_center_point.y() + 20});
- EXPECT_EQ(CameraPreviewSnapPosition::kBottomRight,
- camera_controller->camera_preview_snap_position());
- VerifyPreviewAlignment(GetCaptureBoundsInScreen());
- // Drag and drop camera preview by mouse to the top right of the
- // `capture_bounds_center_point`, verify that camera preview is snapped to
- // the top right with correct position.
- DragPreviewToPoint(preview_widget, {capture_bounds_center_point.x() + 20,
- capture_bounds_center_point.y() - 20});
- EXPECT_EQ(CameraPreviewSnapPosition::kTopRight,
- camera_controller->camera_preview_snap_position());
- VerifyPreviewAlignment(GetCaptureBoundsInScreen());
- // Now drag and drop camera preview by touch to the top left of the center
- // point, verify that camera preview is snapped to the top left with correct
- // position.
- DragPreviewToPoint(preview_widget,
- {capture_bounds_center_point.x() - 20,
- capture_bounds_center_point.y() - 20},
- /*by_touch_gestures=*/true);
- EXPECT_EQ(CameraPreviewSnapPosition::kTopLeft,
- camera_controller->camera_preview_snap_position());
- VerifyPreviewAlignment(GetCaptureBoundsInScreen());
- // Start video recording, verify camera preview is snapped to the correct
- // snap position at the end of drag when there's a video recording in
- // progress.
- StartVideoRecordingImmediately();
- EXPECT_FALSE(CaptureModeController::Get()->IsActive());
- // Drag and drop camera preview by mouse to the bottom left of the center
- // point, verify that camera preview is snapped to the bottom left with
- // correct position.
- DragPreviewToPoint(preview_widget, {capture_bounds_center_point.x() - 20,
- capture_bounds_center_point.y() + 20});
- EXPECT_EQ(CameraPreviewSnapPosition::kBottomLeft,
- camera_controller->camera_preview_snap_position());
- VerifyPreviewAlignment(GetCaptureBoundsInScreen());
- // Now drag and drop camera preview by touch to the bottom right of the
- // center point, verify that camera preview is snapped to the bottom right
- // with correct position.
- DragPreviewToPoint(preview_widget,
- {capture_bounds_center_point.x() + 20,
- capture_bounds_center_point.y() + 20},
- /*by_touch_gestures=*/true);
- EXPECT_EQ(CameraPreviewSnapPosition::kBottomRight,
- camera_controller->camera_preview_snap_position());
- VerifyPreviewAlignment(GetCaptureBoundsInScreen());
- }
- // Tests the use case after pressing on the resize button on camera preview and
- // releasing the press outside of camera preview, camera preview is still
- // draggable. Regression test for https://crbug.com/1308885.
- TEST_P(CaptureModeCameraPreviewTest,
- CameraPreviewDragToSnapAfterPressOnResizeButton) {
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* preview_widget = camera_controller->camera_preview_widget();
- auto* resize_button = GetPreviewResizeButton();
- const int camera_previw_width =
- preview_widget->GetWindowBoundsInScreen().width();
- const gfx::Point capture_bounds_center_point =
- GetCaptureBoundsInScreen().CenterPoint();
- const gfx::Point center_point_of_resize_button =
- resize_button->GetBoundsInScreen().CenterPoint();
- // By default the snap position of preview widget should be `kBottomRight`.
- EXPECT_EQ(CameraPreviewSnapPosition::kBottomRight,
- camera_controller->camera_preview_snap_position());
- auto* event_generator = GetEventGenerator();
- event_generator->set_current_screen_location(center_point_of_resize_button);
- event_generator->PressLeftButton();
- const gfx::Vector2d delta(-camera_previw_width, -camera_previw_width);
- // Now move mouse to the outside of the camera preview and then release.
- event_generator->MoveMouseTo(center_point_of_resize_button + delta);
- event_generator->ReleaseLeftButton();
- // Now try to drag the camera preview to the top left, after camera preview is
- // snapped, the current snap position should be `kTopLeft`.
- DragPreviewToPoint(preview_widget, capture_bounds_center_point + delta);
- EXPECT_EQ(CameraPreviewSnapPosition::kTopLeft,
- camera_controller->camera_preview_snap_position());
- }
- TEST_P(CaptureModeCameraPreviewTest, CaptureUisVisibilityChangeOnDragAndDrop) {
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- auto* capture_session = CaptureModeController::Get()->capture_mode_session();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* preview_widget = camera_controller->camera_preview_widget();
- const gfx::Point center_point_of_preview_widget =
- preview_widget->GetWindowBoundsInScreen().CenterPoint();
- const auto* capture_bar_widget = capture_session->capture_mode_bar_widget();
- const auto* capture_label_widget = capture_session->capture_label_widget();
- // Press on top of the preview widget. Verify capture bar and capture label
- // are hidden.
- auto* event_generator = GetEventGenerator();
- event_generator->set_current_screen_location(center_point_of_preview_widget);
- event_generator->PressLeftButton();
- EXPECT_FALSE(capture_bar_widget->IsVisible());
- EXPECT_FALSE(capture_label_widget->IsVisible());
- // Now drag and move the preview widget. Verify capture bar and capture
- // label are still hidden.
- const gfx::Vector2d delta(-50, -60);
- event_generator->MoveMouseTo(center_point_of_preview_widget + delta);
- EXPECT_FALSE(capture_bar_widget->IsVisible());
- EXPECT_FALSE(capture_label_widget->IsVisible());
- // Release the drag. Verify capture bar and capture label are shown again.
- event_generator->ReleaseLeftButton();
- EXPECT_TRUE(capture_bar_widget->IsVisible());
- EXPECT_TRUE(capture_label_widget->IsVisible());
- }
- TEST_P(CaptureModeCameraPreviewTest, CameraPreviewDragToSnapOnMultipleDisplay) {
- UpdateDisplay("800x700,801+0-800x700");
- const gfx::Point point_in_second_display = gfx::Point(1000, 500);
- auto* event_generator = GetEventGenerator();
- MoveMouseToAndUpdateCursorDisplay(point_in_second_display, event_generator);
- // Start capture mode on the second display.
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* preview_widget = camera_controller->camera_preview_widget();
- const gfx::Point capture_bounds_center_point =
- GetCaptureBoundsInScreen().CenterPoint();
- // Drag and drop camera preview by mouse to the top right of the
- // `capture_bounds_center_point`, verify that camera preview is snapped to
- // the top right with correct position.
- DragPreviewToPoint(preview_widget, {capture_bounds_center_point.x() + 20,
- capture_bounds_center_point.y() - 20});
- EXPECT_EQ(CameraPreviewSnapPosition::kTopRight,
- camera_controller->camera_preview_snap_position());
- VerifyPreviewAlignment(GetCaptureBoundsInScreen());
- }
- // Tests that when there's a video recording is in progress, start a new
- // capture session will make camera preview not draggable.
- TEST_P(CaptureModeCameraPreviewTest,
- DragPreviewInNewCaptureSessionWhileVideoRecordingInProgress) {
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* preview_widget = camera_controller->camera_preview_widget();
- const gfx::Point capture_bounds_center_point =
- GetCaptureBoundsInScreen().CenterPoint();
- StartVideoRecordingImmediately();
- EXPECT_FALSE(CaptureModeController::Get()->IsActive());
- // Start a new capture session while a video recording is in progress.
- auto* controller = CaptureModeController::Get();
- controller->Start(CaptureModeEntryType::kQuickSettings);
- const gfx::Rect preview_bounds_in_screen_before_drag =
- preview_widget->GetWindowBoundsInScreen();
- const auto snap_position_before_drag =
- camera_controller->camera_preview_snap_position();
- // Verify by default snap position is `kBottomRight`.
- EXPECT_EQ(snap_position_before_drag, CameraPreviewSnapPosition::kBottomRight);
- // Try to drag camera preview by mouse without dropping it, verify camera
- // preview is not draggable and its position is not changed.
- DragPreviewToPoint(preview_widget,
- {preview_bounds_in_screen_before_drag.x() + 20,
- preview_bounds_in_screen_before_drag.y() + 20},
- /*by_touch_gestures=*/false,
- /*drop=*/false);
- EXPECT_EQ(preview_widget->GetWindowBoundsInScreen(),
- preview_bounds_in_screen_before_drag);
- // Try to drag and drop camera preview by touch to the top left of the
- // current capture bounds' center point, verity it's not moved. Also verify
- // the snap position is not updated.
- DragPreviewToPoint(preview_widget,
- {capture_bounds_center_point.x() - 20,
- capture_bounds_center_point.y() - 20},
- /*by_touch_gestures=*/true);
- EXPECT_EQ(preview_widget->GetWindowBoundsInScreen(),
- preview_bounds_in_screen_before_drag);
- EXPECT_EQ(camera_controller->camera_preview_snap_position(),
- snap_position_before_drag);
- }
- // Tests that dragging camera preview outside of the preview circle shouldn't
- // work even if the drag events are contained in the preview bounds.
- TEST_P(CaptureModeCameraPreviewTest, DragPreviewOutsidePreviewCircle) {
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* preview_widget = camera_controller->camera_preview_widget();
- const gfx::Point capture_bounds_center_point =
- GetCaptureBoundsInScreen().CenterPoint();
- const gfx::Rect preview_bounds_in_screen_before_drag =
- preview_widget->GetWindowBoundsInScreen();
- // Try to drag camera preview at its origin point, verify camera
- // preview is not draggable and its position is not changed.
- auto* event_generator = GetEventGenerator();
- event_generator->MoveMouseTo(preview_bounds_in_screen_before_drag.origin());
- event_generator->PressLeftButton();
- event_generator->MoveMouseTo(capture_bounds_center_point);
- EXPECT_EQ(preview_widget->GetWindowBoundsInScreen(),
- preview_bounds_in_screen_before_drag);
- }
- // Tests that dragging camera preview outside of the preview circle doesn't
- // work when video recording is in progress.
- TEST_P(CaptureModeCameraPreviewTest,
- DragPreviewOutsidePreviewCircleWhileVideoRecordingInProgress) {
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* preview_widget = camera_controller->camera_preview_widget();
- const gfx::Point capture_bounds_center_point =
- GetCaptureBoundsInScreen().CenterPoint();
- const gfx::Rect preview_bounds_in_screen_before_drag =
- preview_widget->GetWindowBoundsInScreen();
- const auto snap_position_before_drag =
- camera_controller->camera_preview_snap_position();
- // Verify by default snap position is `kBottomRight`.
- EXPECT_EQ(snap_position_before_drag, CameraPreviewSnapPosition::kBottomRight);
- // Try to drag camera preview at its origin point to the top left of current
- // capture bounds' center point, verity it's not moved.
- auto* event_generator = GetEventGenerator();
- event_generator->MoveMouseTo(preview_bounds_in_screen_before_drag.origin());
- event_generator->PressLeftButton();
- event_generator->MoveMouseTo(capture_bounds_center_point);
- EXPECT_EQ(preview_widget->GetWindowBoundsInScreen(),
- preview_bounds_in_screen_before_drag);
- // Release drag, verify snap position is not changed.
- event_generator->ReleaseLeftButton();
- EXPECT_EQ(camera_controller->camera_preview_snap_position(),
- snap_position_before_drag);
- }
- // Tests that when mouse event is on top of camera preview circle, cursor type
- // should be updated accordingly.
- TEST_P(CaptureModeCameraPreviewTest, CursorTypeUpdates) {
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* preview_widget = camera_controller->camera_preview_widget();
- const gfx::Rect preview_bounds_in_screen =
- preview_widget->GetWindowBoundsInScreen();
- const gfx::Point camera_preview_center_point =
- preview_bounds_in_screen.CenterPoint();
- const gfx::Point camera_preview_origin_point =
- preview_bounds_in_screen.origin();
- auto* event_generator = GetEventGenerator();
- auto* cursor_manager = Shell::Get()->cursor_manager();
- // Verify that moving mouse to the origin point on camera preview won't
- // update the cursor type to `kPointer`.
- event_generator->MoveMouseTo(preview_bounds_in_screen.origin());
- EXPECT_NE(cursor_manager->GetCursor(), ui::mojom::CursorType::kPointer);
- // Verify that moving mouse on camera preview will update the cursor type
- // to `kPointer`.
- event_generator->MoveMouseTo(camera_preview_center_point);
- EXPECT_EQ(cursor_manager->GetCursor(), ui::mojom::CursorType::kPointer);
- // Move mouse from camera preview to capture surface, verify cursor type is
- // updated to the correct type of the current capture source.
- event_generator->MoveMouseTo({camera_preview_origin_point.x() - 10,
- camera_preview_origin_point.y() - 10});
- EXPECT_EQ(cursor_manager->GetCursor(), GetCursorTypeOnCaptureSurface());
- // Drag camera preview, verify that cursor type is updated to `kPointer`.
- DragPreviewToPoint(preview_widget,
- {camera_preview_center_point.x() - 10,
- camera_preview_center_point.y() - 10},
- /*by_touch_gestures=*/false,
- /*drop=*/false);
- EXPECT_EQ(cursor_manager->GetCursor(), ui::mojom::CursorType::kPointer);
- // Continue dragging and then drop camera preview, make sure cursor's
- // position is outside of camera preview after it's snapped. Verify cursor
- // type is updated to the correct type of the current capture source.
- DragPreviewToPoint(preview_widget, {camera_preview_origin_point.x() - 20,
- camera_preview_origin_point.y() - 20});
- EXPECT_EQ(cursor_manager->GetCursor(), GetCursorTypeOnCaptureSurface());
- }
- // Tests the functionality of resize button on changing the size of the camera
- // preview widget, updating the icon image and tooltip text after clicking on
- // it. It also tests the ability to restore to previous resize button settings
- // if any when initiating a new capture mode session.
- TEST_P(CaptureModeCameraPreviewTest, ResizePreviewWidget) {
- UpdateDisplay("800x700");
- StartCaptureSessionWithParam();
- auto* controller = CaptureModeController::Get();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- views::Widget* preview_widget = camera_controller->camera_preview_widget();
- DCHECK(preview_widget);
- const auto default_preview_bounds = preview_widget->GetWindowBoundsInScreen();
- EXPECT_EQ(default_preview_bounds.size(),
- GetExpectedPreviewSize(/*collapsed=*/false));
- auto* resize_button = GetPreviewResizeButton();
- auto* event_generator = GetEventGenerator();
- // Tests the default settings of the resize button.
- VerifyResizeButton(camera_controller->is_camera_preview_collapsed(),
- resize_button);
- // First time click on resize button will make the preview widget collapse
- // to half of the default size with tooltip text and resize button icon
- // changed to expanded related contents accordingly.
- ClickOnView(resize_button, event_generator);
- EXPECT_EQ(preview_widget->GetWindowBoundsInScreen().size(),
- GetExpectedPreviewSize(/*collapsed=*/true));
- VerifyResizeButton(camera_controller->is_camera_preview_collapsed(),
- resize_button);
- // Second time click on resize button will make the preview widget expand
- // back to the default size with tooltip text and resize button icon changed
- // to the collapsed related contents accordingly.
- ClickOnView(resize_button, event_generator);
- EXPECT_EQ(preview_widget->GetWindowBoundsInScreen(), default_preview_bounds);
- VerifyResizeButton(camera_controller->is_camera_preview_collapsed(),
- resize_button);
- // Click on the resize button again will collapse the preview widget. Exit the
- // session and start a new session, the settings for preview widget bounds and
- // resize button will be restored.
- ClickOnView(resize_button, event_generator);
- EXPECT_EQ(preview_widget->GetWindowBoundsInScreen().size(),
- GetExpectedPreviewSize(/*collapsed=*/true));
- VerifyResizeButton(camera_controller->is_camera_preview_collapsed(),
- resize_button);
- const auto collapsed_preview_bounds =
- preview_widget->GetWindowBoundsInScreen();
- controller->Stop();
- StartCaptureSessionWithParam();
- preview_widget = camera_controller->camera_preview_widget();
- EXPECT_TRUE(preview_widget);
- EXPECT_EQ(preview_widget->GetWindowBoundsInScreen(),
- collapsed_preview_bounds);
- resize_button = GetPreviewResizeButton();
- EXPECT_TRUE(resize_button);
- VerifyResizeButton(camera_controller->is_camera_preview_collapsed(),
- resize_button);
- }
- // Tests that resizing the camera preview using the resize button, which uses
- // the bounds animation, works correctly on a secondary display. Regression test
- // for https://crbug.com/1313247.
- TEST_P(CaptureModeCameraPreviewTest, MultiDisplayResize) {
- UpdateDisplay("800x700,801+0-800x700");
- ASSERT_EQ(2u, Shell::GetAllRootWindows().size());
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- // Put the cursor in the secondary display, and expect the session root to be
- // there.
- auto* event_generator = GetEventGenerator();
- MoveMouseToAndUpdateCursorDisplay(gfx::Point(900, 500), event_generator);
- StartCaptureSessionWithParam();
- auto* controller = CaptureModeController::Get();
- auto* session = controller->capture_mode_session();
- auto* display_2_root = Shell::GetAllRootWindows()[1];
- // When capturing a window, set its bounds such that it is placed on the
- // secondary display.
- if (GetParam() == CaptureModeSource::kWindow) {
- views::Widget::GetWidgetForNativeWindow(window())->SetBounds(
- {900, 10, 700, 650});
- EXPECT_EQ(display_2_root, window()->GetRootWindow());
- event_generator->MoveMouseToCenterOf(window());
- }
- EXPECT_EQ(display_2_root, session->current_root());
- VerifyPreviewAlignment(GetCaptureBoundsInScreen());
- auto* resize_button = GetPreviewResizeButton();
- ClickOnView(resize_button, event_generator);
- VerifyPreviewAlignment(GetCaptureBoundsInScreen());
- }
- // Tests the visibility of the resize button on mouse events.
- TEST_P(CaptureModeCameraPreviewTest, ResizeButtonVisibilityOnMouseEvents) {
- UpdateDisplay("1366x768");
- StartCaptureSessionWithParam();
- CaptureModeCameraController* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- views::Widget* preview_widget = camera_controller->camera_preview_widget();
- DCHECK(preview_widget);
- const gfx::Rect default_preview_bounds =
- preview_widget->GetWindowBoundsInScreen();
- CaptureModeButton* resize_button = GetPreviewResizeButton();
- auto* event_generator = GetEventGenerator();
- // Tests that the resize button is hidden by default.
- EXPECT_FALSE(resize_button->GetVisible());
- // Tests that the resize button will show up when the mouse is entering the
- // bounds of the preview widget.
- event_generator->MoveMouseTo(default_preview_bounds.CenterPoint());
- EXPECT_TRUE(resize_button->GetVisible());
- // Tests that the resize button will stay visible while moving the mouse
- // within the bounds of the preview widget.
- event_generator->MoveMouseTo(default_preview_bounds.top_center());
- EXPECT_TRUE(resize_button->GetVisible());
- // Tests that when the mouse is exiting the bounds of the preview widget, the
- // resize button will disappear after the predefined duration.
- auto outside_point = default_preview_bounds.origin();
- outside_point.Offset(-1, -1);
- event_generator->MoveMouseTo(outside_point);
- base::OneShotTimer* timer = camera_controller->camera_preview_view()
- ->resize_button_hide_timer_for_test();
- EXPECT_TRUE(timer->IsRunning());
- EXPECT_EQ(timer->GetCurrentDelay(), capture_mode::kResizeButtonShowDuration);
- {
- ViewVisibilityChangeWaiter waiter(resize_button);
- EXPECT_TRUE(resize_button->GetVisible());
- timer->FireNow();
- waiter.Wait();
- EXPECT_FALSE(resize_button->GetVisible());
- }
- }
- // Tests the visibility of the resize button on tap events.
- TEST_P(CaptureModeCameraPreviewTest, ResizeButtonVisibilityOnTapEvents) {
- UpdateDisplay("800x700");
- StartCaptureSessionWithParam();
- CaptureModeCameraController* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- views::Widget* preview_widget = camera_controller->camera_preview_widget();
- DCHECK(preview_widget);
- const gfx::Rect default_preview_bounds =
- preview_widget->GetWindowBoundsInScreen();
- CaptureModeButton* resize_button = GetPreviewResizeButton();
- auto* event_generator = GetEventGenerator();
- // Tests that the resize button is hidden by default.
- EXPECT_FALSE(resize_button->GetVisible());
- // Tests that resize button shows up when tapping within the bounds of the
- // preview widget and will fade out after the predefined duration.
- event_generator->GestureTapAt(default_preview_bounds.CenterPoint());
- EXPECT_TRUE(resize_button->GetVisible());
- base::OneShotTimer* timer = camera_controller->camera_preview_view()
- ->resize_button_hide_timer_for_test();
- EXPECT_TRUE(timer->IsRunning());
- EXPECT_EQ(timer->GetCurrentDelay(), capture_mode::kResizeButtonShowDuration);
- {
- ViewVisibilityChangeWaiter waiter(resize_button);
- timer->FireNow();
- waiter.Wait();
- EXPECT_FALSE(resize_button->GetVisible());
- }
- }
- // Tests the visibility of the resize button on camera preview drag to snap.
- TEST_P(CaptureModeCameraPreviewTest,
- ResizeButtonVisibilityOnCameraPreviewDragToSnap) {
- UpdateDisplay("1366x768");
- StartCaptureSessionWithParam();
- CaptureModeCameraController* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- views::Widget* preview_widget = camera_controller->camera_preview_widget();
- const gfx::Rect preview_bounds = preview_widget->GetWindowBoundsInScreen();
- CaptureModeButton* resize_button = GetPreviewResizeButton();
- auto* event_generator = GetEventGenerator();
- // Tests that the resize button is hidden by default.
- EXPECT_FALSE(resize_button->GetVisible());
- // Tests that the resize button will show up when the mouse is entering the
- // bounds of the preview widget.
- event_generator->MoveMouseTo(preview_bounds.CenterPoint());
- EXPECT_TRUE(resize_button->GetVisible());
- // Tests that when start dragging camera preview, resize button will be
- // hidden.
- event_generator->PressLeftButton();
- EXPECT_FALSE(resize_button->GetVisible());
- // Drag camera preview, test that resize button is still hidden.
- event_generator->MoveMouseBy(-300, -300);
- EXPECT_FALSE(resize_button->GetVisible());
- // Now release drag, verify that resize button is still hidden since cursor is
- // not on top of camera preview after it's snapped.
- event_generator->ReleaseLeftButton();
- EXPECT_FALSE(resize_button->GetVisible());
- // Now drag camera preview with a small distance, make sure when it's snapped
- // cursor is still on top of it. Verify that resize button is shown after
- // camera preview is snapped.
- const gfx::Vector2d delta(-30, -30);
- DragPreviewToPoint(preview_widget, preview_bounds.CenterPoint() + delta);
- EXPECT_TRUE(resize_button->GetVisible());
- }
- TEST_P(CaptureModeCameraPreviewTest, CameraPreviewDeintersectsWithSystemTray) {
- UpdateDisplay("1366x768");
- // Open system tray.
- ui::test::EventGenerator* event_generator = GetEventGenerator();
- auto* system_tray = GetPrimaryUnifiedSystemTray();
- event_generator->MoveMouseTo(system_tray->GetBoundsInScreen().CenterPoint());
- event_generator->ClickLeftButton();
- EXPECT_TRUE(system_tray->IsBubbleShown());
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- // Verify current default snap position is the `kBottomRight` before we select
- // a camera device.
- EXPECT_EQ(camera_controller->camera_preview_snap_position(),
- CameraPreviewSnapPosition::kBottomRight);
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* preview_widget = camera_controller->camera_preview_widget();
- EXPECT_TRUE(system_tray->IsBubbleShown());
- // Verify that camera preview doesn't overlap with system tray when it's
- // shown. Also verify current snap position is updated and not `kBottomRight`
- // anymore.
- EXPECT_FALSE(system_tray->GetBubbleBoundsInScreen().Intersects(
- preview_widget->GetWindowBoundsInScreen()));
- EXPECT_NE(camera_controller->camera_preview_snap_position(),
- CameraPreviewSnapPosition::kBottomRight);
- }
- TEST_P(CaptureModeCameraPreviewTest,
- CameraPreviewDeintersectsWithSystemTrayWhileVideoRecordingInProgress) {
- // Update display size big enough to make sure when capture source is
- // `kWindow`, the selected window is not system tray.
- UpdateDisplay("1366x768");
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* preview_widget = camera_controller->camera_preview_widget();
- const gfx::Point capture_bounds_center_point =
- GetCaptureBoundsInScreen().CenterPoint();
- StartVideoRecordingImmediately();
- // Verify current snap position is `kBottomRight`;
- EXPECT_EQ(camera_controller->camera_preview_snap_position(),
- CameraPreviewSnapPosition::kBottomRight);
- // Now open system tray.
- ui::test::EventGenerator* event_generator = GetEventGenerator();
- auto* system_tray = GetPrimaryUnifiedSystemTray();
- event_generator->MoveMouseTo(system_tray->GetBoundsInScreen().CenterPoint());
- event_generator->ClickLeftButton();
- EXPECT_TRUE(system_tray->IsBubbleShown());
- // Verify that after system tray is open, camera preview is snapped and
- // doesn't overlap with system tray.
- EXPECT_NE(camera_controller->camera_preview_snap_position(),
- CameraPreviewSnapPosition::kBottomRight);
- EXPECT_FALSE(system_tray->GetBubbleBoundsInScreen().Intersects(
- preview_widget->GetWindowBoundsInScreen()));
- // Now try to drag camera preview to the bottom right corner, verify that
- // since system tray is still open, when drag is released, camera preview is
- // not snapped to the bottom right corner even it's the nearest corner to the
- // release position if system tray is still shown.
- const gfx::Vector2d delta(20, 20);
- DragPreviewToPoint(preview_widget, capture_bounds_center_point + delta);
- // Please notice, when capture source is `kWindow`, once the drag starts,
- // system tray will be closed, in this use case we just need to verify camera
- // preview is snapped to the bottom right corner.
- if (system_tray->IsBubbleShown()) {
- EXPECT_NE(camera_controller->camera_preview_snap_position(),
- CameraPreviewSnapPosition::kBottomRight);
- EXPECT_FALSE(system_tray->GetBubbleBoundsInScreen().Intersects(
- preview_widget->GetWindowBoundsInScreen()));
- } else {
- EXPECT_EQ(camera_controller->camera_preview_snap_position(),
- CameraPreviewSnapPosition::kBottomRight);
- }
- }
- TEST_P(CaptureModeCameraPreviewTest, CameraPreviewDeintersectsWithPipWindow) {
- // Create a window at the bottom right of the display, then convert it to a
- // PIP window.
- std::unique_ptr<aura::Window> pip_window(
- CreateTestWindow(gfx::Rect(700, 450, 104, 100)));
- ConvertToPipWindow(pip_window.get());
- const gfx::Rect origin_pip_window_bounds = pip_window->GetBoundsInScreen();
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* preview_widget = camera_controller->camera_preview_widget();
- // Verify that after preview widget is enabled, pip window is repositioned to
- // avoid the overlap with camera preview.
- EXPECT_EQ(camera_controller->camera_preview_snap_position(),
- CameraPreviewSnapPosition::kBottomRight);
- const gfx::Rect current_pip_window_bounds = pip_window->GetBoundsInScreen();
- EXPECT_NE(origin_pip_window_bounds, current_pip_window_bounds);
- EXPECT_FALSE(current_pip_window_bounds.Intersects(
- preview_widget->GetWindowBoundsInScreen()));
- }
- TEST_P(CaptureModeCameraPreviewTest,
- CameraPreviewDeintersectsWithPipWindowDuringRecording) {
- // Create a window at the top left of the display, then convert it to a PIP
- // window.
- std::unique_ptr<aura::Window> pip_window(
- CreateTestWindow(gfx::Rect(0, 0, 104, 100)));
- ConvertToPipWindow(pip_window.get());
- const gfx::Rect origin_pip_window_bounds = pip_window->GetBoundsInScreen();
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* preview_widget = camera_controller->camera_preview_widget();
- const gfx::Point capture_bounds_center_point =
- GetCaptureBoundsInScreen().CenterPoint();
- // Verify camera preview is enabled, current snap position is `kBottomRight`
- // and pip window is not repositioned since there's no overlap.
- EXPECT_TRUE(preview_widget);
- EXPECT_EQ(camera_controller->camera_preview_snap_position(),
- CameraPreviewSnapPosition::kBottomRight);
- EXPECT_EQ(origin_pip_window_bounds, pip_window->GetBoundsInScreen());
- StartVideoRecordingImmediately();
- // Now drag camera preview to the top left corner, verify pip window is
- // repositioned to avoid overlap with camera preview.
- const gfx::Vector2d delta(-20, -20);
- DragPreviewToPoint(preview_widget, capture_bounds_center_point + delta);
- EXPECT_EQ(camera_controller->camera_preview_snap_position(),
- CameraPreviewSnapPosition::kTopLeft);
- EXPECT_NE(origin_pip_window_bounds, pip_window->GetBoundsInScreen());
- EXPECT_FALSE(preview_widget->GetWindowBoundsInScreen().Intersects(
- pip_window->GetBoundsInScreen()));
- }
- TEST_P(CaptureModeCameraPreviewTest,
- CameraPreviewDeintersectsWithAutoclickBar) {
- // Update display size big enough to make sure when capture source is
- // `kWindow`, the selected window is not system tray.
- UpdateDisplay("1366x768");
- // Enable autoclick bar.
- auto* autoclick_controller = Shell::Get()->autoclick_controller();
- autoclick_controller->SetEnabled(true, /*show_confirmation_dialog=*/false);
- Shell::Get()
- ->accessibility_controller()
- ->GetFeature(AccessibilityControllerImpl::FeatureType::kAutoclick)
- .SetEnabled(true);
- views::Widget* autoclick_bubble_widget =
- autoclick_controller->GetMenuBubbleControllerForTesting()
- ->GetBubbleWidgetForTesting();
- EXPECT_TRUE(autoclick_bubble_widget->IsVisible());
- const gfx::Rect origin_autoclick_bar_bounds =
- autoclick_bubble_widget->GetWindowBoundsInScreen();
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* preview_widget = camera_controller->camera_preview_widget();
- // Verify that after preview widget is enabled, autoclick bar is repositioned
- // to avoid the overlap with camera preview.
- EXPECT_EQ(camera_controller->camera_preview_snap_position(),
- CameraPreviewSnapPosition::kBottomRight);
- const gfx::Rect current_autoclick_bar_bounds =
- autoclick_bubble_widget->GetWindowBoundsInScreen();
- EXPECT_NE(origin_autoclick_bar_bounds, current_autoclick_bar_bounds);
- EXPECT_FALSE(current_autoclick_bar_bounds.Intersects(
- preview_widget->GetWindowBoundsInScreen()));
- }
- TEST_P(CaptureModeCameraPreviewTest,
- CameraPreviewDeintersectsWithSystemTrayOnSizeChanged) {
- // Update display size to make sure when system tray is open, camera preview
- // can stay in the same side with it when camera preview is collapsed,
- // otherwise, camera preview should be snapped to the other side of the
- // display.
- UpdateDisplay("1366x700");
- StartCaptureSessionWithParam();
- auto* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* preview_widget = camera_controller->camera_preview_widget();
- // Verify camera preview is enabled, and by default, the current snap position
- // should be `kBottomRight`.
- EXPECT_TRUE(preview_widget);
- EXPECT_EQ(camera_controller->camera_preview_snap_position(),
- CameraPreviewSnapPosition::kBottomRight);
- // Click on resize button to collapse camera preview.
- auto* resize_button = GetPreviewResizeButton();
- auto* event_generator = GetEventGenerator();
- ClickOnView(resize_button, event_generator);
- EXPECT_TRUE(camera_controller->is_camera_preview_collapsed());
- StartVideoRecordingImmediately();
- // Open system tray.
- auto* system_tray = GetPrimaryUnifiedSystemTray();
- event_generator->MoveMouseTo(system_tray->GetBoundsInScreen().CenterPoint());
- event_generator->ClickLeftButton();
- EXPECT_TRUE(system_tray->IsBubbleShown());
- // After system tray is shown, verify that camera preview is snapped to the
- // top right corner, and there's no overlap between camera preview and system
- // tray.
- EXPECT_TRUE(system_tray->IsBubbleShown());
- EXPECT_EQ(camera_controller->camera_preview_snap_position(),
- CameraPreviewSnapPosition::kTopRight);
- EXPECT_FALSE(preview_widget->GetWindowBoundsInScreen().Intersects(
- system_tray->GetBoundsInScreen()));
- // Click on the resize button to enlarge camera preview. Verify that camera
- // preview remains snapped to the top right corner, since there's no overlap.
- ClickOnView(resize_button, event_generator);
- EXPECT_FALSE(preview_widget->GetWindowBoundsInScreen().Intersects(
- system_tray->GetBoundsInScreen()));
- EXPECT_EQ(camera_controller->camera_preview_snap_position(),
- CameraPreviewSnapPosition::kTopRight);
- }
- TEST_P(CaptureModeCameraPreviewTest, CameraPreviewSpecs) {
- AddDefaultCamera();
- CaptureModeTestApi().SelectCameraAtIndex(0);
- auto* camera_controller = GetCameraController();
- struct {
- CameraPreviewState preview_state;
- std::string scope_trace;
- } kTestCases[] = {
- {CameraPreviewState::kCollapsible, "Collapsible Preview"},
- {CameraPreviewState::kNotCollapsible, "Not Collapsible Preview"},
- {CameraPreviewState::kHidden, "Hidden Preview"},
- };
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(test_case.scope_trace);
- UpdateDisplay("1366x700");
- StartCaptureSessionWithParam();
- auto* camera_preview_widget = camera_controller->camera_preview_widget();
- auto* camera_preview_view = camera_controller->camera_preview_view();
- EXPECT_TRUE(camera_preview_widget);
- EXPECT_TRUE(camera_preview_widget->IsVisible());
- EXPECT_TRUE(camera_preview_view->is_collapsible());
- ResizeSurfaceSoCameraPreviewBecomes(test_case.preview_state);
- const auto preview_screen_bounds =
- camera_preview_widget->GetWindowBoundsInScreen();
- switch (test_case.preview_state) {
- case CameraPreviewState::kCollapsible:
- EXPECT_TRUE(camera_preview_widget->IsVisible());
- EXPECT_TRUE(camera_preview_view->is_collapsible());
- EXPECT_EQ(preview_screen_bounds.size(),
- GetExpectedPreviewSize(/*collapsed=*/false));
- break;
- case CameraPreviewState::kNotCollapsible:
- EXPECT_TRUE(camera_preview_widget->IsVisible());
- EXPECT_FALSE(camera_preview_view->is_collapsible());
- EXPECT_EQ(preview_screen_bounds.size(),
- GetExpectedPreviewSize(/*collapsed=*/false));
- break;
- case CameraPreviewState::kHidden:
- EXPECT_FALSE(camera_preview_widget->IsVisible());
- EXPECT_FALSE(camera_preview_view->is_collapsible());
- break;
- }
- }
- }
- // Tests that the resize button will stay visible after mouse exiting the
- // preview and time exceeding the predefined duration on mouse event when switch
- // access is enabled. And the resize button will behave in a default way if
- // switch access is not enabled.
- TEST_P(CaptureModeCameraPreviewTest,
- ResizeButtonSwitchAccessVisibilityTestOnMouseEvent) {
- UpdateDisplay("1366x768");
- CaptureModeCameraController* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* event_generator = GetEventGenerator();
- for (const bool switch_access_enabled : {false, true}) {
- AccessibilityControllerImpl* a11y_controller =
- Shell::Get()->accessibility_controller();
- a11y_controller->switch_access().SetEnabled(switch_access_enabled);
- EXPECT_EQ(switch_access_enabled, a11y_controller->IsSwitchAccessRunning());
- StartCaptureSessionWithParam();
- views::Widget* preview_widget = camera_controller->camera_preview_widget();
- DCHECK(preview_widget);
- gfx::Rect preview_bounds = preview_widget->GetWindowBoundsInScreen();
- CaptureModeButton* resize_button = GetPreviewResizeButton();
- // Tests the default visibility of the resize button based on whether switch
- // access is enabled or not.
- EXPECT_EQ(resize_button->GetVisible(),
- switch_access_enabled ? true : false);
- event_generator->MoveMouseTo(preview_bounds.CenterPoint());
- EXPECT_TRUE(resize_button->GetVisible());
- auto outside_point = preview_bounds.origin();
- outside_point.Offset(-1, -1);
- event_generator->MoveMouseTo(outside_point);
- base::OneShotTimer* timer = camera_controller->camera_preview_view()
- ->resize_button_hide_timer_for_test();
- timer->FireNow();
- EXPECT_EQ(resize_button->GetVisible(),
- switch_access_enabled ? true : false);
- // Tests that the resize button will be hidden when start dragging the
- // camera preview regardless of whether the switch access is enabled or not.
- event_generator->MoveMouseTo(preview_bounds.CenterPoint());
- EXPECT_TRUE(resize_button->GetVisible());
- event_generator->PressLeftButton();
- EXPECT_FALSE(resize_button->GetVisible());
- event_generator->MoveMouseBy(-100, -100);
- EXPECT_FALSE(resize_button->GetVisible());
- // Tests that the resize button will be visible if the switch access is
- // enabled after releasing the drag and not visible otherwise.
- event_generator->ReleaseLeftButton();
- EXPECT_EQ(resize_button->GetVisible(),
- switch_access_enabled ? true : false);
- CaptureModeController::Get()->Stop();
- }
- }
- // Tests that the resize button will stay visible after tapping on the preview
- // and time exceeding the predefined duration on tap event when switch access is
- // enabled. And the resize button will behave in a default way if switch
- // access is not enabled.
- TEST_P(CaptureModeCameraPreviewTest,
- ResizeButtonSwitchAccessVisibilityTestOnTapEvent) {
- UpdateDisplay("1366x768");
- SwitchToTabletMode();
- EXPECT_TRUE(Shell::Get()->IsInTabletMode());
- CaptureModeCameraController* camera_controller = GetCameraController();
- AddDefaultCamera();
- camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
- auto* event_generator = GetEventGenerator();
- for (const bool switch_access_enabled : {false, true}) {
- AccessibilityControllerImpl* a11y_controller =
- Shell::Get()->accessibility_controller();
- a11y_controller->switch_access().SetEnabled(switch_access_enabled);
- EXPECT_EQ(switch_access_enabled, a11y_controller->IsSwitchAccessRunning());
- StartCaptureSessionWithParam();
- views::Widget* preview_widget = camera_controller->camera_preview_widget();
- DCHECK(preview_widget);
- gfx::Rect preview_bounds = preview_widget->GetWindowBoundsInScreen();
- CaptureModeButton* resize_button = GetPreviewResizeButton();
- // Tests the default visibility of the resize button based on whether switch
- // access is enabled or not.
- EXPECT_EQ(resize_button->GetVisible(),
- switch_access_enabled ? true : false);
- event_generator->GestureTapAt(preview_bounds.CenterPoint());
- EXPECT_TRUE(resize_button->GetVisible());
- base::OneShotTimer* timer = camera_controller->camera_preview_view()
- ->resize_button_hide_timer_for_test();
- if (timer->IsRunning())
- timer->FireNow();
- EXPECT_EQ(resize_button->GetVisible(),
- switch_access_enabled ? true : false);
- CaptureModeController::Get()->Stop();
- }
- }
- INSTANTIATE_TEST_SUITE_P(All,
- CaptureModeCameraPreviewTest,
- testing::Values(CaptureModeSource::kFullscreen,
- CaptureModeSource::kRegion,
- CaptureModeSource::kWindow));
- class ProjectorCaptureModeCameraTest : public CaptureModeCameraTest {
- public:
- ProjectorCaptureModeCameraTest() = default;
- ~ProjectorCaptureModeCameraTest() override = default;
- // CaptureModeCameraTest:
- void SetUp() override {
- CaptureModeCameraTest::SetUp();
- projector_helper_.SetUp();
- }
- void StartProjectorModeSession() {
- projector_helper_.StartProjectorModeSession();
- }
- private:
- ProjectorCaptureModeIntegrationHelper projector_helper_;
- };
- TEST_F(ProjectorCaptureModeCameraTest, NoAvailableCameras) {
- // Initially no camera should be selected.
- auto* camera_controller = GetCameraController();
- EXPECT_FALSE(camera_controller->selected_camera().is_valid());
- // Starting a projector session should not result in showing any cameras, or
- // any crashes.
- StartProjectorModeSession();
- EXPECT_FALSE(camera_controller->selected_camera().is_valid());
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- }
- TEST_F(ProjectorCaptureModeCameraTest, FirstCamSelectedByDefault) {
- AddDefaultCamera();
- // Initially no camera should be selected.
- auto* camera_controller = GetCameraController();
- EXPECT_FALSE(camera_controller->selected_camera().is_valid());
- // Starting a projector session should result in selecting the first available
- // camera by default, and its preview should be visible.
- StartProjectorModeSession();
- EXPECT_TRUE(camera_controller->selected_camera().is_valid());
- EXPECT_TRUE(camera_controller->camera_preview_widget());
- }
- TEST_F(ProjectorCaptureModeCameraTest,
- SessionStartsWithAnAlreadySelectedCamera) {
- const std::string model_id_1 = "model1";
- const std::string model_id_2 = "model2";
- AddFakeCamera("/dev/video0", "fake cam 1", model_id_1);
- AddFakeCamera("/dev/video1", "fake cam 2", model_id_2);
- // Initially there's a camera already selected before we start the session,
- // and it's the second camera in the list.
- auto* camera_controller = GetCameraController();
- CameraId cam_id_1(model_id_1, 1);
- CameraId cam_id_2(model_id_2, 1);
- EXPECT_EQ(cam_id_1, camera_controller->available_cameras()[0].camera_id);
- EXPECT_EQ(cam_id_2, camera_controller->available_cameras()[1].camera_id);
- camera_controller->SetSelectedCamera(cam_id_2);
- EXPECT_TRUE(camera_controller->selected_camera().is_valid());
- // Starting a projector session should not result in selecting the first
- // camera. The already selected camera should remain as is.
- StartProjectorModeSession();
- EXPECT_TRUE(camera_controller->selected_camera().is_valid());
- EXPECT_EQ(cam_id_2, camera_controller->selected_camera());
- EXPECT_TRUE(camera_controller->camera_preview_widget());
- }
- // Tests that the recording starts with camera metrics are recorded correctly in
- // a projector-initiated recording.
- TEST_F(ProjectorCaptureModeCameraTest,
- ProjectorRecordingStartsWithCameraHistogramTest) {
- base::HistogramTester histogram_tester;
- constexpr char kHistogramNameBase[] =
- "Ash.CaptureModeController.Projector.RecordingStartsWithCamera";
- AddDefaultCamera();
- struct {
- bool tablet_enabled;
- bool camera_on;
- } kTestCases[] = {
- {false, false},
- {false, true},
- {true, false},
- {true, true},
- };
- for (const auto test_case : kTestCases) {
- if (test_case.tablet_enabled) {
- SwitchToTabletMode();
- EXPECT_TRUE(Shell::Get()->IsInTabletMode());
- } else {
- EXPECT_FALSE(Shell::Get()->IsInTabletMode());
- }
- histogram_tester.ExpectBucketCount(
- GetCaptureModeHistogramName(kHistogramNameBase), test_case.camera_on,
- 0);
- auto* controller = CaptureModeController::Get();
- controller->SetType(CaptureModeType::kVideo);
- controller->SetSource(CaptureModeSource::kFullscreen);
- StartProjectorModeSession();
- EXPECT_TRUE(controller->IsActive());
- auto* session = controller->capture_mode_session();
- EXPECT_TRUE(session->is_in_projector_mode());
- GetCameraController()->SetSelectedCamera(
- test_case.camera_on ? CameraId(kDefaultCameraModelId, 1) : CameraId());
- StartVideoRecordingImmediately();
- EXPECT_TRUE(controller->is_recording_in_progress());
- WaitForSeconds(1);
- controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
- WaitForCaptureFileToBeSaved();
- histogram_tester.ExpectBucketCount(
- GetCaptureModeHistogramName(kHistogramNameBase), test_case.camera_on,
- 1);
- }
- }
- // A test fixture for testing the rendered video frames. The boolean parameter
- // determines the type of the buffer that backs the video frames. `true` means
- // the `kGpuMemoryBuffer` is used, `false` means the `kSharedMemory` buffer type
- // is used.
- class CaptureModeCameraFramesTest : public CaptureModeCameraTest,
- public testing::WithParamInterface<bool> {
- public:
- CaptureModeCameraFramesTest() {
- // Ensure pixels get drawn since they are verified by tests.
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- ::switches::kEnablePixelOutputInTests);
- }
- CaptureModeCameraFramesTest(const CaptureModeCameraFramesTest&) = delete;
- CaptureModeCameraFramesTest& operator=(const CaptureModeCameraFramesTest&) =
- delete;
- ~CaptureModeCameraFramesTest() override = default;
- bool ShouldUseGpuMemoryBuffers() const { return GetParam(); }
- // CaptureModeCameraFramesTest:
- void SetUp() override {
- CaptureModeCameraTest::SetUp();
- CaptureModeTestApi test_api;
- test_api.SetForceUseGpuMemoryBufferForCameraFrames(
- ShouldUseGpuMemoryBuffers());
- AddDefaultCamera();
- ASSERT_EQ(1u, test_api.GetNumberOfAvailableCameras());
- test_api.SelectCameraAtIndex(0);
- const CameraId camera_id(kDefaultCameraModelId, 1);
- EXPECT_EQ(camera_id, GetCameraController()->selected_camera());
- }
- void TearDown() override {
- CaptureModeTestApi().SetForceUseGpuMemoryBufferForCameraFrames(false);
- CaptureModeCameraTest::TearDown();
- }
- };
- namespace {
- // Waits for several rendered frames and verifies that the content of the
- // received video frames are the same as that of the produced video frames.
- void WaitForAndVerifyRenderedVideoFrame() {
- // Render a number of frames that are 3 times the size of the buffer pool.
- // This allows us to exercise calls to `OnNewBuffer()` and potentially
- // `OnFrameDropped()`.
- for (size_t i = 0; i < 3 * FakeCameraDevice::kMaxBufferCount; ++i) {
- base::RunLoop loop;
- CaptureModeTestApi().SetOnCameraVideoFrameRendered(
- base::BindLambdaForTesting([&loop](
- scoped_refptr<media::VideoFrame> frame) {
- ASSERT_TRUE(frame);
- const gfx::Size frame_size = frame->visible_rect().size();
- const auto produced_frame_bitmap =
- FakeCameraDevice::GetProducedFrameAsBitmap(frame_size);
- media::PaintCanvasVideoRenderer renderer;
- SkBitmap received_frame_bitmap;
- scoped_refptr<viz::RasterContextProvider> raster_context_provider =
- aura::Env::GetInstance()
- ->context_factory()
- ->SharedMainThreadRasterContextProvider();
- received_frame_bitmap.allocN32Pixels(frame_size.width(),
- frame_size.height());
- cc::SkiaPaintCanvas canvas(received_frame_bitmap);
- renderer.Copy(frame, &canvas, raster_context_provider.get());
- EXPECT_TRUE(gfx::test::AreBitmapsEqual(produced_frame_bitmap,
- received_frame_bitmap));
- loop.Quit();
- }));
- loop.Run();
- }
- }
- } // namespace
- TEST_P(CaptureModeCameraFramesTest, VerifyFrames) {
- CaptureModeTestApi().StartForFullscreen(/*for_video=*/true);
- EXPECT_TRUE(GetCameraController()->camera_preview_widget());
- WaitForAndVerifyRenderedVideoFrame();
- }
- TEST_P(CaptureModeCameraFramesTest, TurnOffCameraWhileRendering) {
- CaptureModeTestApi test_api;
- test_api.StartForFullscreen(/*for_video=*/true);
- auto* camera_controller = GetCameraController();
- EXPECT_TRUE(camera_controller->camera_preview_widget());
- WaitForAndVerifyRenderedVideoFrame();
- test_api.TurnCameraOff();
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- }
- TEST_P(CaptureModeCameraFramesTest, DisconnectCameraWhileRendering) {
- CaptureModeTestApi test_api;
- test_api.StartForFullscreen(/*for_video=*/true);
- auto* camera_controller = GetCameraController();
- EXPECT_TRUE(camera_controller->camera_preview_widget());
- WaitForAndVerifyRenderedVideoFrame();
- RemoveDefaultCamera();
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- }
- TEST_P(CaptureModeCameraFramesTest, SelectAnotherCameraWhileRendering) {
- CaptureModeTestApi test_api;
- test_api.StartForFullscreen(/*for_video=*/true);
- auto* camera_controller = GetCameraController();
- EXPECT_TRUE(camera_controller->camera_preview_widget());
- auto* preview_view = camera_controller->camera_preview_view();
- ASSERT_TRUE(preview_view);
- EXPECT_EQ(preview_view->camera_id(), camera_controller->selected_camera());
- WaitForAndVerifyRenderedVideoFrame();
- // Adding a new camera while rendering an existing one should not affect
- // anything since the new one is not selected yet.
- const std::string device_id = "/dev/video0";
- const std::string display_name = "Integrated Webcam";
- const std::string model_id = "0123:4567";
- AddFakeCamera(device_id, display_name, model_id);
- EXPECT_EQ(preview_view, camera_controller->camera_preview_view());
- // Now select the new camera, a new widget should be created immediately for
- // the new camera.
- const CameraId second_camera_id(model_id, 1);
- camera_controller->SetSelectedCamera(second_camera_id);
- EXPECT_TRUE(camera_controller->camera_preview_widget());
- EXPECT_NE(preview_view, camera_controller->camera_preview_view());
- preview_view = camera_controller->camera_preview_view();
- EXPECT_EQ(preview_view->camera_id(), second_camera_id);
- WaitForAndVerifyRenderedVideoFrame();
- }
- // Regression test for https://crbug.com/1316230.
- TEST_P(CaptureModeCameraFramesTest, CameraFatalErrors) {
- CaptureModeTestApi().StartForFullscreen(/*for_video=*/true);
- auto* camera_controller = GetCameraController();
- EXPECT_TRUE(camera_controller->selected_camera().is_valid());
- EXPECT_TRUE(camera_controller->camera_preview_widget());
- WaitForAndVerifyRenderedVideoFrame();
- // When a camera fatal error happens during rendering, we detect that an
- // consider it as a camera disconnection, which will result in the temporary
- // removal of the preview, before it gets re-added again when we refresh the
- // list of cameras.
- auto* video_source_provider = GetTestDelegate()->video_source_provider();
- video_source_provider->TriggerFatalErrorOnCamera(kDefaultCameraDeviceId);
- CameraDevicesChangeWaiter().Wait();
- EXPECT_FALSE(camera_controller->camera_preview_widget());
- EXPECT_TRUE(camera_controller->selected_camera().is_valid());
- // Now wait for the camera to be re-added again.
- CameraDevicesChangeWaiter().Wait();
- EXPECT_TRUE(camera_controller->camera_preview_widget());
- WaitForAndVerifyRenderedVideoFrame();
- }
- INSTANTIATE_TEST_SUITE_P(All, CaptureModeCameraFramesTest, testing::Bool());
- // The test fixture for starting test without active session.
- using NoSessionCaptureModeCameraTest = NoSessionAshTestBase;
- // Tests that camera info is requested after the user logs in instead of on
- // Chrome startup.
- TEST_F(NoSessionCaptureModeCameraTest, RequestCameraInfoAfterUserLogsIn) {
- auto* camera_controller = GetCameraController();
- GetTestDelegate()->video_source_provider()->AddFakeCameraWithoutNotifying(
- "/dev/video0", "Integrated Webcam", "0123:4567",
- media::MEDIA_VIDEO_FACING_NONE);
- // Verify that the camera devices info is not updated yet.
- EXPECT_TRUE(camera_controller->available_cameras().empty());
- // Simulate the user login process and wait for the camera info to be updated.
- {
- base::RunLoop loop;
- GetCameraController()->SetOnCameraListReceivedForTesting(
- loop.QuitClosure());
- SimulateUserLogin("example@gmail.com", user_manager::USER_TYPE_REGULAR);
- loop.Run();
- }
- // Verify that after the user logs in, the camera info is up-to-date.
- EXPECT_EQ(camera_controller->available_cameras().size(), 1u);
- }
- } // namespace ash
|