capture_mode_unittests.cc 286 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <memory>
  5. #include <string>
  6. #include <vector>
  7. #include "ash/accessibility/magnifier/docked_magnifier_controller.h"
  8. #include "ash/accessibility/magnifier/magnifier_glass.h"
  9. #include "ash/app_list/app_list_controller_impl.h"
  10. #include "ash/capture_mode/capture_label_view.h"
  11. #include "ash/capture_mode/capture_mode_bar_view.h"
  12. #include "ash/capture_mode/capture_mode_button.h"
  13. #include "ash/capture_mode/capture_mode_constants.h"
  14. #include "ash/capture_mode/capture_mode_controller.h"
  15. #include "ash/capture_mode/capture_mode_menu_group.h"
  16. #include "ash/capture_mode/capture_mode_metrics.h"
  17. #include "ash/capture_mode/capture_mode_session.h"
  18. #include "ash/capture_mode/capture_mode_session_focus_cycler.h"
  19. #include "ash/capture_mode/capture_mode_session_test_api.h"
  20. #include "ash/capture_mode/capture_mode_settings_test_api.h"
  21. #include "ash/capture_mode/capture_mode_settings_view.h"
  22. #include "ash/capture_mode/capture_mode_source_view.h"
  23. #include "ash/capture_mode/capture_mode_test_util.h"
  24. #include "ash/capture_mode/capture_mode_toggle_button.h"
  25. #include "ash/capture_mode/capture_mode_type_view.h"
  26. #include "ash/capture_mode/capture_mode_types.h"
  27. #include "ash/capture_mode/capture_mode_util.h"
  28. #include "ash/capture_mode/fake_folder_selection_dialog_factory.h"
  29. #include "ash/capture_mode/recording_overlay_controller.h"
  30. #include "ash/capture_mode/stop_recording_button_tray.h"
  31. #include "ash/capture_mode/test_capture_mode_delegate.h"
  32. #include "ash/capture_mode/user_nudge_controller.h"
  33. #include "ash/capture_mode/video_recording_watcher.h"
  34. #include "ash/constants/ash_features.h"
  35. #include "ash/display/cursor_window_controller.h"
  36. #include "ash/display/output_protection_delegate.h"
  37. #include "ash/display/screen_orientation_controller_test_api.h"
  38. #include "ash/display/window_tree_host_manager.h"
  39. #include "ash/projector/projector_annotation_tray.h"
  40. #include "ash/projector/projector_controller_impl.h"
  41. #include "ash/projector/projector_metrics.h"
  42. #include "ash/public/cpp/capture_mode/capture_mode_test_api.h"
  43. #include "ash/public/cpp/holding_space/holding_space_test_api.h"
  44. #include "ash/public/cpp/projector/projector_new_screencast_precondition.h"
  45. #include "ash/public/cpp/projector/projector_session.h"
  46. #include "ash/public/cpp/shelf_types.h"
  47. #include "ash/public/cpp/shell_window_ids.h"
  48. #include "ash/public/cpp/test/mock_projector_client.h"
  49. #include "ash/public/cpp/test/shell_test_api.h"
  50. #include "ash/root_window_controller.h"
  51. #include "ash/services/recording/recording_service_test_api.h"
  52. #include "ash/shell.h"
  53. #include "ash/system/status_area_widget.h"
  54. #include "ash/test/ash_test_base.h"
  55. #include "ash/test/test_widget_builder.h"
  56. #include "ash/wm/desks/desk.h"
  57. #include "ash/wm/desks/desks_controller.h"
  58. #include "ash/wm/desks/desks_test_util.h"
  59. #include "ash/wm/overview/overview_controller.h"
  60. #include "ash/wm/tablet_mode/tablet_mode_controller.h"
  61. #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
  62. #include "ash/wm/window_state.h"
  63. #include "ash/wm/window_util.h"
  64. #include "base/bind.h"
  65. #include "base/callback_forward.h"
  66. #include "base/callback_helpers.h"
  67. #include "base/files/file_path.h"
  68. #include "base/files/file_util.h"
  69. #include "base/memory/weak_ptr.h"
  70. #include "base/run_loop.h"
  71. #include "base/scoped_observation.h"
  72. #include "base/strings/stringprintf.h"
  73. #include "base/test/bind.h"
  74. #include "base/test/metrics/histogram_tester.h"
  75. #include "base/test/scoped_feature_list.h"
  76. #include "chromeos/dbus/power/fake_power_manager_client.h"
  77. #include "chromeos/dbus/power_manager/suspend.pb.h"
  78. #include "components/account_id/account_id.h"
  79. #include "components/user_manager/user_type.h"
  80. #include "mojo/public/cpp/bindings/pending_receiver.h"
  81. #include "mojo/public/cpp/bindings/pending_remote.h"
  82. #include "mojo/public/cpp/bindings/receiver.h"
  83. #include "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom.h"
  84. #include "ui/aura/client/aura_constants.h"
  85. #include "ui/aura/client/capture_client.h"
  86. #include "ui/aura/client/capture_client_observer.h"
  87. #include "ui/aura/client/window_parenting_client.h"
  88. #include "ui/aura/window_tracker.h"
  89. #include "ui/base/clipboard/clipboard.h"
  90. #include "ui/base/clipboard/clipboard_buffer.h"
  91. #include "ui/base/cursor/cursor_factory.h"
  92. #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
  93. #include "ui/compositor/compositor.h"
  94. #include "ui/compositor/layer.h"
  95. #include "ui/compositor/scoped_animation_duration_scale_mode.h"
  96. #include "ui/display/types/display_constants.h"
  97. #include "ui/display/util/display_util.h"
  98. #include "ui/events/event_constants.h"
  99. #include "ui/events/event_handler.h"
  100. #include "ui/events/test/event_generator.h"
  101. #include "ui/gfx/geometry/dip_util.h"
  102. #include "ui/gfx/geometry/insets.h"
  103. #include "ui/gfx/geometry/rect.h"
  104. #include "ui/gfx/geometry/size_conversions.h"
  105. #include "ui/gfx/geometry/vector2d.h"
  106. #include "ui/gfx/image/image_unittest_util.h"
  107. #include "ui/gfx/native_widget_types.h"
  108. #include "ui/message_center/message_center.h"
  109. #include "ui/message_center/message_center_observer.h"
  110. #include "ui/message_center/public/cpp/notification.h"
  111. #include "ui/message_center/public/cpp/notification_delegate.h"
  112. #include "ui/ozone/public/ozone_platform.h"
  113. #include "ui/views/accessibility/view_accessibility.h"
  114. #include "ui/views/view.h"
  115. #include "ui/views/widget/widget.h"
  116. #include "ui/wm/core/coordinate_conversion.h"
  117. #include "ui/wm/core/window_modality_controller.h"
  118. #include "ui/wm/core/window_util.h"
  119. namespace ash {
  120. namespace {
  121. constexpr char kEndRecordingReasonInClamshellHistogramName[] =
  122. "Ash.CaptureModeController.EndRecordingReason.ClamshellMode";
  123. constexpr char kScreenCaptureNotificationId[] = "capture_mode_notification";
  124. // Returns true if the software-composited cursor is enabled.
  125. bool IsCursorCompositingEnabled() {
  126. return Shell::Get()
  127. ->window_tree_host_manager()
  128. ->cursor_window_controller()
  129. ->is_cursor_compositing_enabled();
  130. }
  131. const message_center::Notification* GetPreviewNotification() {
  132. const message_center::NotificationList::Notifications notifications =
  133. message_center::MessageCenter::Get()->GetVisibleNotifications();
  134. for (const auto* notification : notifications) {
  135. if (notification->id() == kScreenCaptureNotificationId)
  136. return notification;
  137. }
  138. return nullptr;
  139. }
  140. void ClickNotification(absl::optional<int> button_index) {
  141. const message_center::Notification* notification = GetPreviewNotification();
  142. DCHECK(notification);
  143. notification->delegate()->Click(button_index, absl::nullopt);
  144. }
  145. // Sets up a callback that will be triggered when a capture file (image or
  146. // video) is deleted as a result of a user action. The callback will verify the
  147. // successful deletion of the file, and will quit the given `loop`.
  148. void SetUpFileDeletionVerifier(base::RunLoop* loop) {
  149. DCHECK(loop);
  150. CaptureModeTestApi().SetOnCaptureFileDeletedCallback(
  151. base::BindLambdaForTesting(
  152. [loop](const base::FilePath& path, bool delete_successful) {
  153. EXPECT_TRUE(delete_successful);
  154. base::ScopedAllowBlockingForTesting allow_blocking;
  155. EXPECT_FALSE(base::PathExists(path));
  156. loop->Quit();
  157. }));
  158. }
  159. void LeaveTabletMode() {
  160. TabletModeControllerTestApi test_api;
  161. test_api.LeaveTabletMode();
  162. }
  163. // Defines a capture client observer, that sets the input capture to the window
  164. // given to the constructor, and destroys it once capture is lost.
  165. class TestCaptureClientObserver : public aura::client::CaptureClientObserver {
  166. public:
  167. explicit TestCaptureClientObserver(std::unique_ptr<aura::Window> window)
  168. : window_(std::move(window)) {
  169. DCHECK(window_);
  170. auto* capture_client =
  171. aura::client::GetCaptureClient(window_->GetRootWindow());
  172. capture_client->SetCapture(window_.get());
  173. capture_client->AddObserver(this);
  174. }
  175. ~TestCaptureClientObserver() override { StopObserving(); }
  176. // aura::client::CaptureClientObserver:
  177. void OnCaptureChanged(aura::Window* lost_capture,
  178. aura::Window* gained_capture) override {
  179. if (lost_capture != window_.get())
  180. return;
  181. StopObserving();
  182. window_.reset();
  183. }
  184. private:
  185. void StopObserving() {
  186. if (!window_)
  187. return;
  188. auto* capture_client =
  189. aura::client::GetCaptureClient(window_->GetRootWindow());
  190. capture_client->RemoveObserver(this);
  191. }
  192. std::unique_ptr<aura::Window> window_;
  193. };
  194. } // namespace
  195. class CaptureModeTest : public AshTestBase {
  196. public:
  197. CaptureModeTest() = default;
  198. explicit CaptureModeTest(base::test::TaskEnvironment::TimeSource time)
  199. : AshTestBase(time) {}
  200. CaptureModeTest(const CaptureModeTest&) = delete;
  201. CaptureModeTest& operator=(const CaptureModeTest&) = delete;
  202. ~CaptureModeTest() override = default;
  203. views::Widget* GetCaptureModeBarWidget() const {
  204. auto* session = CaptureModeController::Get()->capture_mode_session();
  205. DCHECK(session);
  206. return session->capture_mode_bar_widget();
  207. }
  208. views::Widget* GetCaptureModeLabelWidget() const {
  209. auto* session = CaptureModeController::Get()->capture_mode_session();
  210. DCHECK(session);
  211. return CaptureModeSessionTestApi(session).GetCaptureLabelWidget();
  212. }
  213. CaptureModeSettingsView* GetCaptureModeSettingsView() const {
  214. auto* session = CaptureModeController::Get()->capture_mode_session();
  215. DCHECK(session);
  216. return CaptureModeSessionTestApi(session).GetCaptureModeSettingsView();
  217. }
  218. views::Widget* GetCaptureModeSettingsWidget() const {
  219. auto* session = CaptureModeController::Get()->capture_mode_session();
  220. DCHECK(session);
  221. return CaptureModeSessionTestApi(session).GetCaptureModeSettingsWidget();
  222. }
  223. bool IsFolderSelectionDialogShown() const {
  224. auto* session = CaptureModeController::Get()->capture_mode_session();
  225. DCHECK(session);
  226. return CaptureModeSessionTestApi(session).IsFolderSelectionDialogShown();
  227. }
  228. bool IsAllCaptureSessionUisVisible() const {
  229. auto* session = CaptureModeController::Get()->capture_mode_session();
  230. DCHECK(session);
  231. return CaptureModeSessionTestApi(session).IsAllUisVisible();
  232. }
  233. CaptureModeToggleButton* GetImageToggleButton() const {
  234. auto* controller = CaptureModeController::Get();
  235. DCHECK(controller->IsActive());
  236. return GetCaptureModeBarView()->capture_type_view()->image_toggle_button();
  237. }
  238. CaptureModeToggleButton* GetVideoToggleButton() const {
  239. auto* controller = CaptureModeController::Get();
  240. DCHECK(controller->IsActive());
  241. return GetCaptureModeBarView()->capture_type_view()->video_toggle_button();
  242. }
  243. CaptureModeToggleButton* GetWindowToggleButton() const {
  244. auto* controller = CaptureModeController::Get();
  245. DCHECK(controller->IsActive());
  246. return GetCaptureModeBarView()
  247. ->capture_source_view()
  248. ->window_toggle_button();
  249. }
  250. CaptureModeToggleButton* GetSettingsButton() const {
  251. auto* controller = CaptureModeController::Get();
  252. DCHECK(controller->IsActive());
  253. return GetCaptureModeBarView()->settings_button();
  254. }
  255. CaptureModeButton* GetCloseButton() const {
  256. auto* controller = CaptureModeController::Get();
  257. DCHECK(controller->IsActive());
  258. return GetCaptureModeBarView()->close_button();
  259. }
  260. aura::Window* GetDimensionsLabelWindow() const {
  261. auto* controller = CaptureModeController::Get();
  262. DCHECK(controller->IsActive());
  263. auto* widget = CaptureModeSessionTestApi(controller->capture_mode_session())
  264. .GetDimensionsLabelWidget();
  265. return widget ? widget->GetNativeWindow() : nullptr;
  266. }
  267. absl::optional<gfx::Point> GetMagnifierGlassCenterPoint() const {
  268. auto* controller = CaptureModeController::Get();
  269. DCHECK(controller->IsActive());
  270. auto& magnifier =
  271. CaptureModeSessionTestApi(controller->capture_mode_session())
  272. .GetMagnifierGlass();
  273. if (magnifier.host_widget_for_testing()) {
  274. return magnifier.host_widget_for_testing()
  275. ->GetWindowBoundsInScreen()
  276. .CenterPoint();
  277. }
  278. return absl::nullopt;
  279. }
  280. // Start Capture Mode with source region and type image.
  281. CaptureModeController* StartImageRegionCapture() {
  282. return StartCaptureSession(CaptureModeSource::kRegion,
  283. CaptureModeType::kImage);
  284. }
  285. CaptureModeController* StartSessionAndRecordWindow(aura::Window* window) {
  286. auto* controller = StartCaptureSession(CaptureModeSource::kWindow,
  287. CaptureModeType::kVideo);
  288. GetEventGenerator()->MoveMouseToCenterOf(window);
  289. StartVideoRecordingImmediately();
  290. EXPECT_TRUE(controller->is_recording_in_progress());
  291. return controller;
  292. }
  293. // Select a region by pressing and dragging the mouse.
  294. void SelectRegion(const gfx::Rect& region_in_screen,
  295. bool release_mouse = true) {
  296. auto* controller = CaptureModeController::Get();
  297. ASSERT_TRUE(controller->IsActive());
  298. ASSERT_EQ(CaptureModeSource::kRegion, controller->source());
  299. auto* event_generator = GetEventGenerator();
  300. event_generator->set_current_screen_location(region_in_screen.origin());
  301. event_generator->PressLeftButton();
  302. event_generator->MoveMouseTo(region_in_screen.bottom_right());
  303. if (release_mouse)
  304. event_generator->ReleaseLeftButton();
  305. auto capture_region_in_root = region_in_screen;
  306. wm::ConvertRectFromScreen(
  307. controller->capture_mode_session()->current_root(),
  308. &capture_region_in_root);
  309. EXPECT_EQ(capture_region_in_root, controller->user_capture_region());
  310. }
  311. void WaitForSessionToEnd() {
  312. auto* controller = CaptureModeController::Get();
  313. if (!controller->IsActive())
  314. return;
  315. auto* test_delegate = static_cast<TestCaptureModeDelegate*>(
  316. controller->delegate_for_testing());
  317. ASSERT_TRUE(test_delegate);
  318. base::RunLoop run_loop;
  319. test_delegate->set_on_session_state_changed_callback(
  320. run_loop.QuitClosure());
  321. run_loop.Run();
  322. ASSERT_FALSE(controller->IsActive());
  323. }
  324. void RemoveSecondaryDisplay() {
  325. const int64_t primary_id = WindowTreeHostManager::GetPrimaryDisplayId();
  326. display::ManagedDisplayInfo primary_info =
  327. display_manager()->GetDisplayInfo(primary_id);
  328. std::vector<display::ManagedDisplayInfo> display_info_list;
  329. display_info_list.push_back(primary_info);
  330. display_manager()->OnNativeDisplaysChanged(display_info_list);
  331. // Spin the run loop so that we get a signal that the associated root window
  332. // of the removed display is destroyed.
  333. base::RunLoop().RunUntilIdle();
  334. }
  335. void SwitchToUser2() {
  336. auto* session_controller = GetSessionControllerClient();
  337. constexpr char kUserEmail[] = "user2@capture_mode";
  338. session_controller->AddUserSession(kUserEmail);
  339. session_controller->SwitchActiveUser(AccountId::FromUserEmail(kUserEmail));
  340. }
  341. base::FilePath CreateFolderOnDriveFS(const std::string& custom_folder_name) {
  342. auto* test_delegate = CaptureModeController::Get()->delegate_for_testing();
  343. base::FilePath mount_point_path;
  344. EXPECT_TRUE(test_delegate->GetDriveFsMountPointPath(&mount_point_path));
  345. base::FilePath folder_on_drive_fs =
  346. mount_point_path.Append("root").Append(custom_folder_name);
  347. base::ScopedAllowBlockingForTesting allow_blocking;
  348. const bool result = base::CreateDirectory(folder_on_drive_fs);
  349. EXPECT_TRUE(result);
  350. return folder_on_drive_fs;
  351. }
  352. void OpenSettingsView() {
  353. CaptureModeSession* session =
  354. CaptureModeController::Get()->capture_mode_session();
  355. DCHECK(session);
  356. ClickOnView(CaptureModeSessionTestApi(session)
  357. .GetCaptureModeBarView()
  358. ->settings_button(),
  359. GetEventGenerator());
  360. }
  361. std::unique_ptr<aura::Window> CreateTransientModalChildWindow(
  362. gfx::Rect child_window_bounds,
  363. aura::Window* transient_parent) {
  364. auto child = CreateTestWindow(child_window_bounds);
  365. wm::AddTransientChild(transient_parent, child.get());
  366. child->Show();
  367. child->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
  368. wm::SetModalParent(child.get(), transient_parent);
  369. return child;
  370. }
  371. };
  372. class CaptureSessionWidgetClosed {
  373. public:
  374. explicit CaptureSessionWidgetClosed(views::Widget* widget) {
  375. DCHECK(widget);
  376. widget_ = widget->GetWeakPtr();
  377. }
  378. CaptureSessionWidgetClosed(const CaptureSessionWidgetClosed&) = delete;
  379. CaptureSessionWidgetClosed& operator=(const CaptureSessionWidgetClosed&) =
  380. delete;
  381. ~CaptureSessionWidgetClosed() = default;
  382. bool GetWidgetClosed() const { return !widget_ || widget_->IsClosed(); }
  383. private:
  384. base::WeakPtr<views::Widget> widget_;
  385. };
  386. class CaptureNotificationWaiter : public message_center::MessageCenterObserver {
  387. public:
  388. CaptureNotificationWaiter() {
  389. message_center::MessageCenter::Get()->AddObserver(this);
  390. }
  391. ~CaptureNotificationWaiter() override {
  392. message_center::MessageCenter::Get()->RemoveObserver(this);
  393. }
  394. void Wait() { run_loop_.Run(); }
  395. // message_center::MessageCenterObserver:
  396. void OnNotificationAdded(const std::string& notification_id) override {
  397. if (notification_id == kScreenCaptureNotificationId)
  398. run_loop_.Quit();
  399. }
  400. private:
  401. base::RunLoop run_loop_;
  402. };
  403. TEST_F(CaptureModeTest, StartStop) {
  404. auto* controller = CaptureModeController::Get();
  405. controller->Start(CaptureModeEntryType::kQuickSettings);
  406. EXPECT_TRUE(controller->IsActive());
  407. // Calling start again is a no-op.
  408. controller->Start(CaptureModeEntryType::kQuickSettings);
  409. EXPECT_TRUE(controller->IsActive());
  410. // Closing the session should close the native window of capture mode bar
  411. // immediately.
  412. auto* bar_window = GetCaptureModeBarWidget()->GetNativeWindow();
  413. aura::WindowTracker tracker({bar_window});
  414. controller->Stop();
  415. EXPECT_TRUE(tracker.windows().empty());
  416. EXPECT_FALSE(controller->IsActive());
  417. }
  418. TEST_F(CaptureModeTest, CheckCursorVisibility) {
  419. // Hide cursor before entering capture mode.
  420. auto* cursor_manager = Shell::Get()->cursor_manager();
  421. cursor_manager->SetCursor(ui::mojom::CursorType::kPointer);
  422. cursor_manager->HideCursor();
  423. cursor_manager->DisableMouseEvents();
  424. EXPECT_FALSE(cursor_manager->IsCursorVisible());
  425. auto* controller = CaptureModeController::Get();
  426. controller->Start(CaptureModeEntryType::kQuickSettings);
  427. // After capture mode initialization, cursor should be visible.
  428. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  429. EXPECT_TRUE(cursor_manager->IsMouseEventsEnabled());
  430. // Enter tablet mode.
  431. SwitchToTabletMode();
  432. // After entering tablet mode, cursor should be invisible and locked.
  433. EXPECT_FALSE(cursor_manager->IsCursorVisible());
  434. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  435. // Leave tablet mode, cursor should be visible again.
  436. LeaveTabletMode();
  437. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  438. }
  439. TEST_F(CaptureModeTest, CheckCursorVisibilityOnTabletMode) {
  440. auto* cursor_manager = Shell::Get()->cursor_manager();
  441. // Enter tablet mode.
  442. SwitchToTabletMode();
  443. // After entering tablet mode, cursor should be invisible.
  444. EXPECT_FALSE(cursor_manager->IsCursorVisible());
  445. // Open capture mode.
  446. auto* controller = CaptureModeController::Get();
  447. controller->Start(CaptureModeEntryType::kQuickSettings);
  448. // Cursor should be invisible since it's still in tablet mode.
  449. EXPECT_FALSE(cursor_manager->IsCursorVisible());
  450. // Leave tablet mode, cursor should be visible now.
  451. LeaveTabletMode();
  452. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  453. }
  454. // Regression test for https://crbug.com/1172425.
  455. TEST_F(CaptureModeTest, NoCrashOnClearingCapture) {
  456. TestCaptureClientObserver observer(CreateTestWindow(gfx::Rect(200, 200)));
  457. auto* controller = StartImageRegionCapture();
  458. EXPECT_TRUE(controller->IsActive());
  459. }
  460. TEST_F(CaptureModeTest, CheckWidgetClosed) {
  461. auto* controller = CaptureModeController::Get();
  462. controller->Start(CaptureModeEntryType::kQuickSettings);
  463. EXPECT_TRUE(controller->IsActive());
  464. EXPECT_TRUE(GetCaptureModeBarWidget());
  465. CaptureSessionWidgetClosed observer(GetCaptureModeBarWidget());
  466. EXPECT_FALSE(observer.GetWidgetClosed());
  467. controller->Stop();
  468. EXPECT_FALSE(controller->IsActive());
  469. EXPECT_FALSE(controller->capture_mode_session());
  470. // The Widget should have been destroyed by now.
  471. EXPECT_TRUE(observer.GetWidgetClosed());
  472. }
  473. TEST_F(CaptureModeTest, StartWithMostRecentTypeAndSource) {
  474. auto* controller = CaptureModeController::Get();
  475. controller->SetSource(CaptureModeSource::kFullscreen);
  476. controller->SetType(CaptureModeType::kVideo);
  477. controller->Start(CaptureModeEntryType::kQuickSettings);
  478. EXPECT_TRUE(controller->IsActive());
  479. EXPECT_FALSE(GetImageToggleButton()->GetToggled());
  480. EXPECT_TRUE(GetVideoToggleButton()->GetToggled());
  481. EXPECT_TRUE(GetFullscreenToggleButton()->GetToggled());
  482. EXPECT_FALSE(GetRegionToggleButton()->GetToggled());
  483. EXPECT_FALSE(GetWindowToggleButton()->GetToggled());
  484. ClickOnView(GetCloseButton(), GetEventGenerator());
  485. EXPECT_FALSE(controller->IsActive());
  486. }
  487. TEST_F(CaptureModeTest, ChangeTypeAndSourceFromUI) {
  488. auto* controller = CaptureModeController::Get();
  489. controller->Start(CaptureModeEntryType::kQuickSettings);
  490. EXPECT_TRUE(controller->IsActive());
  491. EXPECT_TRUE(GetImageToggleButton()->GetToggled());
  492. EXPECT_FALSE(GetVideoToggleButton()->GetToggled());
  493. auto* event_generator = GetEventGenerator();
  494. ClickOnView(GetVideoToggleButton(), event_generator);
  495. EXPECT_FALSE(GetImageToggleButton()->GetToggled());
  496. EXPECT_TRUE(GetVideoToggleButton()->GetToggled());
  497. EXPECT_EQ(controller->type(), CaptureModeType::kVideo);
  498. ClickOnView(GetWindowToggleButton(), event_generator);
  499. EXPECT_FALSE(GetFullscreenToggleButton()->GetToggled());
  500. EXPECT_FALSE(GetRegionToggleButton()->GetToggled());
  501. EXPECT_TRUE(GetWindowToggleButton()->GetToggled());
  502. EXPECT_EQ(controller->source(), CaptureModeSource::kWindow);
  503. ClickOnView(GetFullscreenToggleButton(), event_generator);
  504. EXPECT_TRUE(GetFullscreenToggleButton()->GetToggled());
  505. EXPECT_FALSE(GetRegionToggleButton()->GetToggled());
  506. EXPECT_FALSE(GetWindowToggleButton()->GetToggled());
  507. EXPECT_EQ(controller->source(), CaptureModeSource::kFullscreen);
  508. }
  509. TEST_F(CaptureModeTest, VideoRecordingUiBehavior) {
  510. // Start Capture Mode in a fullscreen video recording mode.
  511. CaptureModeController* controller = StartCaptureSession(
  512. CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
  513. EXPECT_TRUE(controller->IsActive());
  514. EXPECT_FALSE(controller->is_recording_in_progress());
  515. EXPECT_FALSE(IsCursorCompositingEnabled());
  516. // Hit Enter to begin recording.
  517. auto* event_generator = GetEventGenerator();
  518. SendKey(ui::VKEY_RETURN, event_generator);
  519. EXPECT_EQ(ui::mojom::CursorType::kPointer,
  520. Shell::Get()->cursor_manager()->GetCursor().type());
  521. WaitForRecordingToStart();
  522. EXPECT_FALSE(controller->IsActive());
  523. EXPECT_TRUE(controller->is_recording_in_progress());
  524. // The composited cursor should remain disabled now that we're using the
  525. // cursor overlay on the capturer. The stop-recording button should show up in
  526. // the status area widget.
  527. EXPECT_FALSE(IsCursorCompositingEnabled());
  528. auto* stop_recording_button = Shell::GetPrimaryRootWindowController()
  529. ->GetStatusAreaWidget()
  530. ->stop_recording_button_tray();
  531. EXPECT_TRUE(stop_recording_button->visible_preferred());
  532. // End recording via the stop-recording button. Expect that it's now hidden.
  533. base::HistogramTester histogram_tester;
  534. ClickOnView(stop_recording_button, event_generator);
  535. EXPECT_FALSE(stop_recording_button->visible_preferred());
  536. EXPECT_FALSE(controller->is_recording_in_progress());
  537. EXPECT_FALSE(IsCursorCompositingEnabled());
  538. histogram_tester.ExpectBucketCount(
  539. kEndRecordingReasonInClamshellHistogramName,
  540. EndRecordingReason::kStopRecordingButton, 1);
  541. }
  542. // Tests the behavior of repositioning a region with capture mode.
  543. TEST_F(CaptureModeTest, CaptureRegionRepositionBehavior) {
  544. // Use a set display size as we will be choosing points in this test.
  545. UpdateDisplay("800x700");
  546. auto* controller = StartImageRegionCapture();
  547. // The first time selecting a region, the region is a default rect.
  548. EXPECT_EQ(gfx::Rect(), controller->user_capture_region());
  549. // Press down and drag to select a region.
  550. SelectRegion(gfx::Rect(100, 100, 600, 600));
  551. // Click somewhere in the center on the region and drag. The whole region
  552. // should move. Note that the point cannot be in the capture button bounds,
  553. // which is located in the center of the region.
  554. auto* event_generator = GetEventGenerator();
  555. event_generator->set_current_screen_location(gfx::Point(200, 200));
  556. event_generator->DragMouseBy(-50, -50);
  557. EXPECT_EQ(gfx::Rect(50, 50, 600, 600), controller->user_capture_region());
  558. // Try to drag the region offscreen. The region should be bound by the display
  559. // size.
  560. event_generator->set_current_screen_location(gfx::Point(100, 100));
  561. event_generator->DragMouseBy(-150, -150);
  562. EXPECT_EQ(gfx::Rect(600, 600), controller->user_capture_region());
  563. }
  564. // Tests the behavior of resizing a region with capture mode using the corner
  565. // drag affordances.
  566. TEST_F(CaptureModeTest, CaptureRegionCornerResizeBehavior) {
  567. // Use a set display size as we will be choosing points in this test.
  568. UpdateDisplay("800x700");
  569. auto* controller = StartImageRegionCapture();
  570. // Create the initial region.
  571. const gfx::Rect target_region(gfx::Rect(200, 200, 400, 400));
  572. SelectRegion(target_region);
  573. // For each corner point try dragging to several points and verify that the
  574. // capture region is as expected.
  575. struct {
  576. std::string trace;
  577. gfx::Point drag_point;
  578. // The point that stays the same while dragging. It is the opposite vertex
  579. // to |drag_point| on |target_region|.
  580. gfx::Point anchor_point;
  581. } kDragCornerCases[] = {
  582. {"origin", target_region.origin(), target_region.bottom_right()},
  583. {"top_right", target_region.top_right(), target_region.bottom_left()},
  584. {"bottom_right", target_region.bottom_right(), target_region.origin()},
  585. {"bottom_left", target_region.bottom_left(), target_region.top_right()},
  586. };
  587. // The test corner points are one in each corner outside |target_region| and
  588. // one point inside |target_region|.
  589. auto drag_test_points = {gfx::Point(100, 100), gfx::Point(700, 100),
  590. gfx::Point(700, 700), gfx::Point(100, 700),
  591. gfx::Point(400, 400)};
  592. auto* event_generator = GetEventGenerator();
  593. for (auto test_case : kDragCornerCases) {
  594. SCOPED_TRACE(test_case.trace);
  595. event_generator->set_current_screen_location(test_case.drag_point);
  596. event_generator->PressLeftButton();
  597. // At each drag test point, the region rect should be the rect created by
  598. // the given |corner_point| and the drag test point. That is, the width
  599. // should match the x distance between the two points, the height should
  600. // match the y distance between the two points and that both points are
  601. // contained in the region.
  602. for (auto drag_test_point : drag_test_points) {
  603. event_generator->MoveMouseTo(drag_test_point);
  604. gfx::Rect region = controller->user_capture_region();
  605. const gfx::Vector2d distance = test_case.anchor_point - drag_test_point;
  606. EXPECT_EQ(std::abs(distance.x()), region.width());
  607. EXPECT_EQ(std::abs(distance.y()), region.height());
  608. // gfx::Rect::Contains returns the point (x+width, y+height) as false, so
  609. // make the region one unit bigger to account for this.
  610. region.Inset(gfx::Insets(-1));
  611. EXPECT_TRUE(region.Contains(drag_test_point));
  612. EXPECT_TRUE(region.Contains(test_case.anchor_point));
  613. }
  614. // Make sure the region is reset for the next iteration.
  615. event_generator->MoveMouseTo(test_case.drag_point);
  616. event_generator->ReleaseLeftButton();
  617. ASSERT_EQ(target_region, controller->user_capture_region());
  618. }
  619. }
  620. // Tests the behavior of resizing a region with capture mode using the edge drag
  621. // affordances.
  622. TEST_F(CaptureModeTest, CaptureRegionEdgeResizeBehavior) {
  623. // Use a set display size as we will be choosing points in this test.
  624. UpdateDisplay("800x700");
  625. auto* controller = StartImageRegionCapture();
  626. // Create the initial region.
  627. const gfx::Rect target_region(gfx::Rect(200, 200, 200, 200));
  628. SelectRegion(target_region);
  629. // For each edge point try dragging to several points and verify that the
  630. // capture region is as expected.
  631. struct {
  632. std::string trace;
  633. gfx::Point drag_point;
  634. // True if horizontal direction (left, right). Height stays the same while
  635. // dragging if true, width stays the same while dragging if false.
  636. bool horizontal;
  637. // The edge that stays the same while dragging. It is the opposite edge to
  638. // |drag_point|. For example, if |drag_point| is the left center of
  639. // |target_region|, then |anchor_edge| is the right edge.
  640. int anchor_edge;
  641. } kDragEdgeCases[] = {
  642. {"left", target_region.left_center(), true, target_region.right()},
  643. {"top", target_region.top_center(), false, target_region.bottom()},
  644. {"right", target_region.right_center(), true, target_region.x()},
  645. {"bottom", target_region.bottom_center(), false, target_region.y()},
  646. };
  647. // Drag to a couple of points that change both x and y. In all these cases,
  648. // only the width or height should change.
  649. auto drag_test_points = {gfx::Point(150, 150), gfx::Point(350, 350),
  650. gfx::Point(450, 450)};
  651. auto* event_generator = GetEventGenerator();
  652. for (auto test_case : kDragEdgeCases) {
  653. SCOPED_TRACE(test_case.trace);
  654. event_generator->set_current_screen_location(test_case.drag_point);
  655. event_generator->PressLeftButton();
  656. for (auto drag_test_point : drag_test_points) {
  657. event_generator->MoveMouseTo(drag_test_point);
  658. const gfx::Rect region = controller->user_capture_region();
  659. // One of width/height will always be the same as |target_region|'s
  660. // initial width/height, depending on the edge affordance. The other
  661. // dimension will be the distance from |drag_test_point| to the anchor
  662. // edge.
  663. const int variable_length = std::abs(
  664. (test_case.horizontal ? drag_test_point.x() : drag_test_point.y()) -
  665. test_case.anchor_edge);
  666. const int expected_width =
  667. test_case.horizontal ? variable_length : target_region.width();
  668. const int expected_height =
  669. test_case.horizontal ? target_region.height() : variable_length;
  670. EXPECT_EQ(expected_width, region.width());
  671. EXPECT_EQ(expected_height, region.height());
  672. }
  673. // Make sure the region is reset for the next iteration.
  674. event_generator->MoveMouseTo(test_case.drag_point);
  675. event_generator->ReleaseLeftButton();
  676. ASSERT_EQ(target_region, controller->user_capture_region());
  677. }
  678. }
  679. // Tests that the capture region persists after exiting and reentering capture
  680. // mode.
  681. TEST_F(CaptureModeTest, CaptureRegionPersistsAfterExit) {
  682. auto* controller = StartImageRegionCapture();
  683. const gfx::Rect region(100, 100, 200, 200);
  684. SelectRegion(region);
  685. controller->Stop();
  686. controller->Start(CaptureModeEntryType::kQuickSettings);
  687. EXPECT_EQ(region, controller->user_capture_region());
  688. }
  689. // Tests that the capture region resets when clicking outside the current
  690. // capture regions bounds.
  691. TEST_F(CaptureModeTest, CaptureRegionResetsOnClickOutside) {
  692. auto* controller = StartImageRegionCapture();
  693. SelectRegion(gfx::Rect(100, 100, 200, 200));
  694. // Click on an area outside of the current capture region. The capture region
  695. // should reset to default rect.
  696. auto* event_generator = GetEventGenerator();
  697. event_generator->set_current_screen_location(gfx::Point(400, 400));
  698. event_generator->ClickLeftButton();
  699. EXPECT_EQ(gfx::Rect(), controller->user_capture_region());
  700. }
  701. // Tests that buttons on the capture mode bar still work when a region is
  702. // "covering" them.
  703. TEST_F(CaptureModeTest, CaptureRegionCoversCaptureModeBar) {
  704. UpdateDisplay("800x700");
  705. auto* controller = StartImageRegionCapture();
  706. // Select a region such that the capture mode bar is covered.
  707. SelectRegion(gfx::Rect(5, 5, 795, 795));
  708. EXPECT_TRUE(controller->user_capture_region().Contains(
  709. GetCaptureModeBarView()->GetBoundsInScreen()));
  710. // Click on the fullscreen toggle button to verify that we enter fullscreen
  711. // capture mode. Then click on the region toggle button to verify that we
  712. // reenter region capture mode and that the region is still covering the
  713. // capture mode bar.
  714. auto* event_generator = GetEventGenerator();
  715. ClickOnView(GetFullscreenToggleButton(), event_generator);
  716. EXPECT_EQ(CaptureModeSource::kFullscreen, controller->source());
  717. ClickOnView(GetRegionToggleButton(), GetEventGenerator());
  718. ASSERT_EQ(CaptureModeSource::kRegion, controller->source());
  719. ASSERT_TRUE(controller->user_capture_region().Contains(
  720. GetCaptureModeBarView()->GetBoundsInScreen()));
  721. ClickOnView(GetCloseButton(), event_generator);
  722. EXPECT_FALSE(controller->IsActive());
  723. }
  724. // Tests that the magnifying glass appears while fine tuning the capture region,
  725. // and that the cursor is hidden if the magnifying glass is present.
  726. TEST_F(CaptureModeTest, CaptureRegionMagnifierWhenFineTuning) {
  727. const gfx::Vector2d kDragDelta(50, 50);
  728. UpdateDisplay("800x700");
  729. // Start Capture Mode in a region in image mode.
  730. StartImageRegionCapture();
  731. // Press down and drag to select a region. The magnifier should not be
  732. // visible yet.
  733. gfx::Rect capture_region{200, 200, 400, 400};
  734. SelectRegion(capture_region);
  735. EXPECT_EQ(absl::nullopt, GetMagnifierGlassCenterPoint());
  736. auto check_magnifier_shows_properly = [this](const gfx::Point& origin,
  737. const gfx::Point& destination,
  738. bool should_show_magnifier) {
  739. // If |should_show_magnifier|, check that the magnifying glass is centered
  740. // on the mouse after press and during drag, and that the cursor is hidden.
  741. // If not |should_show_magnifier|, check that the magnifying glass never
  742. // shows. Should always be not visible when mouse button is released.
  743. auto* event_generator = GetEventGenerator();
  744. absl::optional<gfx::Point> expected_origin =
  745. should_show_magnifier ? absl::make_optional(origin) : absl::nullopt;
  746. absl::optional<gfx::Point> expected_destination =
  747. should_show_magnifier ? absl::make_optional(destination)
  748. : absl::nullopt;
  749. auto* cursor_manager = Shell::Get()->cursor_manager();
  750. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  751. // Move cursor to |origin| and click.
  752. event_generator->set_current_screen_location(origin);
  753. event_generator->PressLeftButton();
  754. EXPECT_EQ(expected_origin, GetMagnifierGlassCenterPoint());
  755. EXPECT_NE(should_show_magnifier, cursor_manager->IsCursorVisible());
  756. // Drag to |destination| while holding left button.
  757. event_generator->MoveMouseTo(destination);
  758. EXPECT_EQ(expected_destination, GetMagnifierGlassCenterPoint());
  759. EXPECT_NE(should_show_magnifier, cursor_manager->IsCursorVisible());
  760. // Drag back to |origin| while still holding left button.
  761. event_generator->MoveMouseTo(origin);
  762. EXPECT_EQ(expected_origin, GetMagnifierGlassCenterPoint());
  763. EXPECT_NE(should_show_magnifier, cursor_manager->IsCursorVisible());
  764. // Release left button.
  765. event_generator->ReleaseLeftButton();
  766. EXPECT_EQ(absl::nullopt, GetMagnifierGlassCenterPoint());
  767. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  768. };
  769. // Drag the capture region from within the existing selected region. The
  770. // magnifier should not be visible at any point.
  771. check_magnifier_shows_properly(gfx::Point(400, 250), gfx::Point(500, 350),
  772. /*should_show_magnifier=*/false);
  773. // Check that each corner fine tune position shows the magnifier when
  774. // dragging.
  775. struct {
  776. std::string trace;
  777. FineTunePosition position;
  778. } kFineTunePositions[] = {{"top_left", FineTunePosition::kTopLeft},
  779. {"top_right", FineTunePosition::kTopRight},
  780. {"bottom_right", FineTunePosition::kBottomRight},
  781. {"bottom_left", FineTunePosition::kBottomLeft}};
  782. for (const auto& fine_tune_position : kFineTunePositions) {
  783. SCOPED_TRACE(fine_tune_position.trace);
  784. const gfx::Point drag_affordance_location =
  785. capture_mode_util::GetLocationForFineTunePosition(
  786. capture_region, fine_tune_position.position);
  787. check_magnifier_shows_properly(drag_affordance_location,
  788. drag_affordance_location + kDragDelta,
  789. /*should_show_magnifier=*/true);
  790. }
  791. }
  792. // Tests that the dimensions label properly renders for capture regions.
  793. TEST_F(CaptureModeTest, CaptureRegionDimensionsLabelLocation) {
  794. UpdateDisplay("900x800");
  795. // Start Capture Mode in a region in image mode.
  796. StartImageRegionCapture();
  797. // Press down and don't move the mouse. Label shouldn't display for empty
  798. // capture regions.
  799. auto* generator = GetEventGenerator();
  800. generator->set_current_screen_location(gfx::Point(0, 0));
  801. generator->PressLeftButton();
  802. auto* controller = CaptureModeController::Get();
  803. EXPECT_TRUE(controller->IsActive());
  804. EXPECT_TRUE(controller->user_capture_region().IsEmpty());
  805. EXPECT_EQ(nullptr, GetDimensionsLabelWindow());
  806. generator->ReleaseLeftButton();
  807. // Press down and drag to select a large region. Verify that the dimensions
  808. // label is centered and that the label is below the capture region.
  809. gfx::Rect capture_region{100, 100, 600, 200};
  810. SelectRegion(capture_region, /*release_mouse=*/false);
  811. EXPECT_EQ(capture_region.CenterPoint().x(),
  812. GetDimensionsLabelWindow()->bounds().CenterPoint().x());
  813. EXPECT_EQ(capture_region.bottom() +
  814. CaptureModeSession::kSizeLabelYDistanceFromRegionDp,
  815. GetDimensionsLabelWindow()->bounds().y());
  816. generator->ReleaseLeftButton();
  817. EXPECT_EQ(nullptr, GetDimensionsLabelWindow());
  818. // Create a new capture region close to the left side of the screen such that
  819. // if the label was centered it would extend out of the screen.
  820. // The x value of the label should be the left edge of the screen (0).
  821. capture_region.SetRect(2, 100, 2, 100);
  822. SelectRegion(capture_region, /*release_mouse=*/false);
  823. EXPECT_EQ(0, GetDimensionsLabelWindow()->bounds().x());
  824. generator->ReleaseLeftButton();
  825. EXPECT_EQ(nullptr, GetDimensionsLabelWindow());
  826. // Create a new capture region close to the right side of the screen such that
  827. // if the label was centered it would extend out of the screen.
  828. // The right (x + width) of the label should be the right edge of the screen
  829. // (900).
  830. capture_region.SetRect(896, 100, 2, 100);
  831. SelectRegion(capture_region, /*release_mouse=*/false);
  832. EXPECT_EQ(900, GetDimensionsLabelWindow()->bounds().right());
  833. generator->ReleaseLeftButton();
  834. EXPECT_EQ(nullptr, GetDimensionsLabelWindow());
  835. // Create a new capture region close to the bottom side of the screen.
  836. // The label should now appear inside the capture region, just above the
  837. // bottom edge. It should be above the bottom of the screen as well.
  838. capture_region.SetRect(100, 700, 600, 790);
  839. SelectRegion(capture_region, /*release_mouse=*/false);
  840. EXPECT_EQ(800 - CaptureModeSession::kSizeLabelYDistanceFromRegionDp,
  841. GetDimensionsLabelWindow()->bounds().bottom());
  842. generator->ReleaseLeftButton();
  843. EXPECT_EQ(nullptr, GetDimensionsLabelWindow());
  844. }
  845. TEST_F(CaptureModeTest, CaptureRegionCaptureButtonLocation) {
  846. UpdateDisplay("900x800");
  847. auto* controller = StartImageRegionCapture();
  848. // Select a large region. Verify that the capture button widget is centered.
  849. SelectRegion(gfx::Rect(100, 100, 600, 600));
  850. views::Widget* capture_button_widget = GetCaptureModeLabelWidget();
  851. ASSERT_TRUE(capture_button_widget);
  852. aura::Window* capture_button_window =
  853. capture_button_widget->GetNativeWindow();
  854. EXPECT_EQ(gfx::Point(400, 400),
  855. capture_button_window->bounds().CenterPoint());
  856. // Drag the bottom corner so that the region is too small to fit the capture
  857. // button. Verify that the button is aligned horizontally and placed below the
  858. // region.
  859. auto* event_generator = GetEventGenerator();
  860. event_generator->DragMouseTo(gfx::Point(120, 120));
  861. EXPECT_EQ(gfx::Rect(100, 100, 20, 20), controller->user_capture_region());
  862. EXPECT_EQ(110, capture_button_window->bounds().CenterPoint().x());
  863. const int distance_from_region =
  864. CaptureModeSession::kCaptureButtonDistanceFromRegionDp;
  865. EXPECT_EQ(120 + distance_from_region, capture_button_window->bounds().y());
  866. // Click inside the region to drag the entire region to the bottom of the
  867. // screen. Verify that the button is aligned horizontally and placed above the
  868. // region.
  869. event_generator->set_current_screen_location(gfx::Point(110, 110));
  870. event_generator->DragMouseTo(gfx::Point(110, 790));
  871. EXPECT_EQ(gfx::Rect(100, 780, 20, 20), controller->user_capture_region());
  872. EXPECT_EQ(110, capture_button_window->bounds().CenterPoint().x());
  873. EXPECT_EQ(780 - distance_from_region,
  874. capture_button_window->bounds().bottom());
  875. }
  876. // Tests some edge cases to ensure the capture button does not intersect the
  877. // capture bar and end up unclickable since it is stacked below the capture bar.
  878. // Regression test for https://crbug.com/1186462.
  879. TEST_F(CaptureModeTest, CaptureRegionCaptureButtonDoesNotIntersectCaptureBar) {
  880. UpdateDisplay("800x700");
  881. StartImageRegionCapture();
  882. // Create a region that would cover the capture mode bar. Add some insets to
  883. // ensure that the capture button could fit inside. Verify that the two
  884. // widgets do not overlap.
  885. const gfx::Rect capture_bar_bounds =
  886. GetCaptureModeBarWidget()->GetWindowBoundsInScreen();
  887. gfx::Rect region_bounds = capture_bar_bounds;
  888. region_bounds.Inset(-20);
  889. SelectRegion(region_bounds);
  890. EXPECT_FALSE(capture_bar_bounds.Intersects(
  891. GetCaptureModeLabelWidget()->GetWindowBoundsInScreen()));
  892. // Create a thin region above the capture mode bar. The algorithm would
  893. // normally place the capture label under the region, but should adjust to
  894. // avoid intersecting.
  895. auto* event_generator = GetEventGenerator();
  896. event_generator->set_current_screen_location(gfx::Point());
  897. event_generator->ClickLeftButton();
  898. const int capture_bar_midpoint_x = capture_bar_bounds.CenterPoint().x();
  899. SelectRegion(
  900. gfx::Rect(capture_bar_midpoint_x, capture_bar_bounds.y() - 10, 20, 10));
  901. EXPECT_FALSE(capture_bar_bounds.Intersects(
  902. GetCaptureModeLabelWidget()->GetWindowBoundsInScreen()));
  903. // Create a thin region below the capture mode bar which reaches the bottom of
  904. // the display. The algorithm would normally place the capture label above
  905. // the region, but should adjust to avoid intersecting.
  906. event_generator->set_current_screen_location(gfx::Point());
  907. event_generator->ClickLeftButton();
  908. SelectRegion(gfx::Rect(capture_bar_midpoint_x, capture_bar_bounds.bottom(),
  909. 20, 800 - capture_bar_bounds.bottom()));
  910. EXPECT_FALSE(capture_bar_bounds.Intersects(
  911. GetCaptureModeLabelWidget()->GetWindowBoundsInScreen()));
  912. // Create a thin region that is vertical as tall as the display, and at the
  913. // left edge of the display. The capture label button should be right of the
  914. // region.
  915. event_generator->set_current_screen_location(gfx::Point());
  916. event_generator->ClickLeftButton();
  917. SelectRegion(gfx::Rect(20, 800));
  918. EXPECT_GT(GetCaptureModeLabelWidget()->GetWindowBoundsInScreen().x(), 20);
  919. }
  920. // Tests that pressing on the capture bar and releasing the press outside of the
  921. // capture bar, the capture region could still be draggable and set. Regression
  922. // test for https://crbug.com/1325028.
  923. TEST_F(CaptureModeTest, SetCaptureRegionAfterPressOnCaptureBar) {
  924. UpdateDisplay("800x600");
  925. auto* controller =
  926. StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
  927. auto* settings_button = GetSettingsButton();
  928. // Press on the settings button without release.
  929. auto* event_generator = GetEventGenerator();
  930. event_generator->MoveMouseTo(
  931. settings_button->GetBoundsInScreen().CenterPoint());
  932. event_generator->PressLeftButton();
  933. // Move mouse to the outside of the capture bar and then release the press.
  934. event_generator->MoveMouseTo({300, 300});
  935. event_generator->ReleaseLeftButton();
  936. // Set the capture region, and verify it's set successfully.
  937. const gfx::Rect region_bounds(100, 100, 200, 200);
  938. SelectRegion(region_bounds);
  939. EXPECT_EQ(controller->user_capture_region(), region_bounds);
  940. }
  941. TEST_F(CaptureModeTest, WindowCapture) {
  942. // Create 2 windows that overlap with each other.
  943. const gfx::Rect bounds1(0, 0, 200, 200);
  944. std::unique_ptr<aura::Window> window1(CreateTestWindow(bounds1));
  945. const gfx::Rect bounds2(150, 150, 200, 200);
  946. std::unique_ptr<aura::Window> window2(CreateTestWindow(bounds2));
  947. auto* controller = CaptureModeController::Get();
  948. controller->SetSource(CaptureModeSource::kWindow);
  949. controller->SetType(CaptureModeType::kImage);
  950. controller->Start(CaptureModeEntryType::kAccelTakeWindowScreenshot);
  951. EXPECT_TRUE(controller->IsActive());
  952. auto* event_generator = GetEventGenerator();
  953. event_generator->MoveMouseToCenterOf(window1.get());
  954. auto* capture_mode_session = controller->capture_mode_session();
  955. EXPECT_EQ(capture_mode_session->GetSelectedWindow(), window1.get());
  956. event_generator->MoveMouseToCenterOf(window2.get());
  957. EXPECT_EQ(capture_mode_session->GetSelectedWindow(), window2.get());
  958. // Now move the mouse to the overlapped area.
  959. event_generator->MoveMouseTo(gfx::Point(175, 175));
  960. EXPECT_EQ(capture_mode_session->GetSelectedWindow(), window2.get());
  961. // Close the current selected window should automatically focus to next one.
  962. window2.reset();
  963. EXPECT_EQ(capture_mode_session->GetSelectedWindow(), window1.get());
  964. // Open another one on top also change the selected window.
  965. std::unique_ptr<aura::Window> window3(CreateTestWindow(bounds2));
  966. EXPECT_EQ(capture_mode_session->GetSelectedWindow(), window3.get());
  967. // Minimize the window should also automatically change the selected window.
  968. WindowState::Get(window3.get())->Minimize();
  969. EXPECT_EQ(capture_mode_session->GetSelectedWindow(), window1.get());
  970. // Stop the capture session to avoid CaptureModeSession from receiving more
  971. // events during test tearing down.
  972. controller->Stop();
  973. }
  974. // Tests that the capture bar is located on the root with the cursor when
  975. // starting capture mode.
  976. TEST_F(CaptureModeTest, MultiDisplayCaptureBarInitialLocation) {
  977. UpdateDisplay("800x700,801+0-800x700");
  978. auto* event_generator = GetEventGenerator();
  979. MoveMouseToAndUpdateCursorDisplay(gfx::Point(1000, 500), event_generator);
  980. auto* controller = StartImageRegionCapture();
  981. EXPECT_TRUE(gfx::Rect(801, 0, 800, 800)
  982. .Contains(GetCaptureModeBarView()->GetBoundsInScreen()));
  983. controller->Stop();
  984. MoveMouseToAndUpdateCursorDisplay(gfx::Point(100, 500), event_generator);
  985. StartImageRegionCapture();
  986. EXPECT_TRUE(gfx::Rect(800, 800).Contains(
  987. GetCaptureModeBarView()->GetBoundsInScreen()));
  988. }
  989. // Tests behavior of a capture mode session if the active display is removed.
  990. TEST_F(CaptureModeTest, DisplayRemoval) {
  991. UpdateDisplay("800x700,801+0-800x700");
  992. // Start capture mode on the secondary display.
  993. MoveMouseToAndUpdateCursorDisplay(gfx::Point(1000, 500), GetEventGenerator());
  994. auto* controller = StartImageRegionCapture();
  995. auto* session = controller->capture_mode_session();
  996. EXPECT_TRUE(gfx::Rect(801, 0, 800, 800)
  997. .Contains(GetCaptureModeBarView()->GetBoundsInScreen()));
  998. ASSERT_EQ(Shell::GetAllRootWindows()[1], session->current_root());
  999. RemoveSecondaryDisplay();
  1000. // Tests that the capture mode bar is now on the primary display.
  1001. EXPECT_TRUE(gfx::Rect(800, 800).Contains(
  1002. GetCaptureModeBarView()->GetBoundsInScreen()));
  1003. ASSERT_EQ(Shell::GetAllRootWindows()[0], session->current_root());
  1004. }
  1005. // Tests behavior of a capture mode session if the active display is removed
  1006. // and countdown running.
  1007. TEST_F(CaptureModeTest, DisplayRemovalWithCountdownVisible) {
  1008. UpdateDisplay("800x700,801+0-800x700");
  1009. // Start capture mode on the secondary display.
  1010. auto recorded_window = CreateTestWindow(gfx::Rect(1000, 200, 400, 400));
  1011. auto* controller =
  1012. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
  1013. GetEventGenerator()->MoveMouseToCenterOf(recorded_window.get());
  1014. auto* session = controller->capture_mode_session();
  1015. RemoveSecondaryDisplay();
  1016. ASSERT_EQ(Shell::GetAllRootWindows()[0], session->current_root());
  1017. // Test passes if no crash.
  1018. }
  1019. // Tests behavior of a capture mode session if the active display is removed,
  1020. // countdown running, fullscreen window, and in overview mode.
  1021. TEST_F(CaptureModeTest,
  1022. DisplayRemovalWithCountdownVisibleFullscreenWindowAndInOverview) {
  1023. UpdateDisplay("800x700,801+0-800x700");
  1024. // Start capture mode on the secondary display.
  1025. auto recorded_window = CreateTestWindow(gfx::Rect(1000, 200, 400, 400));
  1026. auto* controller =
  1027. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
  1028. GetEventGenerator()->MoveMouseToCenterOf(recorded_window.get());
  1029. // Make the window fullscreen. This is important as the corner case is
  1030. // moving a fullscreen window triggers the shelf to occur, which changes
  1031. // display metrics.
  1032. recorded_window->SetProperty(aura::client::kShowStateKey,
  1033. ui::SHOW_STATE_FULLSCREEN);
  1034. auto* session = controller->capture_mode_session();
  1035. EnterOverview();
  1036. RemoveSecondaryDisplay();
  1037. ASSERT_EQ(Shell::GetAllRootWindows()[0], session->current_root());
  1038. // Test passes if no crash.
  1039. }
  1040. // Tests that using fullscreen or window source, moving the mouse across
  1041. // displays will change the root window of the capture session.
  1042. TEST_F(CaptureModeTest, MultiDisplayFullscreenOrWindowSourceRootWindow) {
  1043. UpdateDisplay("800x700,801+0-800x700");
  1044. ASSERT_EQ(2u, Shell::GetAllRootWindows().size());
  1045. auto* event_generator = GetEventGenerator();
  1046. MoveMouseToAndUpdateCursorDisplay(gfx::Point(100, 500), event_generator);
  1047. for (auto source :
  1048. {CaptureModeSource::kFullscreen, CaptureModeSource::kWindow}) {
  1049. SCOPED_TRACE(source == CaptureModeSource::kFullscreen ? "Fullscreen source"
  1050. : "Window source");
  1051. auto* controller = StartCaptureSession(source, CaptureModeType::kImage);
  1052. auto* session = controller->capture_mode_session();
  1053. EXPECT_EQ(Shell::GetAllRootWindows()[0], session->current_root());
  1054. MoveMouseToAndUpdateCursorDisplay(gfx::Point(1000, 500), event_generator);
  1055. EXPECT_EQ(Shell::GetAllRootWindows()[1], session->current_root());
  1056. MoveMouseToAndUpdateCursorDisplay(gfx::Point(100, 500), event_generator);
  1057. EXPECT_EQ(Shell::GetAllRootWindows()[0], session->current_root());
  1058. controller->Stop();
  1059. }
  1060. }
  1061. // Tests that in region mode, moving the mouse across displays will not change
  1062. // the root window of the capture session, but clicking on a new display will.
  1063. TEST_F(CaptureModeTest, MultiDisplayRegionSourceRootWindow) {
  1064. UpdateDisplay("800x700,801+0-800x700");
  1065. ASSERT_EQ(2u, Shell::GetAllRootWindows().size());
  1066. auto* event_generator = GetEventGenerator();
  1067. MoveMouseToAndUpdateCursorDisplay(gfx::Point(100, 500), event_generator);
  1068. auto* controller = StartImageRegionCapture();
  1069. auto* session = controller->capture_mode_session();
  1070. EXPECT_EQ(Shell::GetAllRootWindows()[0], session->current_root());
  1071. // Tests that moving the mouse to the secondary display does not change the
  1072. // root.
  1073. MoveMouseToAndUpdateCursorDisplay(gfx::Point(1000, 500), event_generator);
  1074. EXPECT_EQ(Shell::GetAllRootWindows()[0], session->current_root());
  1075. // Tests that pressing the mouse changes the root. The capture bar stays on
  1076. // the primary display until the mouse is released.
  1077. event_generator->PressLeftButton();
  1078. EXPECT_EQ(Shell::GetAllRootWindows()[1], session->current_root());
  1079. EXPECT_TRUE(gfx::Rect(800, 800).Contains(
  1080. GetCaptureModeBarView()->GetBoundsInScreen()));
  1081. event_generator->ReleaseLeftButton();
  1082. EXPECT_EQ(Shell::GetAllRootWindows()[1], session->current_root());
  1083. EXPECT_TRUE(gfx::Rect(801, 0, 800, 800)
  1084. .Contains(GetCaptureModeBarView()->GetBoundsInScreen()));
  1085. }
  1086. // Tests that using touch on multi display setups works as intended. Regression
  1087. // test for https://crbug.com/1159512.
  1088. TEST_F(CaptureModeTest, MultiDisplayTouch) {
  1089. UpdateDisplay("800x700,801+0-800x700");
  1090. ASSERT_EQ(2u, Shell::GetAllRootWindows().size());
  1091. auto* controller = StartImageRegionCapture();
  1092. auto* session = controller->capture_mode_session();
  1093. ASSERT_EQ(Shell::GetAllRootWindows()[0], session->current_root());
  1094. // Touch and move your finger on the secondary display. We should switch roots
  1095. // and the region size should be as expected.
  1096. auto* event_generator = GetEventGenerator();
  1097. event_generator->PressTouch(gfx::Point(1000, 200));
  1098. event_generator->MoveTouch(gfx::Point(1200, 400));
  1099. event_generator->ReleaseTouch();
  1100. EXPECT_EQ(Shell::GetAllRootWindows()[1], session->current_root());
  1101. EXPECT_EQ(gfx::Size(200, 200), controller->user_capture_region().size());
  1102. }
  1103. TEST_F(CaptureModeTest, RegionCursorStates) {
  1104. UpdateDisplay("800x700,801+0-800x700");
  1105. using ui::mojom::CursorType;
  1106. auto* cursor_manager = Shell::Get()->cursor_manager();
  1107. auto* event_generator = GetEventGenerator();
  1108. struct {
  1109. std::string scoped_trace;
  1110. gfx::Rect display_rect;
  1111. gfx::Point point;
  1112. gfx::Rect capture_region;
  1113. } kRegionTestCases[] = {
  1114. {"primary_display", gfx::Rect(0, 0, 800, 700), gfx::Point(250, 250),
  1115. gfx::Rect(200, 200, 200, 200)},
  1116. {"external_display", gfx::Rect(801, 0, 800, 700), gfx::Point(1050, 250),
  1117. gfx::Rect(1000, 200, 200, 200)},
  1118. };
  1119. for (auto test_case : kRegionTestCases) {
  1120. SCOPED_TRACE(test_case.scoped_trace);
  1121. MoveMouseToAndUpdateCursorDisplay(test_case.point, event_generator);
  1122. const CursorType original_cursor_type = cursor_manager->GetCursor().type();
  1123. EXPECT_FALSE(cursor_manager->IsCursorLocked());
  1124. auto* controller = StartImageRegionCapture();
  1125. EXPECT_TRUE(test_case.display_rect.Contains(
  1126. GetCaptureModeBarView()->GetBoundsInScreen()));
  1127. auto outside_point = test_case.capture_region.origin();
  1128. outside_point.Offset(-10, -10);
  1129. // Clear the previous region if any.
  1130. event_generator->MoveMouseTo(outside_point);
  1131. event_generator->ClickLeftButton();
  1132. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1133. EXPECT_EQ(CursorType::kCell, cursor_manager->GetCursor().type());
  1134. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1135. // Makes sure that the cursor is updated when the user releases the region
  1136. // select and is still hovering in the same location.
  1137. SelectRegion(test_case.capture_region);
  1138. EXPECT_EQ(CursorType::kSouthEastResize, cursor_manager->GetCursor().type());
  1139. // Verify that all of the `FineTunePosition` locations have the correct
  1140. // cursor when hovered over both in primary display and external display.
  1141. event_generator->MoveMouseTo(test_case.capture_region.origin());
  1142. EXPECT_EQ(CursorType::kNorthWestResize, cursor_manager->GetCursor().type());
  1143. event_generator->MoveMouseTo(test_case.capture_region.top_center());
  1144. EXPECT_EQ(CursorType::kNorthSouthResize,
  1145. cursor_manager->GetCursor().type());
  1146. event_generator->MoveMouseTo(test_case.capture_region.top_right());
  1147. EXPECT_EQ(CursorType::kNorthEastResize, cursor_manager->GetCursor().type());
  1148. event_generator->MoveMouseTo(test_case.capture_region.right_center());
  1149. EXPECT_EQ(CursorType::kEastWestResize, cursor_manager->GetCursor().type());
  1150. event_generator->MoveMouseTo(test_case.capture_region.bottom_right());
  1151. EXPECT_EQ(CursorType::kSouthEastResize, cursor_manager->GetCursor().type());
  1152. event_generator->MoveMouseTo(test_case.capture_region.bottom_center());
  1153. EXPECT_EQ(CursorType::kNorthSouthResize,
  1154. cursor_manager->GetCursor().type());
  1155. event_generator->MoveMouseTo(test_case.capture_region.bottom_left());
  1156. EXPECT_EQ(CursorType::kSouthWestResize, cursor_manager->GetCursor().type());
  1157. event_generator->MoveMouseTo(test_case.capture_region.left_center());
  1158. EXPECT_EQ(CursorType::kEastWestResize, cursor_manager->GetCursor().type());
  1159. // Tests that within the bounds of the selected region, the cursor is a hand
  1160. // when hovering over the capture button, otherwise it is a
  1161. // multi-directional move cursor.
  1162. event_generator->MoveMouseTo(test_case.point);
  1163. EXPECT_EQ(CursorType::kMove, cursor_manager->GetCursor().type());
  1164. event_generator->MoveMouseTo(test_case.capture_region.CenterPoint());
  1165. EXPECT_EQ(CursorType::kHand, cursor_manager->GetCursor().type());
  1166. // Tests that the cursor changes to a cell type when hovering over the
  1167. // unselected region.
  1168. event_generator->MoveMouseTo(outside_point);
  1169. EXPECT_EQ(CursorType::kCell, cursor_manager->GetCursor().type());
  1170. // Check that cursor is unlocked when changing sources, and that the cursor
  1171. // changes to a pointer when hovering over the capture mode bar.
  1172. event_generator->MoveMouseTo(
  1173. GetRegionToggleButton()->GetBoundsInScreen().CenterPoint());
  1174. EXPECT_EQ(CursorType::kPointer, cursor_manager->GetCursor().type());
  1175. event_generator->MoveMouseTo(
  1176. GetWindowToggleButton()->GetBoundsInScreen().CenterPoint());
  1177. EXPECT_EQ(CursorType::kPointer, cursor_manager->GetCursor().type());
  1178. event_generator->ClickLeftButton();
  1179. ASSERT_EQ(CaptureModeSource::kWindow, controller->source());
  1180. // The event on the capture bar to change capture source will still keep the
  1181. // cursor locked.
  1182. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1183. EXPECT_EQ(CursorType::kPointer, cursor_manager->GetCursor().type());
  1184. // Tests that on changing back to region capture mode, the cursor becomes
  1185. // locked, and is still a pointer type over the bar, whilst a cell cursor
  1186. // otherwise (not over the selected region).
  1187. event_generator->MoveMouseTo(
  1188. GetRegionToggleButton()->GetBoundsInScreen().CenterPoint());
  1189. event_generator->ClickLeftButton();
  1190. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1191. EXPECT_EQ(CursorType::kPointer, cursor_manager->GetCursor().type());
  1192. // Tests that clicking on the button again doesn't change the cursor.
  1193. event_generator->ClickLeftButton();
  1194. EXPECT_EQ(CursorType::kPointer, cursor_manager->GetCursor().type());
  1195. event_generator->MoveMouseTo(outside_point);
  1196. EXPECT_EQ(CursorType::kCell, cursor_manager->GetCursor().type());
  1197. // Tests that when exiting capture mode that the cursor is restored to its
  1198. // original state.
  1199. controller->Stop();
  1200. EXPECT_FALSE(controller->IsActive());
  1201. EXPECT_FALSE(cursor_manager->IsCursorLocked());
  1202. EXPECT_EQ(original_cursor_type, cursor_manager->GetCursor().type());
  1203. }
  1204. // Tests the cursor state in tablet mode.
  1205. auto* controller = StartImageRegionCapture();
  1206. // Enter tablet mode, the cursor should be hidden.
  1207. SwitchToTabletMode();
  1208. EXPECT_FALSE(cursor_manager->IsCursorVisible());
  1209. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1210. // Move mouse but it should still be invisible.
  1211. event_generator->MoveMouseTo(gfx::Point(100, 100));
  1212. EXPECT_FALSE(cursor_manager->IsCursorVisible());
  1213. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1214. // Return to clamshell mode, mouse should appear again.
  1215. LeaveTabletMode();
  1216. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1217. EXPECT_EQ(CursorType::kCell, cursor_manager->GetCursor().type());
  1218. controller->Stop();
  1219. }
  1220. // Regression testing for https://crbug.com/1334824.
  1221. TEST_F(CaptureModeTest, CursorShouldNotChangeWhileAdjustingRegion) {
  1222. UpdateDisplay("800x600");
  1223. using ui::mojom::CursorType;
  1224. auto* cursor_manager = Shell::Get()->cursor_manager();
  1225. auto* event_generator = GetEventGenerator();
  1226. EXPECT_FALSE(cursor_manager->IsCursorLocked());
  1227. StartImageRegionCapture();
  1228. event_generator->MoveMouseTo(gfx::Point(200, 200));
  1229. EXPECT_EQ(CursorType::kCell, cursor_manager->GetCursor().type());
  1230. event_generator->PressLeftButton();
  1231. event_generator->MoveMouseTo(gfx::Point(300, 300));
  1232. EXPECT_EQ(CursorType::kSouthEastResize, cursor_manager->GetCursor().type());
  1233. // Drag the region by moving the cursor to the center point of the capture bar
  1234. // and expect that it doesn't change back to a pointer.
  1235. const auto capture_bar_center =
  1236. GetCaptureModeBarView()->GetBoundsInScreen().CenterPoint();
  1237. event_generator->MoveMouseTo(capture_bar_center);
  1238. EXPECT_EQ(CursorType::kSouthEastResize, cursor_manager->GetCursor().type());
  1239. }
  1240. TEST_F(CaptureModeTest, FullscreenCursorStates) {
  1241. using ui::mojom::CursorType;
  1242. auto* cursor_manager = Shell::Get()->cursor_manager();
  1243. CursorType original_cursor_type = cursor_manager->GetCursor().type();
  1244. EXPECT_FALSE(cursor_manager->IsCursorLocked());
  1245. EXPECT_EQ(CursorType::kPointer, original_cursor_type);
  1246. auto* event_generator = GetEventGenerator();
  1247. CaptureModeController* controller = StartCaptureSession(
  1248. CaptureModeSource::kFullscreen, CaptureModeType::kImage);
  1249. EXPECT_EQ(controller->type(), CaptureModeType::kImage);
  1250. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1251. event_generator->MoveMouseTo(gfx::Point(175, 175));
  1252. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1253. // Use image capture icon as the mouse cursor icon in image capture mode.
  1254. EXPECT_EQ(CursorType::kCustom, cursor_manager->GetCursor().type());
  1255. CaptureModeSessionTestApi test_api(controller->capture_mode_session());
  1256. EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kImage));
  1257. // Move the mouse over to capture label widget won't change the cursor since
  1258. // it's a label not a label button.
  1259. event_generator->MoveMouseTo(test_api.GetCaptureLabelWidget()
  1260. ->GetWindowBoundsInScreen()
  1261. .CenterPoint());
  1262. EXPECT_EQ(CursorType::kCustom, cursor_manager->GetCursor().type());
  1263. EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kImage));
  1264. // Use pointer mouse if the event is on the capture bar.
  1265. ClickOnView(GetVideoToggleButton(), event_generator);
  1266. EXPECT_EQ(controller->type(), CaptureModeType::kVideo);
  1267. EXPECT_EQ(CursorType::kPointer, cursor_manager->GetCursor().type());
  1268. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1269. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1270. // Use video record icon as the mouse cursor icon in video recording mode.
  1271. event_generator->MoveMouseTo(gfx::Point(175, 175));
  1272. EXPECT_EQ(CursorType::kCustom, cursor_manager->GetCursor().type());
  1273. EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kVideo));
  1274. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1275. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1276. // Enter tablet mode, the cursor should be hidden.
  1277. // To avoid flaky failures due to mouse devices blocking entering tablet mode,
  1278. // we detach all mouse devices. This shouldn't affect testing the cursor
  1279. // status.
  1280. SwitchToTabletMode();
  1281. EXPECT_FALSE(cursor_manager->IsCursorVisible());
  1282. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1283. // Exit tablet mode, the cursor should appear again.
  1284. LeaveTabletMode();
  1285. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1286. EXPECT_EQ(CursorType::kCustom, cursor_manager->GetCursor().type());
  1287. EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kVideo));
  1288. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1289. // Stop capture mode, the cursor should be restored to its original state.
  1290. controller->Stop();
  1291. EXPECT_FALSE(controller->IsActive());
  1292. EXPECT_FALSE(cursor_manager->IsCursorLocked());
  1293. EXPECT_EQ(original_cursor_type, cursor_manager->GetCursor().type());
  1294. // Test that if we're in tablet mode for dev purpose, the cursor should still
  1295. // be visible.
  1296. Shell::Get()->tablet_mode_controller()->SetEnabledForDev(true);
  1297. StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kImage);
  1298. EXPECT_EQ(controller->type(), CaptureModeType::kImage);
  1299. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1300. event_generator->MoveMouseTo(gfx::Point(175, 175));
  1301. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1302. }
  1303. TEST_F(CaptureModeTest, WindowCursorStates) {
  1304. using ui::mojom::CursorType;
  1305. std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(200, 200)));
  1306. auto* cursor_manager = Shell::Get()->cursor_manager();
  1307. CursorType original_cursor_type = cursor_manager->GetCursor().type();
  1308. EXPECT_FALSE(cursor_manager->IsCursorLocked());
  1309. EXPECT_EQ(CursorType::kPointer, original_cursor_type);
  1310. auto* event_generator = GetEventGenerator();
  1311. CaptureModeController* controller =
  1312. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kImage);
  1313. EXPECT_EQ(controller->type(), CaptureModeType::kImage);
  1314. // If the mouse is above the window, use the image capture icon.
  1315. event_generator->MoveMouseTo(gfx::Point(150, 150));
  1316. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1317. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1318. EXPECT_EQ(CursorType::kCustom, cursor_manager->GetCursor().type());
  1319. CaptureModeSessionTestApi test_api(controller->capture_mode_session());
  1320. EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kImage));
  1321. // If the mouse is not above the window, use a pointer.
  1322. event_generator->MoveMouseTo(gfx::Point(300, 300));
  1323. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1324. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1325. EXPECT_EQ(CursorType::kPointer, cursor_manager->GetCursor().type());
  1326. // Use pointer mouse if the event is on the capture bar.
  1327. ClickOnView(GetVideoToggleButton(), event_generator);
  1328. EXPECT_EQ(controller->type(), CaptureModeType::kVideo);
  1329. EXPECT_EQ(CursorType::kPointer, cursor_manager->GetCursor().type());
  1330. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1331. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1332. // Use video record icon as the mouse cursor icon in video recording mode.
  1333. event_generator->MoveMouseTo(gfx::Point(150, 150));
  1334. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1335. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1336. EXPECT_EQ(CursorType::kCustom, cursor_manager->GetCursor().type());
  1337. EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kVideo));
  1338. // If the mouse is not above the window, use the original mouse cursor.
  1339. event_generator->MoveMouseTo(gfx::Point(300, 300));
  1340. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1341. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1342. EXPECT_EQ(CursorType::kPointer, cursor_manager->GetCursor().type());
  1343. // Move above the window again, the cursor should change back to the video
  1344. // record icon.
  1345. event_generator->MoveMouseTo(gfx::Point(150, 150));
  1346. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1347. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1348. EXPECT_EQ(CursorType::kCustom, cursor_manager->GetCursor().type());
  1349. EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kVideo));
  1350. // Enter tablet mode, the cursor should be hidden.
  1351. // To avoid flaky failures due to mouse devices blocking entering tablet mode,
  1352. // we detach all mouse devices. This shouldn't affect testing the cursor
  1353. // status.
  1354. SwitchToTabletMode();
  1355. EXPECT_FALSE(cursor_manager->IsCursorVisible());
  1356. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1357. // Exit tablet mode, the cursor should appear again.
  1358. LeaveTabletMode();
  1359. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1360. EXPECT_EQ(CursorType::kCustom, cursor_manager->GetCursor().type());
  1361. EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kVideo));
  1362. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1363. // Stop capture mode, the cursor should be restored to its original state.
  1364. controller->Stop();
  1365. EXPECT_FALSE(controller->IsActive());
  1366. EXPECT_FALSE(cursor_manager->IsCursorLocked());
  1367. EXPECT_EQ(original_cursor_type, cursor_manager->GetCursor().type());
  1368. }
  1369. // Tests that nothing crashes when windows are destroyed while being observed.
  1370. TEST_F(CaptureModeTest, WindowDestruction) {
  1371. using ui::mojom::CursorType;
  1372. // Create 2 windows that overlap with each other.
  1373. const gfx::Rect bounds1(0, 0, 200, 200);
  1374. const gfx::Rect bounds2(150, 150, 200, 200);
  1375. const gfx::Rect bounds3(50, 50, 200, 200);
  1376. std::unique_ptr<aura::Window> window1(CreateTestWindow(bounds1));
  1377. std::unique_ptr<aura::Window> window2(CreateTestWindow(bounds2));
  1378. auto* cursor_manager = Shell::Get()->cursor_manager();
  1379. CursorType original_cursor_type = cursor_manager->GetCursor().type();
  1380. EXPECT_FALSE(cursor_manager->IsCursorLocked());
  1381. EXPECT_EQ(CursorType::kPointer, original_cursor_type);
  1382. // Start capture session with Image type, so we have a custom cursor.
  1383. auto* event_generator = GetEventGenerator();
  1384. CaptureModeController* controller =
  1385. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kImage);
  1386. EXPECT_EQ(controller->type(), CaptureModeType::kImage);
  1387. // If the mouse is above the window, use the image capture icon.
  1388. event_generator->MoveMouseToCenterOf(window2.get());
  1389. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1390. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1391. EXPECT_EQ(CursorType::kCustom, cursor_manager->GetCursor().type());
  1392. auto* capture_mode_session = controller->capture_mode_session();
  1393. CaptureModeSessionTestApi test_api(capture_mode_session);
  1394. EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kImage));
  1395. // Destroy the window while hovering. There is no window underneath, so it
  1396. // should revert back to a pointer.
  1397. window2.reset();
  1398. EXPECT_TRUE(cursor_manager->IsCursorLocked());
  1399. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1400. EXPECT_EQ(CursorType::kPointer, cursor_manager->GetCursor().type());
  1401. // Destroy the window while mouse is in a pressed state. Cursor should revert
  1402. // back to the original cursor.
  1403. std::unique_ptr<aura::Window> window3(CreateTestWindow(bounds2));
  1404. EXPECT_EQ(CursorType::kCustom, cursor_manager->GetCursor().type());
  1405. EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kImage));
  1406. event_generator->PressLeftButton();
  1407. EXPECT_EQ(CursorType::kCustom, cursor_manager->GetCursor().type());
  1408. EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kImage));
  1409. window3.reset();
  1410. event_generator->ReleaseLeftButton();
  1411. EXPECT_EQ(original_cursor_type, cursor_manager->GetCursor().type());
  1412. // When hovering over a window, if it is destroyed and there is another window
  1413. // under the cursor location in screen, then the selected window is
  1414. // automatically updated.
  1415. std::unique_ptr<aura::Window> window4(CreateTestWindow(bounds3));
  1416. event_generator->MoveMouseToCenterOf(window4.get());
  1417. EXPECT_EQ(CursorType::kCustom, cursor_manager->GetCursor().type());
  1418. EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kImage));
  1419. EXPECT_EQ(capture_mode_session->GetSelectedWindow(), window4.get());
  1420. window4.reset();
  1421. EXPECT_EQ(CursorType::kCustom, cursor_manager->GetCursor().type());
  1422. EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kImage));
  1423. // Check to see it's observing window1.
  1424. EXPECT_EQ(capture_mode_session->GetSelectedWindow(), window1.get());
  1425. // Cursor is over a window in the mouse pressed state. If the window is
  1426. // destroyed and there is another window under the cursor, the selected window
  1427. // is updated and the new selected window is captured.
  1428. std::unique_ptr<aura::Window> window5(CreateTestWindow(bounds3));
  1429. EXPECT_EQ(capture_mode_session->GetSelectedWindow(), window5.get());
  1430. event_generator->PressLeftButton();
  1431. window5.reset();
  1432. EXPECT_EQ(CursorType::kCustom, cursor_manager->GetCursor().type());
  1433. EXPECT_TRUE(test_api.IsUsingCustomCursor(CaptureModeType::kImage));
  1434. EXPECT_EQ(capture_mode_session->GetSelectedWindow(), window1.get());
  1435. event_generator->ReleaseLeftButton();
  1436. EXPECT_FALSE(controller->IsActive());
  1437. }
  1438. TEST_F(CaptureModeTest, CursorUpdatedOnDisplayRotation) {
  1439. using ui::mojom::CursorType;
  1440. UpdateDisplay("600x400");
  1441. const int64_t display_id =
  1442. display::Screen::GetScreen()->GetPrimaryDisplay().id();
  1443. display::SetInternalDisplayIds({display_id});
  1444. ScreenOrientationControllerTestApi orientation_test_api(
  1445. Shell::Get()->screen_orientation_controller());
  1446. auto* event_generator = GetEventGenerator();
  1447. auto* cursor_manager = Shell::Get()->cursor_manager();
  1448. CaptureModeController* controller = StartCaptureSession(
  1449. CaptureModeSource::kFullscreen, CaptureModeType::kImage);
  1450. event_generator->MoveMouseTo(gfx::Point(175, 175));
  1451. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1452. // Use image capture icon as the mouse cursor icon in image capture mode.
  1453. const ui::Cursor landscape_cursor = cursor_manager->GetCursor();
  1454. EXPECT_EQ(CursorType::kCustom, landscape_cursor.type());
  1455. CaptureModeSessionTestApi session_test_api(
  1456. controller->capture_mode_session());
  1457. EXPECT_TRUE(session_test_api.IsUsingCustomCursor(CaptureModeType::kImage));
  1458. // Rotate the screen.
  1459. orientation_test_api.SetDisplayRotation(
  1460. display::Display::ROTATE_270, display::Display::RotationSource::ACTIVE);
  1461. const ui::Cursor portrait_cursor = cursor_manager->GetCursor();
  1462. EXPECT_TRUE(session_test_api.IsUsingCustomCursor(CaptureModeType::kImage));
  1463. EXPECT_NE(landscape_cursor, portrait_cursor);
  1464. }
  1465. // Tests that in Region mode, cursor compositing is used instead of the system
  1466. // cursor when the cursor is being dragged.
  1467. TEST_F(CaptureModeTest, RegionDragCursorCompositing) {
  1468. auto* event_generator = GetEventGenerator();
  1469. auto* session = StartImageRegionCapture()->capture_mode_session();
  1470. auto* cursor_manager = Shell::Get()->cursor_manager();
  1471. // Initially cursor should be visible and cursor compositing is not enabled.
  1472. EXPECT_FALSE(session->is_drag_in_progress());
  1473. EXPECT_FALSE(IsCursorCompositingEnabled());
  1474. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  1475. const gfx::Rect target_region(gfx::Rect(200, 200, 200, 200));
  1476. // For each start and end point try dragging and verify that cursor
  1477. // compositing is functioning as expected.
  1478. struct {
  1479. std::string trace;
  1480. gfx::Point start_point;
  1481. gfx::Point end_point;
  1482. } kDragCases[] = {
  1483. {"initial_region", target_region.origin(), target_region.bottom_right()},
  1484. {"edge_resize", target_region.right_center(),
  1485. gfx::Point(target_region.right_center() + gfx::Vector2d(50, 0))},
  1486. {"corner_resize", target_region.origin(), gfx::Point(175, 175)},
  1487. {"move", gfx::Point(250, 250), gfx::Point(300, 300)},
  1488. };
  1489. for (auto test_case : kDragCases) {
  1490. SCOPED_TRACE(test_case.trace);
  1491. event_generator->MoveMouseTo(test_case.start_point);
  1492. event_generator->PressLeftButton();
  1493. EXPECT_TRUE(session->is_drag_in_progress());
  1494. EXPECT_TRUE(IsCursorCompositingEnabled());
  1495. event_generator->MoveMouseTo(test_case.end_point);
  1496. EXPECT_TRUE(session->is_drag_in_progress());
  1497. EXPECT_TRUE(IsCursorCompositingEnabled());
  1498. event_generator->ReleaseLeftButton();
  1499. EXPECT_FALSE(session->is_drag_in_progress());
  1500. EXPECT_FALSE(IsCursorCompositingEnabled());
  1501. }
  1502. }
  1503. // Test that during countdown, capture mode session should not handle any
  1504. // incoming input events.
  1505. TEST_F(CaptureModeTest, DoNotHandleEventDuringCountDown) {
  1506. // We need a non-zero duration to avoid infinite loop on countdown.
  1507. ui::ScopedAnimationDurationScaleMode animation_scale(
  1508. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  1509. // Create 2 windows that overlap with each other.
  1510. std::unique_ptr<aura::Window> window1(CreateTestWindow(gfx::Rect(200, 200)));
  1511. std::unique_ptr<aura::Window> window2(
  1512. CreateTestWindow(gfx::Rect(150, 150, 200, 200)));
  1513. auto* controller = CaptureModeController::Get();
  1514. controller->SetSource(CaptureModeSource::kWindow);
  1515. controller->SetType(CaptureModeType::kVideo);
  1516. controller->Start(CaptureModeEntryType::kQuickSettings);
  1517. EXPECT_TRUE(controller->IsActive());
  1518. auto* event_generator = GetEventGenerator();
  1519. event_generator->MoveMouseToCenterOf(window1.get());
  1520. auto* capture_mode_session = controller->capture_mode_session();
  1521. EXPECT_EQ(capture_mode_session->GetSelectedWindow(), window1.get());
  1522. // Start video recording. Countdown should start at this moment.
  1523. event_generator->ClickLeftButton();
  1524. // Now move the mouse onto the other window, we should not change the captured
  1525. // window during countdown.
  1526. event_generator->MoveMouseToCenterOf(window2.get());
  1527. EXPECT_EQ(capture_mode_session->GetSelectedWindow(), window1.get());
  1528. EXPECT_NE(capture_mode_session->GetSelectedWindow(), window2.get());
  1529. WaitForRecordingToStart();
  1530. }
  1531. // Test that during countdown, window changes or crashes are handled.
  1532. TEST_F(CaptureModeTest, WindowChangesDuringCountdown) {
  1533. // We need a non-zero duration to avoid infinite loop on countdown.
  1534. ui::ScopedAnimationDurationScaleMode animation_scale(
  1535. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  1536. std::unique_ptr<aura::Window> window;
  1537. auto* controller = CaptureModeController::Get();
  1538. controller->SetSource(CaptureModeSource::kWindow);
  1539. controller->SetType(CaptureModeType::kVideo);
  1540. auto start_countdown = [this, &window, controller]() {
  1541. window = CreateTestWindow(gfx::Rect(200, 200));
  1542. controller->Start(CaptureModeEntryType::kQuickSettings);
  1543. auto* event_generator = GetEventGenerator();
  1544. event_generator->MoveMouseToCenterOf(window.get());
  1545. event_generator->ClickLeftButton();
  1546. EXPECT_TRUE(controller->IsActive());
  1547. EXPECT_FALSE(controller->is_recording_in_progress());
  1548. };
  1549. // Destroying or minimizing the observed window terminates the countdown and
  1550. // exits capture mode.
  1551. start_countdown();
  1552. window.reset();
  1553. EXPECT_FALSE(controller->IsActive());
  1554. start_countdown();
  1555. WindowState::Get(window.get())->Minimize();
  1556. EXPECT_FALSE(controller->IsActive());
  1557. // Activation changes (such as opening overview) should not terminate the
  1558. // countdown.
  1559. start_countdown();
  1560. EnterOverview();
  1561. EXPECT_TRUE(controller->IsActive());
  1562. EXPECT_FALSE(controller->is_recording_in_progress());
  1563. // Wait for countdown to finish and check that recording starts.
  1564. WaitForRecordingToStart();
  1565. EXPECT_FALSE(controller->IsActive());
  1566. EXPECT_TRUE(controller->is_recording_in_progress());
  1567. }
  1568. // Tests that metrics are recorded properly for capture mode entry points.
  1569. TEST_F(CaptureModeTest, CaptureModeEntryPointHistograms) {
  1570. constexpr char kClamshellHistogram[] =
  1571. "Ash.CaptureModeController.EntryPoint.ClamshellMode";
  1572. constexpr char kTabletHistogram[] =
  1573. "Ash.CaptureModeController.EntryPoint.TabletMode";
  1574. base::HistogramTester histogram_tester;
  1575. auto* controller = CaptureModeController::Get();
  1576. // Test the various entry points in clamshell mode.
  1577. controller->Start(CaptureModeEntryType::kAccelTakeWindowScreenshot);
  1578. histogram_tester.ExpectBucketCount(
  1579. kClamshellHistogram, CaptureModeEntryType::kAccelTakeWindowScreenshot, 1);
  1580. controller->Stop();
  1581. controller->Start(CaptureModeEntryType::kAccelTakePartialScreenshot);
  1582. histogram_tester.ExpectBucketCount(
  1583. kClamshellHistogram, CaptureModeEntryType::kAccelTakePartialScreenshot,
  1584. 1);
  1585. controller->Stop();
  1586. controller->Start(CaptureModeEntryType::kQuickSettings);
  1587. histogram_tester.ExpectBucketCount(kClamshellHistogram,
  1588. CaptureModeEntryType::kQuickSettings, 1);
  1589. controller->Stop();
  1590. controller->Start(CaptureModeEntryType::kStylusPalette);
  1591. histogram_tester.ExpectBucketCount(kClamshellHistogram,
  1592. CaptureModeEntryType::kStylusPalette, 1);
  1593. controller->Stop();
  1594. // Enter tablet mode and test the various entry points in tablet mode.
  1595. auto* tablet_mode_controller = Shell::Get()->tablet_mode_controller();
  1596. tablet_mode_controller->SetEnabledForTest(true);
  1597. ASSERT_TRUE(tablet_mode_controller->InTabletMode());
  1598. controller->Start(CaptureModeEntryType::kAccelTakeWindowScreenshot);
  1599. histogram_tester.ExpectBucketCount(
  1600. kTabletHistogram, CaptureModeEntryType::kAccelTakeWindowScreenshot, 1);
  1601. controller->Stop();
  1602. controller->Start(CaptureModeEntryType::kAccelTakePartialScreenshot);
  1603. histogram_tester.ExpectBucketCount(
  1604. kTabletHistogram, CaptureModeEntryType::kAccelTakePartialScreenshot, 1);
  1605. controller->Stop();
  1606. controller->Start(CaptureModeEntryType::kQuickSettings);
  1607. histogram_tester.ExpectBucketCount(kTabletHistogram,
  1608. CaptureModeEntryType::kQuickSettings, 1);
  1609. controller->Stop();
  1610. controller->Start(CaptureModeEntryType::kStylusPalette);
  1611. histogram_tester.ExpectBucketCount(kTabletHistogram,
  1612. CaptureModeEntryType::kStylusPalette, 1);
  1613. controller->Stop();
  1614. // Check total counts for each histogram to ensure calls aren't counted in
  1615. // multiple buckets.
  1616. histogram_tester.ExpectTotalCount(kClamshellHistogram, 4);
  1617. histogram_tester.ExpectTotalCount(kTabletHistogram, 4);
  1618. // Check that histogram isn't counted if we don't actually enter capture mode.
  1619. controller->Start(CaptureModeEntryType::kAccelTakePartialScreenshot);
  1620. histogram_tester.ExpectBucketCount(
  1621. kTabletHistogram, CaptureModeEntryType::kAccelTakePartialScreenshot, 2);
  1622. controller->Start(CaptureModeEntryType::kAccelTakePartialScreenshot);
  1623. histogram_tester.ExpectBucketCount(
  1624. kTabletHistogram, CaptureModeEntryType::kAccelTakePartialScreenshot, 2);
  1625. }
  1626. // Verifies that the video notification will show the same thumbnail image as
  1627. // sent by recording service.
  1628. TEST_F(CaptureModeTest, VideoNotificationThumbnail) {
  1629. auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  1630. CaptureModeType::kVideo);
  1631. StartVideoRecordingImmediately();
  1632. EXPECT_TRUE(controller->is_recording_in_progress());
  1633. CaptureModeTestApi().FlushRecordingServiceForTesting();
  1634. auto* test_delegate =
  1635. static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
  1636. // Request and wait for a video frame so that the recording service can use it
  1637. // to create a video thumbnail.
  1638. test_delegate->RequestAndWaitForVideoFrame();
  1639. SkBitmap service_thumbnail =
  1640. gfx::Image(test_delegate->GetVideoThumbnail()).AsBitmap();
  1641. EXPECT_FALSE(service_thumbnail.drawsNothing());
  1642. CaptureNotificationWaiter waiter;
  1643. controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
  1644. EXPECT_FALSE(controller->is_recording_in_progress());
  1645. waiter.Wait();
  1646. // Verify that the service's thumbnail is the same image shown in the
  1647. // notification shown when recording ends.
  1648. const message_center::Notification* notification = GetPreviewNotification();
  1649. EXPECT_TRUE(notification);
  1650. EXPECT_FALSE(notification->image().IsEmpty());
  1651. const SkBitmap notification_thumbnail = notification->image().AsBitmap();
  1652. EXPECT_TRUE(
  1653. gfx::test::AreBitmapsEqual(notification_thumbnail, service_thumbnail));
  1654. }
  1655. TEST_F(CaptureModeTest, LowDriveFsSpace) {
  1656. auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  1657. CaptureModeType::kVideo);
  1658. const base::FilePath drive_fs_folder = CreateFolderOnDriveFS("test");
  1659. controller->SetCustomCaptureFolder(drive_fs_folder);
  1660. auto* test_delegate =
  1661. static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
  1662. // Simulate low DriveFS free space by setting it to e.g. 200 MB.
  1663. test_delegate->set_fake_drive_fs_free_bytes(200 * 1024 * 1024);
  1664. base::HistogramTester histogram_tester;
  1665. StartVideoRecordingImmediately();
  1666. EXPECT_TRUE(controller->is_recording_in_progress());
  1667. CaptureModeTestApi().FlushRecordingServiceForTesting();
  1668. test_delegate->RequestAndWaitForVideoFrame();
  1669. // Recording should end immediately due to a low Drive FS free space.
  1670. WaitForCaptureFileToBeSaved();
  1671. histogram_tester.ExpectBucketCount(
  1672. kEndRecordingReasonInClamshellHistogramName,
  1673. EndRecordingReason::kLowDriveFsQuota, 1);
  1674. }
  1675. TEST_F(CaptureModeTest, WindowRecordingCaptureId) {
  1676. auto window = CreateTestWindow(gfx::Rect(200, 200));
  1677. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
  1678. auto* event_generator = GetEventGenerator();
  1679. event_generator->MoveMouseToCenterOf(window.get());
  1680. auto* controller = CaptureModeController::Get();
  1681. StartVideoRecordingImmediately();
  1682. EXPECT_TRUE(controller->is_recording_in_progress());
  1683. // The window should have a valid capture ID.
  1684. EXPECT_TRUE(window->subtree_capture_id().is_valid());
  1685. // Once recording ends, the window should no longer be marked as capturable.
  1686. controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
  1687. EXPECT_FALSE(controller->is_recording_in_progress());
  1688. EXPECT_FALSE(window->subtree_capture_id().is_valid());
  1689. }
  1690. TEST_F(CaptureModeTest, ClosingDimmedWidgetAboveRecordedWindow) {
  1691. views::Widget* widget = TestWidgetBuilder().BuildOwnedByNativeWidget();
  1692. auto* window = widget->GetNativeWindow();
  1693. auto recorded_window = CreateTestWindow(gfx::Rect(200, 200));
  1694. auto* controller = StartSessionAndRecordWindow(recorded_window.get());
  1695. EXPECT_TRUE(controller->is_recording_in_progress());
  1696. auto* recording_watcher = controller->video_recording_watcher_for_testing();
  1697. // Activate the window so that it becomes on top of the recorded window, and
  1698. // expect it gets dimmed.
  1699. wm::ActivateWindow(window);
  1700. EXPECT_TRUE(recording_watcher->IsWindowDimmedForTesting(window));
  1701. // Close the widget, this should not lead to any use-after-free. See
  1702. // https://crbug.com/1273197.
  1703. widget->Close();
  1704. }
  1705. TEST_F(CaptureModeTest, DimmingOfUnRecordedWindows) {
  1706. auto win1 = CreateTestWindow(gfx::Rect(200, 200));
  1707. auto win2 = CreateTestWindow(gfx::Rect(200, 200));
  1708. auto recorded_window = CreateTestWindow(gfx::Rect(200, 200));
  1709. auto* controller = StartSessionAndRecordWindow(recorded_window.get());
  1710. auto* recording_watcher = controller->video_recording_watcher_for_testing();
  1711. auto* shield_layer = recording_watcher->layer();
  1712. // Since the recorded window is the top most, no windows should be
  1713. // individually dimmed.
  1714. EXPECT_TRUE(recording_watcher->should_paint_layer());
  1715. EXPECT_TRUE(IsLayerStackedRightBelow(shield_layer, recorded_window->layer()));
  1716. EXPECT_FALSE(
  1717. recording_watcher->IsWindowDimmedForTesting(recorded_window.get()));
  1718. EXPECT_FALSE(recording_watcher->IsWindowDimmedForTesting(win1.get()));
  1719. EXPECT_FALSE(recording_watcher->IsWindowDimmedForTesting(win2.get()));
  1720. // Activating |win1| brings it to the front of the shield, so it should be
  1721. // dimmed separately.
  1722. wm::ActivateWindow(win1.get());
  1723. EXPECT_TRUE(recording_watcher->should_paint_layer());
  1724. EXPECT_TRUE(IsLayerStackedRightBelow(shield_layer, recorded_window->layer()));
  1725. EXPECT_FALSE(
  1726. recording_watcher->IsWindowDimmedForTesting(recorded_window.get()));
  1727. EXPECT_TRUE(recording_watcher->IsWindowDimmedForTesting(win1.get()));
  1728. EXPECT_FALSE(recording_watcher->IsWindowDimmedForTesting(win2.get()));
  1729. // Similarly for |win2|.
  1730. wm::ActivateWindow(win2.get());
  1731. EXPECT_TRUE(recording_watcher->should_paint_layer());
  1732. EXPECT_TRUE(IsLayerStackedRightBelow(shield_layer, recorded_window->layer()));
  1733. EXPECT_FALSE(
  1734. recording_watcher->IsWindowDimmedForTesting(recorded_window.get()));
  1735. EXPECT_TRUE(recording_watcher->IsWindowDimmedForTesting(win1.get()));
  1736. EXPECT_TRUE(recording_watcher->IsWindowDimmedForTesting(win2.get()));
  1737. // Minimizing the recorded window should stop painting the shield, and the
  1738. // dimmers should be removed.
  1739. WindowState::Get(recorded_window.get())->Minimize();
  1740. EXPECT_FALSE(recording_watcher->should_paint_layer());
  1741. EXPECT_FALSE(recording_watcher->IsWindowDimmedForTesting(win1.get()));
  1742. EXPECT_FALSE(recording_watcher->IsWindowDimmedForTesting(win2.get()));
  1743. // Activating the recorded window again unminimizes the window, which will
  1744. // reenable painting the shield.
  1745. wm::ActivateWindow(recorded_window.get());
  1746. EXPECT_FALSE(recording_watcher->IsWindowDimmedForTesting(win1.get()));
  1747. EXPECT_FALSE(recording_watcher->IsWindowDimmedForTesting(win2.get()));
  1748. EXPECT_FALSE(WindowState::Get(recorded_window.get())->IsMinimized());
  1749. EXPECT_TRUE(recording_watcher->should_paint_layer());
  1750. // Destroying a dimmed window is correctly tracked.
  1751. wm::ActivateWindow(win2.get());
  1752. EXPECT_TRUE(recording_watcher->IsWindowDimmedForTesting(win2.get()));
  1753. win2.reset();
  1754. EXPECT_FALSE(recording_watcher->IsWindowDimmedForTesting(win2.get()));
  1755. }
  1756. TEST_F(CaptureModeTest, DimmingWithDesks) {
  1757. auto recorded_window = CreateAppWindow(gfx::Rect(250, 100));
  1758. auto* controller = StartSessionAndRecordWindow(recorded_window.get());
  1759. auto* recording_watcher = controller->video_recording_watcher_for_testing();
  1760. EXPECT_TRUE(recording_watcher->should_paint_layer());
  1761. auto* desks_controller = DesksController::Get();
  1762. desks_controller->NewDesk(DesksCreationRemovalSource::kKeyboard);
  1763. Desk* desk_2 = desks_controller->desks()[1].get();
  1764. ActivateDesk(desk_2);
  1765. // A window on a different desk than that of the recorded window should not be
  1766. // dimmed.
  1767. auto win1 = CreateAppWindow(gfx::Rect(200, 200));
  1768. EXPECT_FALSE(recording_watcher->IsWindowDimmedForTesting(win1.get()));
  1769. // However, moving it to the desk of the recorded window should give it a
  1770. // dimmer, since it's a more recently-used window (i.e. above the recorded
  1771. // window).
  1772. Desk* desk_1 = desks_controller->desks()[0].get();
  1773. desks_controller->MoveWindowFromActiveDeskTo(
  1774. win1.get(), desk_1, win1->GetRootWindow(),
  1775. DesksMoveWindowFromActiveDeskSource::kShortcut);
  1776. EXPECT_TRUE(recording_watcher->IsWindowDimmedForTesting(win1.get()));
  1777. // Moving the recorded window out of the active desk should destroy the
  1778. // dimmer.
  1779. ActivateDesk(desk_1);
  1780. desks_controller->MoveWindowFromActiveDeskTo(
  1781. recorded_window.get(), desk_2, recorded_window->GetRootWindow(),
  1782. DesksMoveWindowFromActiveDeskSource::kShortcut);
  1783. EXPECT_FALSE(recording_watcher->IsWindowDimmedForTesting(win1.get()));
  1784. }
  1785. TEST_F(CaptureModeTest, DimmingWithDisplays) {
  1786. UpdateDisplay("500x400,401+0-800x700");
  1787. auto recorded_window = CreateAppWindow(gfx::Rect(250, 100));
  1788. auto* controller = StartSessionAndRecordWindow(recorded_window.get());
  1789. auto* recording_watcher = controller->video_recording_watcher_for_testing();
  1790. EXPECT_TRUE(recording_watcher->should_paint_layer());
  1791. // Create a new window on the second display. It should not be dimmed.
  1792. auto window = CreateTestWindow(gfx::Rect(420, 10, 200, 200));
  1793. auto roots = Shell::GetAllRootWindows();
  1794. EXPECT_EQ(roots[1], window->GetRootWindow());
  1795. EXPECT_FALSE(recording_watcher->IsWindowDimmedForTesting(window.get()));
  1796. // However when moved to the first display, it gets dimmed.
  1797. window_util::MoveWindowToDisplay(window.get(),
  1798. roots[0]->GetHost()->GetDisplayId());
  1799. EXPECT_TRUE(recording_watcher->IsWindowDimmedForTesting(window.get()));
  1800. // Moving the recorded window to the second display will remove the dimming of
  1801. // |window|.
  1802. window_util::MoveWindowToDisplay(recorded_window.get(),
  1803. roots[1]->GetHost()->GetDisplayId());
  1804. EXPECT_FALSE(recording_watcher->IsWindowDimmedForTesting(window.get()));
  1805. }
  1806. TEST_F(CaptureModeTest, MultiDisplayWindowRecording) {
  1807. UpdateDisplay("500x400,401+0-800x700");
  1808. auto roots = Shell::GetAllRootWindows();
  1809. ASSERT_EQ(2u, roots.size());
  1810. auto window = CreateTestWindow(gfx::Rect(200, 200));
  1811. auto* controller =
  1812. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
  1813. auto* event_generator = GetEventGenerator();
  1814. event_generator->MoveMouseToCenterOf(window.get());
  1815. auto* session_layer = controller->capture_mode_session()->layer();
  1816. StartVideoRecordingImmediately();
  1817. EXPECT_TRUE(controller->is_recording_in_progress());
  1818. // The session layer is reused to paint the recording shield.
  1819. auto* shield_layer =
  1820. controller->video_recording_watcher_for_testing()->layer();
  1821. EXPECT_EQ(session_layer, shield_layer);
  1822. EXPECT_EQ(shield_layer->parent(), window->layer()->parent());
  1823. EXPECT_TRUE(IsLayerStackedRightBelow(shield_layer, window->layer()));
  1824. EXPECT_EQ(shield_layer->bounds(), roots[0]->bounds());
  1825. // The capturer should capture from the frame sink of the first display.
  1826. // The video size should match the window's size.
  1827. CaptureModeTestApi test_api;
  1828. test_api.FlushRecordingServiceForTesting();
  1829. auto* test_delegate =
  1830. static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
  1831. EXPECT_EQ(roots[0]->GetFrameSinkId(), test_delegate->GetCurrentFrameSinkId());
  1832. EXPECT_EQ(roots[0]->bounds().size(),
  1833. test_delegate->GetCurrentFrameSinkSizeInPixels());
  1834. EXPECT_EQ(window->bounds().size(), test_delegate->GetCurrentVideoSize());
  1835. // Moving a window to a different display should be propagated to the service,
  1836. // with the new root's frame sink ID, and the new root's size.
  1837. window_util::MoveWindowToDisplay(window.get(),
  1838. roots[1]->GetHost()->GetDisplayId());
  1839. test_api.FlushRecordingServiceForTesting();
  1840. ASSERT_EQ(window->GetRootWindow(), roots[1]);
  1841. EXPECT_EQ(roots[1]->GetFrameSinkId(), test_delegate->GetCurrentFrameSinkId());
  1842. EXPECT_EQ(roots[1]->bounds().size(),
  1843. test_delegate->GetCurrentFrameSinkSizeInPixels());
  1844. EXPECT_EQ(window->bounds().size(), test_delegate->GetCurrentVideoSize());
  1845. // The shield layer should move with the window, and maintain the stacking
  1846. // below the window's layer.
  1847. EXPECT_EQ(shield_layer->parent(), window->layer()->parent());
  1848. EXPECT_TRUE(IsLayerStackedRightBelow(shield_layer, window->layer()));
  1849. EXPECT_EQ(shield_layer->bounds(), roots[1]->bounds());
  1850. }
  1851. // Flaky especially on MSan: https://crbug.com/1293188
  1852. TEST_F(CaptureModeTest, DISABLED_WindowResizing) {
  1853. UpdateDisplay("700x600");
  1854. auto window = CreateTestWindow(gfx::Rect(200, 200));
  1855. auto* controller =
  1856. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
  1857. auto* event_generator = GetEventGenerator();
  1858. event_generator->MoveMouseToCenterOf(window.get());
  1859. StartVideoRecordingImmediately();
  1860. EXPECT_TRUE(controller->is_recording_in_progress());
  1861. auto* test_delegate =
  1862. static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
  1863. CaptureModeTestApi test_api;
  1864. test_api.FlushRecordingServiceForTesting();
  1865. EXPECT_EQ(gfx::Size(200, 200), test_delegate->GetCurrentVideoSize());
  1866. EXPECT_EQ(gfx::Size(700, 600),
  1867. test_delegate->GetCurrentFrameSinkSizeInPixels());
  1868. // Multiple resize events should be throttled.
  1869. window->SetBounds(gfx::Rect(250, 250));
  1870. test_api.FlushRecordingServiceForTesting();
  1871. EXPECT_EQ(gfx::Size(200, 200), test_delegate->GetCurrentVideoSize());
  1872. window->SetBounds(gfx::Rect(250, 300));
  1873. test_api.FlushRecordingServiceForTesting();
  1874. EXPECT_EQ(gfx::Size(200, 200), test_delegate->GetCurrentVideoSize());
  1875. window->SetBounds(gfx::Rect(300, 300));
  1876. test_api.FlushRecordingServiceForTesting();
  1877. EXPECT_EQ(gfx::Size(200, 200), test_delegate->GetCurrentVideoSize());
  1878. // Once throttling ends, the current size is pushed.
  1879. auto* recording_watcher = controller->video_recording_watcher_for_testing();
  1880. recording_watcher->SendThrottledWindowSizeChangedNowForTesting();
  1881. test_api.FlushRecordingServiceForTesting();
  1882. EXPECT_EQ(gfx::Size(300, 300), test_delegate->GetCurrentVideoSize());
  1883. EXPECT_EQ(gfx::Size(700, 600),
  1884. test_delegate->GetCurrentFrameSinkSizeInPixels());
  1885. // Maximizing a window changes its size, and is pushed to the service with
  1886. // throttling.
  1887. WindowState::Get(window.get())->Maximize();
  1888. test_api.FlushRecordingServiceForTesting();
  1889. EXPECT_EQ(gfx::Size(300, 300), test_delegate->GetCurrentVideoSize());
  1890. recording_watcher->SendThrottledWindowSizeChangedNowForTesting();
  1891. test_api.FlushRecordingServiceForTesting();
  1892. EXPECT_NE(gfx::Size(300, 300), test_delegate->GetCurrentVideoSize());
  1893. EXPECT_EQ(window->bounds().size(), test_delegate->GetCurrentVideoSize());
  1894. }
  1895. TEST_F(CaptureModeTest, RotateDisplayWhileRecording) {
  1896. UpdateDisplay("600x800");
  1897. auto* controller =
  1898. StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
  1899. SelectRegion(gfx::Rect(20, 40, 100, 200));
  1900. StartVideoRecordingImmediately();
  1901. EXPECT_TRUE(controller->is_recording_in_progress());
  1902. // Initially the frame sink size matches the un-rotated display size in DIPs,
  1903. // but the video size matches the size of the crop region.
  1904. CaptureModeTestApi test_api;
  1905. test_api.FlushRecordingServiceForTesting();
  1906. auto* test_delegate =
  1907. static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
  1908. EXPECT_EQ(gfx::Size(600, 800),
  1909. test_delegate->GetCurrentFrameSinkSizeInPixels());
  1910. EXPECT_EQ(gfx::Size(100, 200), test_delegate->GetCurrentVideoSize());
  1911. // Rotate by 90 degree, the frame sink size should be updated to match that.
  1912. // The video size should remain unaffected.
  1913. Shell::Get()->display_manager()->SetDisplayRotation(
  1914. WindowTreeHostManager::GetPrimaryDisplayId(), display::Display::ROTATE_90,
  1915. display::Display::RotationSource::USER);
  1916. test_api.FlushRecordingServiceForTesting();
  1917. EXPECT_EQ(gfx::Size(800, 600),
  1918. test_delegate->GetCurrentFrameSinkSizeInPixels());
  1919. EXPECT_EQ(gfx::Size(100, 200), test_delegate->GetCurrentVideoSize());
  1920. }
  1921. // Regression test for https://crbug.com/1331095.
  1922. TEST_F(CaptureModeTest, CornerRegionWithScreenRotation) {
  1923. UpdateDisplay("800x600");
  1924. // Pick a region at the bottom right corner of the landscape screen, so that
  1925. // when the screen is rotated to portrait, the unadjusted region becomes
  1926. // outside the new portrait bounds.
  1927. auto* controller =
  1928. StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kVideo);
  1929. SelectRegion(gfx::Rect(700, 400, 100, 200));
  1930. StartVideoRecordingImmediately();
  1931. EXPECT_TRUE(controller->is_recording_in_progress());
  1932. CaptureModeTestApi test_api;
  1933. test_api.FlushRecordingServiceForTesting();
  1934. auto* test_delegate =
  1935. static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
  1936. EXPECT_EQ(gfx::Size(100, 200), test_delegate->GetCurrentVideoSize());
  1937. auto* root_window = Shell::GetPrimaryRootWindow();
  1938. auto* recording_watcher = controller->video_recording_watcher_for_testing();
  1939. gfx::Rect effective_region_bounds =
  1940. recording_watcher->GetEffectivePartialRegionBounds();
  1941. EXPECT_FALSE(effective_region_bounds.IsEmpty());
  1942. EXPECT_TRUE(root_window->bounds().Contains(effective_region_bounds));
  1943. // Verifies that the bounds of the visible rect of the frame is within the
  1944. // bounds of the root window.
  1945. auto verify_video_frame = [&](const media::VideoFrame& frame,
  1946. const gfx::Rect& content_rect) {
  1947. EXPECT_TRUE(root_window->bounds().Contains(frame.visible_rect()));
  1948. };
  1949. test_delegate->recording_service()->RequestAndWaitForVideoFrame(
  1950. base::BindLambdaForTesting(verify_video_frame));
  1951. // Rotate by 90 degree, the adjusted region bounds should not be empty and
  1952. // should remain within the bounds of the new portrait root window bounds.
  1953. Shell::Get()->display_manager()->SetDisplayRotation(
  1954. WindowTreeHostManager::GetPrimaryDisplayId(), display::Display::ROTATE_90,
  1955. display::Display::RotationSource::USER);
  1956. test_api.FlushRecordingServiceForTesting();
  1957. EXPECT_EQ(gfx::Size(100, 200), test_delegate->GetCurrentVideoSize());
  1958. effective_region_bounds =
  1959. recording_watcher->GetEffectivePartialRegionBounds();
  1960. EXPECT_FALSE(effective_region_bounds.IsEmpty());
  1961. EXPECT_TRUE(root_window->bounds().Contains(effective_region_bounds));
  1962. test_delegate->recording_service()->RequestAndWaitForVideoFrame(
  1963. base::BindLambdaForTesting(verify_video_frame));
  1964. }
  1965. // Tests that the video frames delivered to the service for recorded windows are
  1966. // valid (i.e. they have the correct size, and suffer from no letterboxing, even
  1967. // when the window gets resized).
  1968. // This is a regression test for https://crbug.com/1214023.
  1969. TEST_F(CaptureModeTest, VerifyWindowRecordingVideoFrames) {
  1970. auto window = CreateTestWindow(gfx::Rect(100, 50, 200, 200));
  1971. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
  1972. auto* event_generator = GetEventGenerator();
  1973. event_generator->MoveMouseToCenterOf(window.get());
  1974. auto* controller = CaptureModeController::Get();
  1975. StartVideoRecordingImmediately();
  1976. EXPECT_TRUE(controller->is_recording_in_progress());
  1977. CaptureModeTestApi test_api;
  1978. test_api.FlushRecordingServiceForTesting();
  1979. bool is_video_frame_valid = false;
  1980. std::string failures;
  1981. auto verify_video_frame = [&](const media::VideoFrame& frame,
  1982. const gfx::Rect& content_rect) {
  1983. is_video_frame_valid = true;
  1984. failures.clear();
  1985. // Having the content positioned at (0,0) with a size that matches the
  1986. // current window's size means that there is no letterboxing.
  1987. if (gfx::Point() != content_rect.origin()) {
  1988. is_video_frame_valid = false;
  1989. failures =
  1990. base::StringPrintf("content_rect is not at (0,0), instead at: %s\n",
  1991. content_rect.origin().ToString().c_str());
  1992. }
  1993. const gfx::Size window_size = window->bounds().size();
  1994. if (window_size != content_rect.size()) {
  1995. is_video_frame_valid = false;
  1996. failures += base::StringPrintf(
  1997. "content_rect doesn't match the window size:\n"
  1998. " content_rect.size(): %s\n"
  1999. " window_size: %s\n",
  2000. content_rect.size().ToString().c_str(),
  2001. window_size.ToString().c_str());
  2002. }
  2003. // The video frame contents should match the bounds of the video frame.
  2004. if (frame.visible_rect() != content_rect) {
  2005. is_video_frame_valid = false;
  2006. failures += base::StringPrintf(
  2007. "content_rect doesn't match the frame's visible_rect:\n"
  2008. " content_rect: %s\n"
  2009. " visible_rect: %s\n",
  2010. content_rect.ToString().c_str(),
  2011. frame.visible_rect().ToString().c_str());
  2012. }
  2013. if (frame.coded_size() != window_size) {
  2014. is_video_frame_valid = false;
  2015. failures += base::StringPrintf(
  2016. "the frame's coded size doesn't match the window size:\n"
  2017. " frame.coded_size(): %s\n"
  2018. " window_size: %s\n",
  2019. frame.coded_size().ToString().c_str(),
  2020. window_size.ToString().c_str());
  2021. }
  2022. };
  2023. auto* test_delegate =
  2024. static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
  2025. ASSERT_TRUE(test_delegate->recording_service());
  2026. {
  2027. SCOPED_TRACE("Initial window size");
  2028. test_delegate->recording_service()->RequestAndWaitForVideoFrame(
  2029. base::BindLambdaForTesting(verify_video_frame));
  2030. EXPECT_TRUE(is_video_frame_valid) << failures;
  2031. }
  2032. // Even when the window is resized and the throttled size reaches the service,
  2033. // new video frames should still be valid.
  2034. window->SetBounds(gfx::Rect(120, 60, 600, 500));
  2035. auto* recording_watcher = controller->video_recording_watcher_for_testing();
  2036. recording_watcher->SendThrottledWindowSizeChangedNowForTesting();
  2037. test_api.FlushRecordingServiceForTesting();
  2038. {
  2039. SCOPED_TRACE("After window resizing");
  2040. // A video frame is produced on the Viz side when a CopyOutputRequest is
  2041. // fulfilled. Those CopyOutputRequests could have been placed before the
  2042. // window's layer resize results in a new resized render pass in Viz. But
  2043. // eventually this must happen, and a valid frame must be delivered.
  2044. int remaining_attempts = 2;
  2045. do {
  2046. --remaining_attempts;
  2047. test_delegate->recording_service()->RequestAndWaitForVideoFrame(
  2048. base::BindLambdaForTesting(verify_video_frame));
  2049. } while (!is_video_frame_valid && remaining_attempts);
  2050. EXPECT_TRUE(is_video_frame_valid) << failures;
  2051. }
  2052. controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
  2053. EXPECT_FALSE(controller->is_recording_in_progress());
  2054. }
  2055. // Tests that the focus should be on the `Settings` button after closing the
  2056. // settings menu.
  2057. TEST_F(CaptureModeTest, ReturnFocusToSettingsButtonAfterSettingsMenuIsClosed) {
  2058. auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  2059. CaptureModeType::kImage);
  2060. CaptureModeSession* capture_mode_session = controller->capture_mode_session();
  2061. CaptureModeSessionTestApi test_api(capture_mode_session);
  2062. using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
  2063. auto* event_generator = GetEventGenerator();
  2064. // Check the initial focus of the focus ring.
  2065. EXPECT_EQ(FocusGroup::kNone, test_api.GetCurrentFocusGroup());
  2066. // Tab six times, `Settings` button should be focused.
  2067. SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/6);
  2068. EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
  2069. EXPECT_TRUE(test_api.GetCaptureModeBarView()->settings_button()->has_focus());
  2070. // Tab the space key and the settings menu will be opened.
  2071. SendKey(ui::VKEY_SPACE, event_generator, ui::EF_NONE);
  2072. EXPECT_TRUE(test_api.GetCaptureModeSettingsView());
  2073. EXPECT_EQ(FocusGroup::kPendingSettings, test_api.GetCurrentFocusGroup());
  2074. // Close the settings menu, the focus ring should be on the `Settings` button.
  2075. SendKey(ui::VKEY_ESCAPE, event_generator, ui::EF_NONE);
  2076. EXPECT_FALSE(test_api.GetCaptureModeSettingsView());
  2077. EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
  2078. EXPECT_TRUE(test_api.GetCaptureModeBarView()->settings_button()->has_focus());
  2079. // Tab the space key to open the settings menu again and tab to focus on the
  2080. // settings menu item.
  2081. SendKey(ui::VKEY_SPACE, event_generator, ui::EF_NONE);
  2082. EXPECT_TRUE(test_api.GetCaptureModeSettingsView());
  2083. SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/3);
  2084. EXPECT_EQ(FocusGroup::kSettingsMenu, test_api.GetCurrentFocusGroup());
  2085. // Close the settings menu, the focus ring should be on the `Settings` button.
  2086. SendKey(ui::VKEY_ESCAPE, event_generator, ui::EF_NONE);
  2087. EXPECT_FALSE(test_api.GetCaptureModeSettingsView());
  2088. EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
  2089. EXPECT_TRUE(test_api.GetCaptureModeBarView()->settings_button()->has_focus());
  2090. }
  2091. // Tests that minimized window(s) will be ignored whereas four corners occluded
  2092. // but overall partially occluded window will be focusable while tabbing through
  2093. // in `kWindow` mode.
  2094. TEST_F(CaptureModeTest, IgnoreMinimizeWindowsInKWindow) {
  2095. // Layout of three windows: four corners of `window3` are occluded by
  2096. // `window1` and `window2`.
  2097. //
  2098. // +------+
  2099. // | | +-----------+
  2100. // | 1 |-------| |
  2101. // | | 3 | 2 |
  2102. // | | | |
  2103. // | | | |
  2104. // | |-------| |
  2105. // | | +-----------+
  2106. // +------+
  2107. std::unique_ptr<aura::Window> window3 =
  2108. CreateTestWindow(gfx::Rect(100, 45, 150, 200));
  2109. std::unique_ptr<aura::Window> window2 =
  2110. CreateTestWindow(gfx::Rect(150, 50, 150, 250));
  2111. std::unique_ptr<aura::Window> window1 =
  2112. CreateTestWindow(gfx::Rect(20, 30, 100, 300));
  2113. std::unique_ptr<aura::Window> window4(
  2114. CreateTestWindow(gfx::Rect(0, 0, 50, 90)));
  2115. WindowState::Get(window4.get())->Minimize();
  2116. auto* controller =
  2117. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kImage);
  2118. CaptureModeSession* capture_mode_session = controller->capture_mode_session();
  2119. CaptureModeSessionTestApi test_api(capture_mode_session);
  2120. using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
  2121. auto* event_generator = GetEventGenerator();
  2122. EXPECT_EQ(FocusGroup::kNone, test_api.GetCurrentFocusGroup());
  2123. EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
  2124. // Tab six times, `window1` should be focused. Tab another time, `window2`
  2125. // should be focused. Tab again, `window3` will be focused.
  2126. SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/6);
  2127. EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
  2128. EXPECT_EQ(window1.get(), capture_mode_session->GetSelectedWindow());
  2129. SendKey(ui::VKEY_TAB, event_generator);
  2130. EXPECT_EQ(window2.get(), capture_mode_session->GetSelectedWindow());
  2131. SendKey(ui::VKEY_TAB, event_generator);
  2132. EXPECT_EQ(window3.get(), capture_mode_session->GetSelectedWindow());
  2133. // Tab once, the `settings` button should be focused. The minimized `window4`
  2134. // will be ignored during the tabbing process.
  2135. SendKey(ui::VKEY_TAB, event_generator);
  2136. EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
  2137. controller->Stop();
  2138. }
  2139. // Tests that partially occluded window(s) will be focusable even when four
  2140. // edges are occluded by other windows while tabbing through in `kWindow` mode.
  2141. TEST_F(CaptureModeTest, PartiallyOccludedWindowIsFocusableInKWindow) {
  2142. // Layout of five windows: four edges of `window3` is occluded by `window1`,
  2143. // `window2`, `window4` and `window5` respectively, but the middle part is not
  2144. // occluded.
  2145. // +-----------+
  2146. // | |
  2147. // +----| 4 |
  2148. // | | |---------+
  2149. // | | | |
  2150. // | +-|-------|-+ |
  2151. // | 1 | 3 | 2 |
  2152. // | | | |
  2153. // | +-|-------|--+ |
  2154. // | | |--------+
  2155. // +----| 5 |
  2156. // | |
  2157. // +------------+
  2158. std::unique_ptr<aura::Window> window3 =
  2159. CreateTestWindow(gfx::Rect(100, 45, 150, 200));
  2160. std::unique_ptr<aura::Window> window2 =
  2161. CreateTestWindow(gfx::Rect(150, 50, 150, 250));
  2162. std::unique_ptr<aura::Window> window1 =
  2163. CreateTestWindow(gfx::Rect(20, 30, 100, 300));
  2164. std::unique_ptr<aura::Window> window4 =
  2165. CreateTestWindow(gfx::Rect(50, 5, 150, 55));
  2166. std::unique_ptr<aura::Window> window5 =
  2167. CreateTestWindow(gfx::Rect(60, 225, 210, 45));
  2168. auto* controller =
  2169. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kImage);
  2170. CaptureModeSession* capture_mode_session = controller->capture_mode_session();
  2171. CaptureModeSessionTestApi test_api(capture_mode_session);
  2172. using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
  2173. auto* event_generator = GetEventGenerator();
  2174. EXPECT_EQ(FocusGroup::kNone, test_api.GetCurrentFocusGroup());
  2175. EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
  2176. // Tab six times, `window5` should be focused. Then `window4`, `window1`,
  2177. // `window2` and `window3` will be focused after each tab.
  2178. SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/6);
  2179. EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
  2180. EXPECT_EQ(window5.get(), capture_mode_session->GetSelectedWindow());
  2181. SendKey(ui::VKEY_TAB, event_generator);
  2182. EXPECT_EQ(window4.get(), capture_mode_session->GetSelectedWindow());
  2183. SendKey(ui::VKEY_TAB, event_generator);
  2184. EXPECT_EQ(window1.get(), capture_mode_session->GetSelectedWindow());
  2185. SendKey(ui::VKEY_TAB, event_generator);
  2186. EXPECT_EQ(window2.get(), capture_mode_session->GetSelectedWindow());
  2187. SendKey(ui::VKEY_TAB, event_generator);
  2188. EXPECT_EQ(window3.get(), capture_mode_session->GetSelectedWindow());
  2189. // Tab once, the `settings` button should be focused.
  2190. SendKey(ui::VKEY_TAB, event_generator);
  2191. EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
  2192. controller->Stop();
  2193. }
  2194. // Tests that fully occluded window(s) will be ignored while tabbing in
  2195. // `kWindow`.
  2196. TEST_F(CaptureModeTest, IgnoreFullyOccludedWindowWhileTabbingInKWindow) {
  2197. // Layout of six windows: `window3` is fully occluded by `window1`, `window2`,
  2198. // `window4`, `window5` and `window6`.
  2199. // +-----------+
  2200. // | |
  2201. // +----| 4 |
  2202. // | 1 | |---------+
  2203. // | +-----------------+ |
  2204. // | | | |
  2205. // | | 6 | 2 |
  2206. // | | | |
  2207. // | +-----------------+ |
  2208. // | | |--------+
  2209. // +----| 5 |
  2210. // | |
  2211. // +------------+
  2212. std::unique_ptr<aura::Window> window3 =
  2213. CreateTestWindow(gfx::Rect(100, 45, 150, 200));
  2214. std::unique_ptr<aura::Window> window2 =
  2215. CreateTestWindow(gfx::Rect(150, 50, 150, 250));
  2216. std::unique_ptr<aura::Window> window1 =
  2217. CreateTestWindow(gfx::Rect(20, 30, 100, 300));
  2218. std::unique_ptr<aura::Window> window4 =
  2219. CreateTestWindow(gfx::Rect(50, 5, 150, 55));
  2220. std::unique_ptr<aura::Window> window5 =
  2221. CreateTestWindow(gfx::Rect(60, 225, 210, 45));
  2222. std::unique_ptr<aura::Window> window6 =
  2223. CreateTestWindow(gfx::Rect(30, 55, 175, 185));
  2224. auto* controller =
  2225. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kImage);
  2226. CaptureModeSession* capture_mode_session = controller->capture_mode_session();
  2227. CaptureModeSessionTestApi test_api(capture_mode_session);
  2228. using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
  2229. auto* event_generator = GetEventGenerator();
  2230. EXPECT_EQ(FocusGroup::kNone, test_api.GetCurrentFocusGroup());
  2231. EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
  2232. // Tab six times, `window6` should be focused. Then `window5`, `window4`,
  2233. // `window1` and `window2` will be focused after each tab.
  2234. SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/6);
  2235. EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
  2236. EXPECT_EQ(window6.get(), capture_mode_session->GetSelectedWindow());
  2237. SendKey(ui::VKEY_TAB, event_generator);
  2238. EXPECT_EQ(window5.get(), capture_mode_session->GetSelectedWindow());
  2239. SendKey(ui::VKEY_TAB, event_generator);
  2240. EXPECT_EQ(window4.get(), capture_mode_session->GetSelectedWindow());
  2241. SendKey(ui::VKEY_TAB, event_generator);
  2242. EXPECT_EQ(window1.get(), capture_mode_session->GetSelectedWindow());
  2243. SendKey(ui::VKEY_TAB, event_generator);
  2244. EXPECT_EQ(window2.get(), capture_mode_session->GetSelectedWindow());
  2245. // Tab once, the `settings` button should be focused. The fully occluded
  2246. // `window3` will be ignored during the tabbing process.
  2247. SendKey(ui::VKEY_TAB, event_generator);
  2248. EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
  2249. }
  2250. class CaptureModeSaveFileTest
  2251. : public CaptureModeTest,
  2252. public testing::WithParamInterface<CaptureModeType> {
  2253. public:
  2254. CaptureModeSaveFileTest() = default;
  2255. CaptureModeSaveFileTest(
  2256. const CaptureModeSaveFileTest& capture_mode_save_file_test) = delete;
  2257. CaptureModeSaveFileTest& operator=(const CaptureModeSaveFileTest&) = delete;
  2258. ~CaptureModeSaveFileTest() override = default;
  2259. void StartCaptureSessionWithParam() {
  2260. StartCaptureSession(CaptureModeSource::kFullscreen, GetParam());
  2261. }
  2262. // Based on the `CaptureModeType`, it performs the capture and then returns
  2263. // the path of the saved image or video files.
  2264. base::FilePath PerformCapture() {
  2265. auto* controller = CaptureModeController::Get();
  2266. switch (GetParam()) {
  2267. case CaptureModeType::kImage:
  2268. controller->PerformCapture();
  2269. return WaitForCaptureFileToBeSaved();
  2270. case CaptureModeType::kVideo:
  2271. StartVideoRecordingImmediately();
  2272. controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
  2273. return WaitForCaptureFileToBeSaved();
  2274. }
  2275. }
  2276. };
  2277. // Tests that if the custom folder becomes unavailable, the captured file should
  2278. // be saved into the default folder. Otherwise, it's saved into custom folder.
  2279. TEST_P(CaptureModeSaveFileTest, SaveCapturedFileWithCustomFolder) {
  2280. auto* controller = CaptureModeController::Get();
  2281. const base::FilePath default_folder =
  2282. controller->delegate_for_testing()->GetUserDefaultDownloadsFolder();
  2283. const base::FilePath custom_folder((FILE_PATH_LITERAL("/home/tests")));
  2284. controller->SetCustomCaptureFolder(custom_folder);
  2285. // Make sure the current folder is the custom folder here and then perform
  2286. // capture.
  2287. auto capture_folder = controller->GetCurrentCaptureFolder();
  2288. EXPECT_FALSE(capture_folder.is_default_downloads_folder);
  2289. StartCaptureSessionWithParam();
  2290. base::FilePath file_saved_path = PerformCapture();
  2291. // Since `custom_folder` is not available, the captured files will be saved
  2292. // into default folder;
  2293. EXPECT_EQ(file_saved_path.DirName(), default_folder);
  2294. // Now create an available custom folder and set it for custom capture folder.
  2295. const base::FilePath available_custom_folder =
  2296. CreateCustomFolderInUserDownloadsPath("test");
  2297. controller->SetCustomCaptureFolder(available_custom_folder);
  2298. capture_folder = controller->GetCurrentCaptureFolder();
  2299. EXPECT_FALSE(capture_folder.is_default_downloads_folder);
  2300. StartCaptureSessionWithParam();
  2301. file_saved_path = PerformCapture();
  2302. // Since `available_custom_folder` is now available, the captured files will
  2303. // be saved into the custom folder;
  2304. EXPECT_EQ(file_saved_path.DirName(), available_custom_folder);
  2305. }
  2306. TEST_P(CaptureModeSaveFileTest, CaptureModeSaveToLocationMetric) {
  2307. constexpr char kHistogramBase[] = "Ash.CaptureModeController.SaveLocation";
  2308. base::HistogramTester histogram_tester;
  2309. auto* controller = CaptureModeController::Get();
  2310. auto* test_delegate = controller->delegate_for_testing();
  2311. // Initialize four different save-to locations for screen capture that
  2312. // includes default downloads folder, local customized folder, root drive and
  2313. // a specific folder on drive.
  2314. const auto downloads_folder = test_delegate->GetUserDefaultDownloadsFolder();
  2315. const base::FilePath custom_folder =
  2316. CreateCustomFolderInUserDownloadsPath("test");
  2317. base::FilePath mount_point_path;
  2318. test_delegate->GetDriveFsMountPointPath(&mount_point_path);
  2319. const auto root_drive_folder = mount_point_path.Append("root");
  2320. const base::FilePath non_root_drive_folder = CreateFolderOnDriveFS("test");
  2321. struct {
  2322. base::FilePath set_save_file_folder;
  2323. CaptureModeSaveToLocation save_location;
  2324. } kTestCases[] = {
  2325. {downloads_folder, CaptureModeSaveToLocation::kDefault},
  2326. {custom_folder, CaptureModeSaveToLocation::kCustomizedFolder},
  2327. {root_drive_folder, CaptureModeSaveToLocation::kDrive},
  2328. {non_root_drive_folder, CaptureModeSaveToLocation::kDriveFolder},
  2329. };
  2330. for (auto test_case : kTestCases) {
  2331. histogram_tester.ExpectBucketCount(
  2332. GetCaptureModeHistogramName(kHistogramBase), test_case.save_location,
  2333. 0);
  2334. }
  2335. // Set four different save-to locations in clamshell mode and check the
  2336. // histogram results.
  2337. EXPECT_FALSE(Shell::Get()->IsInTabletMode());
  2338. for (auto test_case : kTestCases) {
  2339. StartCaptureSessionWithParam();
  2340. controller->SetCustomCaptureFolder(test_case.set_save_file_folder);
  2341. auto file_saved_path = PerformCapture();
  2342. histogram_tester.ExpectBucketCount(
  2343. GetCaptureModeHistogramName(kHistogramBase), test_case.save_location,
  2344. 1);
  2345. }
  2346. // Set four different save-to locations in tablet mode and check the histogram
  2347. // results.
  2348. SwitchToTabletMode();
  2349. EXPECT_TRUE(Shell::Get()->IsInTabletMode());
  2350. for (auto test_case : kTestCases) {
  2351. StartCaptureSessionWithParam();
  2352. controller->SetCustomCaptureFolder(test_case.set_save_file_folder);
  2353. auto file_saved_path = PerformCapture();
  2354. histogram_tester.ExpectBucketCount(
  2355. GetCaptureModeHistogramName(kHistogramBase), test_case.save_location,
  2356. 1);
  2357. }
  2358. }
  2359. INSTANTIATE_TEST_SUITE_P(All,
  2360. CaptureModeSaveFileTest,
  2361. testing::Values(CaptureModeType::kImage,
  2362. CaptureModeType::kVideo));
  2363. // Test fixture for verifying that the videos are recorded at the pixel size of
  2364. // the targets being captured in all recording modes. This avoids having the
  2365. // scaling in CopyOutputRequests when performing the capture at a different size
  2366. // than that of the render pass (which is in pixels). This scaling causes a loss
  2367. // of quality, and a blurry video frames. https://crbug.com/1215185.
  2368. class CaptureModeRecordingSizeTest : public CaptureModeTest {
  2369. public:
  2370. CaptureModeRecordingSizeTest() = default;
  2371. ~CaptureModeRecordingSizeTest() override = default;
  2372. // CaptureModeTest:
  2373. void SetUp() override {
  2374. CaptureModeTest::SetUp();
  2375. window_ = CreateTestWindow(gfx::Rect(100, 50, 200, 200));
  2376. CaptureModeController::Get()->SetUserCaptureRegion(user_region_,
  2377. /*by_user=*/true);
  2378. UpdateDisplay("800x600");
  2379. }
  2380. void TearDown() override {
  2381. window_.reset();
  2382. CaptureModeTest::TearDown();
  2383. }
  2384. // Converts the given |size| from DIPs to pixels based on the given value of
  2385. // |dsf|.
  2386. gfx::Size ToPixels(const gfx::Size& size, float dsf) const {
  2387. return gfx::ToFlooredSize(gfx::ConvertSizeToPixels(size, dsf));
  2388. }
  2389. protected:
  2390. // Verifies the size of the received video frame.
  2391. static void VerifyVideoFrame(const gfx::Size& expected_video_size,
  2392. const media::VideoFrame& frame,
  2393. const gfx::Rect& content_rect) {
  2394. // The I420 pixel format does not like odd dimensions, so the size of the
  2395. // visible rect in the video frame will be adjusted to be an even value.
  2396. const gfx::Size adjusted_size(expected_video_size.width() & ~1,
  2397. expected_video_size.height() & ~1);
  2398. EXPECT_EQ(adjusted_size, frame.visible_rect().size());
  2399. }
  2400. CaptureModeController* StartVideoRecording(CaptureModeSource source) {
  2401. auto* controller = StartCaptureSession(source, CaptureModeType::kVideo);
  2402. if (source == CaptureModeSource::kWindow)
  2403. GetEventGenerator()->MoveMouseToCenterOf(window_.get());
  2404. StartVideoRecordingImmediately();
  2405. EXPECT_TRUE(controller->is_recording_in_progress());
  2406. CaptureModeTestApi().FlushRecordingServiceForTesting();
  2407. return controller;
  2408. }
  2409. void SetDeviceScaleFactor(float dsf) {
  2410. const auto display_id = display_manager()->GetDisplayAt(0).id();
  2411. display_manager()->UpdateZoomFactor(display_id, dsf);
  2412. EXPECT_EQ(dsf, window_->GetHost()->device_scale_factor());
  2413. auto* controller = CaptureModeController::Get();
  2414. if (controller->is_recording_in_progress()) {
  2415. CaptureModeTestApi().FlushRecordingServiceForTesting();
  2416. auto* test_delegate = static_cast<TestCaptureModeDelegate*>(
  2417. controller->delegate_for_testing());
  2418. // Consume any pending video frame from before changing the DSF prior to
  2419. // proceeding.
  2420. test_delegate->RequestAndWaitForVideoFrame();
  2421. }
  2422. }
  2423. protected:
  2424. const gfx::Rect user_region_{20, 50};
  2425. std::unique_ptr<aura::Window> window_;
  2426. };
  2427. // TODO(crbug.com/1291073): Flaky on ChromeOS.
  2428. #if BUILDFLAG(IS_CHROMEOS)
  2429. #define MAYBE_CaptureAtPixelsFullscreen DISABLED_CaptureAtPixelsFullscreen
  2430. #else
  2431. #define MAYBE_CaptureAtPixelsFullscreen CaptureAtPixelsFullscreen
  2432. #endif
  2433. TEST_F(CaptureModeRecordingSizeTest, MAYBE_CaptureAtPixelsFullscreen) {
  2434. float dsf = 1.6f;
  2435. SetDeviceScaleFactor(dsf);
  2436. auto* controller = StartVideoRecording(CaptureModeSource::kFullscreen);
  2437. auto* root = window_->GetRootWindow();
  2438. gfx::Size initial_root_window_size_pixels =
  2439. ToPixels(root->bounds().size(), dsf);
  2440. auto* test_delegate =
  2441. static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
  2442. ASSERT_TRUE(test_delegate->recording_service());
  2443. {
  2444. SCOPED_TRACE("Testing @ 1.6 device scale factor");
  2445. EXPECT_EQ(initial_root_window_size_pixels,
  2446. test_delegate->GetCurrentVideoSize());
  2447. EXPECT_EQ(
  2448. dsf, test_delegate->recording_service()->GetCurrentDeviceScaleFactor());
  2449. EXPECT_EQ(initial_root_window_size_pixels,
  2450. test_delegate->GetCurrentFrameSinkSizeInPixels());
  2451. test_delegate->recording_service()->RequestAndWaitForVideoFrame(
  2452. base::BindOnce(&CaptureModeRecordingSizeTest::VerifyVideoFrame,
  2453. initial_root_window_size_pixels));
  2454. }
  2455. // Change the DSF and expect the video size will remain at the initial pixel
  2456. // size of the fullscreen.
  2457. dsf = 2.f;
  2458. SetDeviceScaleFactor(dsf);
  2459. {
  2460. SCOPED_TRACE("Testing @ 2.0 device scale factor");
  2461. EXPECT_EQ(initial_root_window_size_pixels,
  2462. test_delegate->GetCurrentVideoSize());
  2463. // The recording service still tracks the up-to-date DSF and frame sink
  2464. // pixel size even though it doesn't change the video size from its initial
  2465. // value.
  2466. EXPECT_EQ(
  2467. dsf, test_delegate->recording_service()->GetCurrentDeviceScaleFactor());
  2468. EXPECT_EQ(ToPixels(root->bounds().size(), dsf),
  2469. test_delegate->GetCurrentFrameSinkSizeInPixels());
  2470. test_delegate->recording_service()->RequestAndWaitForVideoFrame(
  2471. base::BindOnce(&CaptureModeRecordingSizeTest::VerifyVideoFrame,
  2472. initial_root_window_size_pixels));
  2473. }
  2474. // When recording the fullscreen, the video size never changes, and remains at
  2475. // the initial pixel size of the recording. Hence, there should be no
  2476. // reconfigures.
  2477. EXPECT_EQ(0, test_delegate->recording_service()
  2478. ->GetNumberOfVideoEncoderReconfigures());
  2479. }
  2480. // The test is flaky. https://crbug.com/1287724.
  2481. TEST_F(CaptureModeRecordingSizeTest, DISABLED_CaptureAtPixelsRegion) {
  2482. float dsf = 1.6f;
  2483. SetDeviceScaleFactor(dsf);
  2484. auto* controller = StartVideoRecording(CaptureModeSource::kRegion);
  2485. auto* test_delegate =
  2486. static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
  2487. ASSERT_TRUE(test_delegate->recording_service());
  2488. {
  2489. SCOPED_TRACE("Testing @ 1.6 device scale factor");
  2490. const gfx::Size expected_video_size = ToPixels(user_region_.size(), dsf);
  2491. EXPECT_EQ(expected_video_size, test_delegate->GetCurrentVideoSize());
  2492. EXPECT_EQ(
  2493. dsf, test_delegate->recording_service()->GetCurrentDeviceScaleFactor());
  2494. test_delegate->recording_service()->RequestAndWaitForVideoFrame(
  2495. base::BindOnce(&CaptureModeRecordingSizeTest::VerifyVideoFrame,
  2496. expected_video_size));
  2497. }
  2498. // Change the DSF and expect the video size to change to match the new pixel
  2499. // size of the recorded target.
  2500. dsf = 2.f;
  2501. SetDeviceScaleFactor(dsf);
  2502. {
  2503. SCOPED_TRACE("Testing @ 2.0 device scale factor");
  2504. const gfx::Size expected_video_size = ToPixels(user_region_.size(), dsf);
  2505. EXPECT_EQ(expected_video_size, test_delegate->GetCurrentVideoSize());
  2506. EXPECT_EQ(
  2507. dsf, test_delegate->recording_service()->GetCurrentDeviceScaleFactor());
  2508. test_delegate->recording_service()->RequestAndWaitForVideoFrame(
  2509. base::BindOnce(&CaptureModeRecordingSizeTest::VerifyVideoFrame,
  2510. expected_video_size));
  2511. }
  2512. // Since the user chooses the capture region in DIPs, its corresponding pixel
  2513. // size will change when changing the device scale factor. Therefore, the
  2514. // encoder is expected to reconfigure once.
  2515. EXPECT_EQ(1, test_delegate->recording_service()
  2516. ->GetNumberOfVideoEncoderReconfigures());
  2517. }
  2518. // The test is flaky. https://crbug.com/1287724.
  2519. TEST_F(CaptureModeRecordingSizeTest, DISABLED_CaptureAtPixelsWindow) {
  2520. float dsf = 1.6f;
  2521. SetDeviceScaleFactor(dsf);
  2522. auto* controller = StartVideoRecording(CaptureModeSource::kWindow);
  2523. auto* test_delegate =
  2524. static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
  2525. ASSERT_TRUE(test_delegate->recording_service());
  2526. {
  2527. SCOPED_TRACE("Testing @ 1.6 device scale factor");
  2528. const gfx::Size expected_video_size =
  2529. ToPixels(window_->GetBoundsInRootWindow().size(), dsf);
  2530. EXPECT_EQ(expected_video_size, test_delegate->GetCurrentVideoSize());
  2531. EXPECT_EQ(
  2532. dsf, test_delegate->recording_service()->GetCurrentDeviceScaleFactor());
  2533. test_delegate->recording_service()->RequestAndWaitForVideoFrame(
  2534. base::BindOnce(&CaptureModeRecordingSizeTest::VerifyVideoFrame,
  2535. expected_video_size));
  2536. }
  2537. // Change the DSF and expect the video size to change to match the new pixel
  2538. // size of the recorded target.
  2539. dsf = 2.f;
  2540. SetDeviceScaleFactor(dsf);
  2541. {
  2542. SCOPED_TRACE("Testing @ 2.0 device scale factor");
  2543. const gfx::Size expected_video_size =
  2544. ToPixels(window_->GetBoundsInRootWindow().size(), dsf);
  2545. EXPECT_EQ(expected_video_size, test_delegate->GetCurrentVideoSize());
  2546. EXPECT_EQ(
  2547. dsf, test_delegate->recording_service()->GetCurrentDeviceScaleFactor());
  2548. test_delegate->recording_service()->RequestAndWaitForVideoFrame(
  2549. base::BindOnce(&CaptureModeRecordingSizeTest::VerifyVideoFrame,
  2550. expected_video_size));
  2551. }
  2552. // When changing the device scale factor, the DIPs size of the window doesn't
  2553. // change, but (like |kRegion|) its pixel size will. Hence, the
  2554. // reconfiguration.
  2555. EXPECT_EQ(1, test_delegate->recording_service()
  2556. ->GetNumberOfVideoEncoderReconfigures());
  2557. }
  2558. // Tests the behavior of screen recording with the presence of HDCP secure
  2559. // content on the screen in all capture mode sources (fullscreen, region, and
  2560. // window) depending on the test param.
  2561. class CaptureModeHdcpTest
  2562. : public CaptureModeTest,
  2563. public ::testing::WithParamInterface<CaptureModeSource> {
  2564. public:
  2565. CaptureModeHdcpTest() = default;
  2566. ~CaptureModeHdcpTest() override = default;
  2567. // CaptureModeTest:
  2568. void SetUp() override {
  2569. CaptureModeTest::SetUp();
  2570. window_ = CreateTestWindow(gfx::Rect(200, 200));
  2571. // Create a child window with protected content. This simulates the real
  2572. // behavior of a browser window hosting a page with protected content, where
  2573. // the window that has a protection mask is the RenderWidgetHostViewAura,
  2574. // which is a descendant of the BrowserFrame window which can get recorded.
  2575. protected_content_window_ = CreateTestWindow(gfx::Rect(150, 150));
  2576. window_->AddChild(protected_content_window_.get());
  2577. protection_delegate_ = std::make_unique<OutputProtectionDelegate>(
  2578. protected_content_window_.get());
  2579. CaptureModeController::Get()->SetUserCaptureRegion(gfx::Rect(20, 50),
  2580. /*by_user=*/true);
  2581. }
  2582. void TearDown() override {
  2583. protection_delegate_.reset();
  2584. protected_content_window_.reset();
  2585. window_.reset();
  2586. CaptureModeTest::TearDown();
  2587. }
  2588. // Enters the capture mode session.
  2589. void StartSessionForVideo() {
  2590. StartCaptureSession(GetParam(), CaptureModeType::kVideo);
  2591. }
  2592. // Attempts video recording from the capture mode source set by the test
  2593. // param.
  2594. void AttemptRecording() {
  2595. auto* controller = CaptureModeController::Get();
  2596. ASSERT_TRUE(controller->IsActive());
  2597. switch (GetParam()) {
  2598. case CaptureModeSource::kFullscreen:
  2599. case CaptureModeSource::kRegion:
  2600. controller->StartVideoRecordingImmediatelyForTesting();
  2601. break;
  2602. case CaptureModeSource::kWindow:
  2603. // Window capture mode selects the window under the cursor as the
  2604. // capture source.
  2605. auto* event_generator = GetEventGenerator();
  2606. event_generator->MoveMouseToCenterOf(window_.get());
  2607. controller->StartVideoRecordingImmediatelyForTesting();
  2608. break;
  2609. }
  2610. }
  2611. protected:
  2612. std::unique_ptr<aura::Window> window_;
  2613. std::unique_ptr<aura::Window> protected_content_window_;
  2614. std::unique_ptr<OutputProtectionDelegate> protection_delegate_;
  2615. };
  2616. TEST_P(CaptureModeHdcpTest, WindowBecomesProtectedWhileRecording) {
  2617. StartSessionForVideo();
  2618. AttemptRecording();
  2619. WaitForRecordingToStart();
  2620. auto* controller = CaptureModeController::Get();
  2621. EXPECT_TRUE(controller->is_recording_in_progress());
  2622. // The window becomes HDCP protected, which should end video recording.
  2623. base::HistogramTester histogram_tester;
  2624. protection_delegate_->SetProtection(display::CONTENT_PROTECTION_METHOD_HDCP,
  2625. base::DoNothing());
  2626. EXPECT_FALSE(controller->is_recording_in_progress());
  2627. histogram_tester.ExpectBucketCount(
  2628. kEndRecordingReasonInClamshellHistogramName,
  2629. EndRecordingReason::kHdcpInterruption, 1);
  2630. }
  2631. TEST_P(CaptureModeHdcpTest, ProtectedWindowDestruction) {
  2632. auto window_2 = CreateTestWindow(gfx::Rect(100, 50));
  2633. OutputProtectionDelegate protection_delegate_2(window_2.get());
  2634. protection_delegate_2.SetProtection(display::CONTENT_PROTECTION_METHOD_HDCP,
  2635. base::DoNothing());
  2636. StartSessionForVideo();
  2637. AttemptRecording();
  2638. // Recording cannot start because of another protected window on the screen,
  2639. // except when we're capturing a different |window_|.
  2640. auto* controller = CaptureModeController::Get();
  2641. EXPECT_FALSE(controller->IsActive());
  2642. if (GetParam() == CaptureModeSource::kWindow) {
  2643. WaitForRecordingToStart();
  2644. EXPECT_TRUE(controller->is_recording_in_progress());
  2645. controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
  2646. EXPECT_FALSE(controller->is_recording_in_progress());
  2647. // Wait for the video file to be saved so that we can start a new recording.
  2648. WaitForCaptureFileToBeSaved();
  2649. } else {
  2650. EXPECT_FALSE(controller->is_recording_in_progress());
  2651. }
  2652. // When the protected window is destroyed, it's possbile now to record from
  2653. // all capture sources.
  2654. window_2.reset();
  2655. StartSessionForVideo();
  2656. AttemptRecording();
  2657. WaitForRecordingToStart();
  2658. EXPECT_FALSE(controller->IsActive());
  2659. EXPECT_TRUE(controller->is_recording_in_progress());
  2660. }
  2661. TEST_P(CaptureModeHdcpTest, WindowBecomesProtectedBeforeRecording) {
  2662. protection_delegate_->SetProtection(display::CONTENT_PROTECTION_METHOD_HDCP,
  2663. base::DoNothing());
  2664. StartSessionForVideo();
  2665. AttemptRecording();
  2666. // Recording cannot even start.
  2667. auto* controller = CaptureModeController::Get();
  2668. EXPECT_FALSE(controller->is_recording_in_progress());
  2669. EXPECT_FALSE(controller->IsActive());
  2670. }
  2671. TEST_P(CaptureModeHdcpTest, ProtectedWindowInMultiDisplay) {
  2672. UpdateDisplay("500x400,401+0-500x400");
  2673. auto roots = Shell::GetAllRootWindows();
  2674. ASSERT_EQ(2u, roots.size());
  2675. protection_delegate_->SetProtection(display::CONTENT_PROTECTION_METHOD_HDCP,
  2676. base::DoNothing());
  2677. // Move the cursor to the secondary display before starting the session to
  2678. // make sure the session starts on that display.
  2679. auto* event_generator = GetEventGenerator();
  2680. MoveMouseToAndUpdateCursorDisplay(roots[1]->GetBoundsInScreen().CenterPoint(),
  2681. event_generator);
  2682. StartSessionForVideo();
  2683. // Also, make sure the selected region is in the secondary display.
  2684. auto* controller = CaptureModeController::Get();
  2685. EXPECT_EQ(controller->capture_mode_session()->current_root(), roots[1]);
  2686. AttemptRecording();
  2687. // Recording should be able to start (since the protected window is on the
  2688. // first display) unless the protected window itself is the one being
  2689. // recorded.
  2690. if (GetParam() == CaptureModeSource::kWindow) {
  2691. EXPECT_FALSE(controller->is_recording_in_progress());
  2692. } else {
  2693. WaitForRecordingToStart();
  2694. EXPECT_TRUE(controller->is_recording_in_progress());
  2695. // Moving the protected window to the display being recorded should
  2696. // terminate the recording.
  2697. base::HistogramTester histogram_tester;
  2698. window_util::MoveWindowToDisplay(window_.get(),
  2699. roots[1]->GetHost()->GetDisplayId());
  2700. ASSERT_EQ(window_->GetRootWindow(), roots[1]);
  2701. ASSERT_EQ(protected_content_window_->GetRootWindow(), roots[1]);
  2702. EXPECT_FALSE(controller->is_recording_in_progress());
  2703. histogram_tester.ExpectBucketCount(
  2704. kEndRecordingReasonInClamshellHistogramName,
  2705. EndRecordingReason::kHdcpInterruption, 1);
  2706. }
  2707. }
  2708. INSTANTIATE_TEST_SUITE_P(All,
  2709. CaptureModeHdcpTest,
  2710. testing::Values(CaptureModeSource::kFullscreen,
  2711. CaptureModeSource::kRegion,
  2712. CaptureModeSource::kWindow));
  2713. TEST_F(CaptureModeTest, ClosingWindowBeingRecorded) {
  2714. auto window = CreateTestWindow(gfx::Rect(200, 200));
  2715. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
  2716. auto* event_generator = GetEventGenerator();
  2717. event_generator->MoveMouseToCenterOf(window.get());
  2718. auto* controller = CaptureModeController::Get();
  2719. StartVideoRecordingImmediately();
  2720. EXPECT_TRUE(controller->is_recording_in_progress());
  2721. // The window should have a valid capture ID.
  2722. EXPECT_TRUE(window->subtree_capture_id().is_valid());
  2723. // Generate a couple of mouse moves, so that the second one gets throttled
  2724. // using the `VideoRecordingWatcher::cursor_events_throttle_timer_`. This is
  2725. // needed for a regression testing of https://crbug.com/1273609.
  2726. event_generator->MoveMouseBy(20, 30);
  2727. event_generator->MoveMouseBy(-10, -20);
  2728. // Closing the window being recorded should end video recording.
  2729. base::HistogramTester histogram_tester;
  2730. window.reset();
  2731. auto* stop_recording_button = Shell::GetPrimaryRootWindowController()
  2732. ->GetStatusAreaWidget()
  2733. ->stop_recording_button_tray();
  2734. EXPECT_FALSE(stop_recording_button->visible_preferred());
  2735. EXPECT_FALSE(controller->is_recording_in_progress());
  2736. WaitForCaptureFileToBeSaved();
  2737. EXPECT_FALSE(controller->video_recording_watcher_for_testing());
  2738. histogram_tester.ExpectBucketCount(
  2739. kEndRecordingReasonInClamshellHistogramName,
  2740. EndRecordingReason::kDisplayOrWindowClosing, 1);
  2741. }
  2742. TEST_F(CaptureModeTest, DetachDisplayWhileWindowRecording) {
  2743. UpdateDisplay("500x400,401+0-500x400");
  2744. // Create a window on the second display.
  2745. auto window = CreateTestWindow(gfx::Rect(450, 20, 200, 200));
  2746. auto roots = Shell::GetAllRootWindows();
  2747. ASSERT_EQ(2u, roots.size());
  2748. EXPECT_EQ(window->GetRootWindow(), roots[1]);
  2749. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kVideo);
  2750. auto* event_generator = GetEventGenerator();
  2751. MoveMouseToAndUpdateCursorDisplay(window->GetBoundsInScreen().CenterPoint(),
  2752. event_generator);
  2753. auto* controller = CaptureModeController::Get();
  2754. StartVideoRecordingImmediately();
  2755. EXPECT_TRUE(controller->is_recording_in_progress());
  2756. auto* stop_recording_button = RootWindowController::ForWindow(roots[1])
  2757. ->GetStatusAreaWidget()
  2758. ->stop_recording_button_tray();
  2759. EXPECT_TRUE(stop_recording_button->visible_preferred());
  2760. // Disconnecting the display, on which the window being recorded is located,
  2761. // should not end the recording. The window should be reparented to another
  2762. // display, and the stop-recording button should move with to that display.
  2763. RemoveSecondaryDisplay();
  2764. roots = Shell::GetAllRootWindows();
  2765. ASSERT_EQ(1u, roots.size());
  2766. EXPECT_TRUE(controller->is_recording_in_progress());
  2767. stop_recording_button = RootWindowController::ForWindow(roots[0])
  2768. ->GetStatusAreaWidget()
  2769. ->stop_recording_button_tray();
  2770. EXPECT_TRUE(stop_recording_button->visible_preferred());
  2771. }
  2772. TEST_F(CaptureModeTest, SuspendWhileSessionIsActive) {
  2773. auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  2774. CaptureModeType::kVideo);
  2775. EXPECT_TRUE(controller->IsActive());
  2776. power_manager_client()->SendSuspendImminent(
  2777. power_manager::SuspendImminent::IDLE);
  2778. EXPECT_FALSE(controller->IsActive());
  2779. }
  2780. TEST_F(CaptureModeTest, SuspendAfterCountdownStarts) {
  2781. // User NORMAL_DURATION for the countdown animation so we can have predictable
  2782. // timings.
  2783. ui::ScopedAnimationDurationScaleMode animation_scale(
  2784. ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
  2785. auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  2786. CaptureModeType::kVideo);
  2787. // Hit Enter to begin recording, wait for 1 second, then suspend the device.
  2788. auto* event_generator = GetEventGenerator();
  2789. SendKey(ui::VKEY_RETURN, event_generator);
  2790. WaitForSeconds(1);
  2791. power_manager_client()->SendSuspendImminent(
  2792. power_manager::SuspendImminent::IDLE);
  2793. EXPECT_FALSE(controller->IsActive());
  2794. EXPECT_FALSE(controller->is_recording_in_progress());
  2795. }
  2796. TEST_F(CaptureModeTest, SuspendAfterRecordingStarts) {
  2797. auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  2798. CaptureModeType::kVideo);
  2799. StartVideoRecordingImmediately();
  2800. EXPECT_TRUE(controller->is_recording_in_progress());
  2801. base::HistogramTester histogram_tester;
  2802. power_manager_client()->SendSuspendImminent(
  2803. power_manager::SuspendImminent::IDLE);
  2804. EXPECT_FALSE(controller->is_recording_in_progress());
  2805. histogram_tester.ExpectBucketCount(
  2806. kEndRecordingReasonInClamshellHistogramName,
  2807. EndRecordingReason::kImminentSuspend, 1);
  2808. }
  2809. TEST_F(CaptureModeTest, SwitchUsersWhileRecording) {
  2810. auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  2811. CaptureModeType::kVideo);
  2812. StartVideoRecordingImmediately();
  2813. base::HistogramTester histogram_tester;
  2814. EXPECT_TRUE(controller->is_recording_in_progress());
  2815. SwitchToUser2();
  2816. EXPECT_FALSE(controller->is_recording_in_progress());
  2817. histogram_tester.ExpectBucketCount(
  2818. kEndRecordingReasonInClamshellHistogramName,
  2819. EndRecordingReason::kActiveUserChange, 1);
  2820. }
  2821. TEST_F(CaptureModeTest, SwitchUsersAfterCountdownStarts) {
  2822. // User NORMAL_DURATION for the countdown animation so we can have predictable
  2823. // timings.
  2824. ui::ScopedAnimationDurationScaleMode animation_scale(
  2825. ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
  2826. auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  2827. CaptureModeType::kVideo);
  2828. // Hit Enter to begin recording, wait for 1 second, then switch users.
  2829. auto* event_generator = GetEventGenerator();
  2830. SendKey(ui::VKEY_RETURN, event_generator);
  2831. WaitForSeconds(1);
  2832. SwitchToUser2();
  2833. EXPECT_FALSE(controller->IsActive());
  2834. EXPECT_FALSE(controller->is_recording_in_progress());
  2835. }
  2836. TEST_F(CaptureModeTest, ClosingDisplayBeingFullscreenRecorded) {
  2837. UpdateDisplay("500x400,401+0-500x400");
  2838. auto roots = Shell::GetAllRootWindows();
  2839. ASSERT_EQ(2u, roots.size());
  2840. StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
  2841. auto* event_generator = GetEventGenerator();
  2842. MoveMouseToAndUpdateCursorDisplay(roots[1]->GetBoundsInScreen().CenterPoint(),
  2843. event_generator);
  2844. auto* controller = CaptureModeController::Get();
  2845. StartVideoRecordingImmediately();
  2846. EXPECT_TRUE(controller->is_recording_in_progress());
  2847. auto* stop_recording_button = RootWindowController::ForWindow(roots[1])
  2848. ->GetStatusAreaWidget()
  2849. ->stop_recording_button_tray();
  2850. EXPECT_TRUE(stop_recording_button->visible_preferred());
  2851. // Disconnecting the display being fullscreen recorded should end the
  2852. // recording and remove the stop recording button.
  2853. base::HistogramTester histogram_tester;
  2854. RemoveSecondaryDisplay();
  2855. roots = Shell::GetAllRootWindows();
  2856. ASSERT_EQ(1u, roots.size());
  2857. EXPECT_FALSE(controller->is_recording_in_progress());
  2858. stop_recording_button = RootWindowController::ForWindow(roots[0])
  2859. ->GetStatusAreaWidget()
  2860. ->stop_recording_button_tray();
  2861. EXPECT_FALSE(stop_recording_button->visible_preferred());
  2862. histogram_tester.ExpectBucketCount(
  2863. kEndRecordingReasonInClamshellHistogramName,
  2864. EndRecordingReason::kDisplayOrWindowClosing, 1);
  2865. }
  2866. TEST_F(CaptureModeTest, ShuttingDownWhileRecording) {
  2867. StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
  2868. auto* controller = CaptureModeController::Get();
  2869. StartVideoRecordingImmediately();
  2870. EXPECT_TRUE(controller->is_recording_in_progress());
  2871. // Exiting the test now will shut down ash while recording is in progress,
  2872. // there should be no crashes when
  2873. // VideoRecordingWatcher::OnChromeTerminating() terminates the recording.
  2874. }
  2875. // Tests that metrics are recorded properly for capture mode bar buttons.
  2876. TEST_F(CaptureModeTest, CaptureModeBarButtonTypeHistograms) {
  2877. constexpr char kClamshellHistogram[] =
  2878. "Ash.CaptureModeController.BarButtons.ClamshellMode";
  2879. constexpr char kTabletHistogram[] =
  2880. "Ash.CaptureModeController.BarButtons.TabletMode";
  2881. base::HistogramTester histogram_tester;
  2882. CaptureModeController::Get()->Start(CaptureModeEntryType::kQuickSettings);
  2883. auto* event_generator = GetEventGenerator();
  2884. // Tests each bar button in clamshell mode.
  2885. ClickOnView(GetImageToggleButton(), event_generator);
  2886. histogram_tester.ExpectBucketCount(
  2887. kClamshellHistogram, CaptureModeBarButtonType::kScreenCapture, 1);
  2888. ClickOnView(GetVideoToggleButton(), event_generator);
  2889. histogram_tester.ExpectBucketCount(
  2890. kClamshellHistogram, CaptureModeBarButtonType::kScreenRecord, 1);
  2891. ClickOnView(GetFullscreenToggleButton(), event_generator);
  2892. histogram_tester.ExpectBucketCount(kClamshellHistogram,
  2893. CaptureModeBarButtonType::kFull, 1);
  2894. ClickOnView(GetRegionToggleButton(), event_generator);
  2895. histogram_tester.ExpectBucketCount(kClamshellHistogram,
  2896. CaptureModeBarButtonType::kRegion, 1);
  2897. ClickOnView(GetWindowToggleButton(), event_generator);
  2898. histogram_tester.ExpectBucketCount(kClamshellHistogram,
  2899. CaptureModeBarButtonType::kWindow, 1);
  2900. // Enter tablet mode and test the bar buttons.
  2901. auto* tablet_mode_controller = Shell::Get()->tablet_mode_controller();
  2902. tablet_mode_controller->SetEnabledForTest(true);
  2903. ASSERT_TRUE(tablet_mode_controller->InTabletMode());
  2904. ClickOnView(GetImageToggleButton(), event_generator);
  2905. histogram_tester.ExpectBucketCount(
  2906. kTabletHistogram, CaptureModeBarButtonType::kScreenCapture, 1);
  2907. ClickOnView(GetVideoToggleButton(), event_generator);
  2908. histogram_tester.ExpectBucketCount(
  2909. kTabletHistogram, CaptureModeBarButtonType::kScreenRecord, 1);
  2910. ClickOnView(GetFullscreenToggleButton(), event_generator);
  2911. histogram_tester.ExpectBucketCount(kTabletHistogram,
  2912. CaptureModeBarButtonType::kFull, 1);
  2913. ClickOnView(GetRegionToggleButton(), event_generator);
  2914. histogram_tester.ExpectBucketCount(kTabletHistogram,
  2915. CaptureModeBarButtonType::kRegion, 1);
  2916. ClickOnView(GetWindowToggleButton(), event_generator);
  2917. histogram_tester.ExpectBucketCount(kTabletHistogram,
  2918. CaptureModeBarButtonType::kWindow, 1);
  2919. }
  2920. TEST_F(CaptureModeTest, CaptureSessionSwitchedModeMetric) {
  2921. constexpr char kHistogramName[] =
  2922. "Ash.CaptureModeController.SwitchesFromInitialCaptureMode";
  2923. base::HistogramTester histogram_tester;
  2924. histogram_tester.ExpectBucketCount(kHistogramName, false, 0);
  2925. histogram_tester.ExpectBucketCount(kHistogramName, true, 0);
  2926. // Perform a capture without switching modes. A false should be recorded.
  2927. auto* controller = StartImageRegionCapture();
  2928. SelectRegion(gfx::Rect(100, 100));
  2929. auto* event_generator = GetEventGenerator();
  2930. SendKey(ui::VKEY_RETURN, event_generator);
  2931. histogram_tester.ExpectBucketCount(kHistogramName, false, 1);
  2932. histogram_tester.ExpectBucketCount(kHistogramName, true, 0);
  2933. // Perform a capture after switching to fullscreen mode. A true should be
  2934. // recorded.
  2935. controller->Start(CaptureModeEntryType::kQuickSettings);
  2936. ClickOnView(GetFullscreenToggleButton(), event_generator);
  2937. SendKey(ui::VKEY_RETURN, event_generator);
  2938. histogram_tester.ExpectBucketCount(kHistogramName, false, 1);
  2939. histogram_tester.ExpectBucketCount(kHistogramName, true, 1);
  2940. // Perform a capture after switching to another mode and back to the original
  2941. // mode. A true should still be recorded as there was some switching done.
  2942. controller->Start(CaptureModeEntryType::kQuickSettings);
  2943. ClickOnView(GetRegionToggleButton(), event_generator);
  2944. ClickOnView(GetFullscreenToggleButton(), event_generator);
  2945. SendKey(ui::VKEY_RETURN, event_generator);
  2946. histogram_tester.ExpectBucketCount(kHistogramName, false, 1);
  2947. histogram_tester.ExpectBucketCount(kHistogramName, true, 2);
  2948. }
  2949. // Test that cancel recording during countdown won't cause crash.
  2950. TEST_F(CaptureModeTest, CancelCaptureDuringCountDown) {
  2951. ui::ScopedAnimationDurationScaleMode animation_scale(
  2952. ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
  2953. StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
  2954. // Hit Enter to begin recording, Wait for 1 second, then press ESC while count
  2955. // down is in progress.
  2956. auto* event_generator = GetEventGenerator();
  2957. SendKey(ui::VKEY_RETURN, event_generator);
  2958. WaitForSeconds(1);
  2959. CaptureModeTestApi test_api;
  2960. EXPECT_TRUE(test_api.IsInCountDownAnimation());
  2961. SendKey(ui::VKEY_ESCAPE, event_generator);
  2962. EXPECT_FALSE(test_api.IsInCountDownAnimation());
  2963. EXPECT_FALSE(test_api.IsSessionActive());
  2964. EXPECT_FALSE(test_api.IsVideoRecordingInProgress());
  2965. }
  2966. TEST_F(CaptureModeTest, EscDuringCountDownWhileSettingsOpen) {
  2967. ui::ScopedAnimationDurationScaleMode animation_scale(
  2968. ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
  2969. StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
  2970. // Hitting Esc while the settings menu is open and the count down is in
  2971. // progress should end the session directly.
  2972. auto* event_generator = GetEventGenerator();
  2973. ClickOnView(GetSettingsButton(), event_generator);
  2974. EXPECT_TRUE(GetCaptureModeSettingsWidget());
  2975. SendKey(ui::VKEY_RETURN, event_generator);
  2976. WaitForSeconds(1);
  2977. CaptureModeTestApi test_api;
  2978. EXPECT_TRUE(test_api.IsInCountDownAnimation());
  2979. SendKey(ui::VKEY_ESCAPE, event_generator);
  2980. EXPECT_FALSE(test_api.IsInCountDownAnimation());
  2981. EXPECT_FALSE(test_api.IsSessionActive());
  2982. EXPECT_FALSE(test_api.IsVideoRecordingInProgress());
  2983. }
  2984. // Tests that metrics are recorded properly for capture region adjustments.
  2985. TEST_F(CaptureModeTest, NumberOfCaptureRegionAdjustmentsHistogram) {
  2986. constexpr char kClamshellHistogram[] =
  2987. "Ash.CaptureModeController.CaptureRegionAdjusted.ClamshellMode";
  2988. constexpr char kTabletHistogram[] =
  2989. "Ash.CaptureModeController.CaptureRegionAdjusted.TabletMode";
  2990. base::HistogramTester histogram_tester;
  2991. UpdateDisplay("800x700");
  2992. auto* controller = StartImageRegionCapture();
  2993. // Create the initial region.
  2994. const gfx::Rect target_region(gfx::Rect(200, 200, 400, 400));
  2995. SelectRegion(target_region);
  2996. auto resize_and_reset_region = [](ui::test::EventGenerator* event_generator,
  2997. const gfx::Point& top_right) {
  2998. // Enlarges the region and then resize it back to its original size.
  2999. event_generator->set_current_screen_location(top_right);
  3000. event_generator->DragMouseTo(top_right + gfx::Vector2d(50, 50));
  3001. event_generator->DragMouseTo(top_right);
  3002. };
  3003. auto move_and_reset_region = [](ui::test::EventGenerator* event_generator,
  3004. const gfx::Point& drag_point) {
  3005. // Moves the region and then moves it back to its original position.
  3006. event_generator->set_current_screen_location(drag_point);
  3007. event_generator->DragMouseTo(drag_point + gfx::Vector2d(-50, -50));
  3008. event_generator->DragMouseTo(drag_point);
  3009. };
  3010. // Resize the region twice by dragging the top right of the region out and
  3011. // then back again.
  3012. auto* event_generator = GetEventGenerator();
  3013. auto top_right = target_region.top_right();
  3014. resize_and_reset_region(event_generator, top_right);
  3015. // Move the region twice by dragging within the region.
  3016. const gfx::Point drag_point(300, 300);
  3017. move_and_reset_region(event_generator, drag_point);
  3018. // Perform a capture to record the count.
  3019. controller->PerformCapture();
  3020. histogram_tester.ExpectBucketCount(kClamshellHistogram, 4, 1);
  3021. // Create a new image region capture. Move the region twice then change
  3022. // sources to fullscreen and back to region. This toggle should reset the
  3023. // count. Perform a capture to record the count.
  3024. StartImageRegionCapture();
  3025. move_and_reset_region(event_generator, drag_point);
  3026. controller->SetSource(CaptureModeSource::kFullscreen);
  3027. controller->SetSource(CaptureModeSource::kRegion);
  3028. controller->PerformCapture();
  3029. histogram_tester.ExpectBucketCount(kClamshellHistogram, 0, 1);
  3030. // Enter tablet mode and restart the capture session. The capture region
  3031. // should be remembered.
  3032. auto* tablet_mode_controller = Shell::Get()->tablet_mode_controller();
  3033. tablet_mode_controller->SetEnabledForTest(true);
  3034. ASSERT_TRUE(tablet_mode_controller->InTabletMode());
  3035. StartImageRegionCapture();
  3036. ASSERT_EQ(target_region, controller->user_capture_region());
  3037. // Resize the region twice by dragging the top right of the region out and
  3038. // then back again.
  3039. resize_and_reset_region(event_generator, top_right);
  3040. // Move the region twice by dragging within the region.
  3041. move_and_reset_region(event_generator, drag_point);
  3042. // Perform a capture to record the count.
  3043. controller->PerformCapture();
  3044. histogram_tester.ExpectBucketCount(kTabletHistogram, 4, 1);
  3045. // Restart the region capture and resize it. Then create a new region by
  3046. // dragging outside of the existing capture region. This should reset the
  3047. // counter. Change source to record a sample.
  3048. StartImageRegionCapture();
  3049. resize_and_reset_region(event_generator, top_right);
  3050. SelectRegion(gfx::Rect(0, 0, 100, 100));
  3051. controller->PerformCapture();
  3052. histogram_tester.ExpectBucketCount(kTabletHistogram, 0, 1);
  3053. }
  3054. TEST_F(CaptureModeTest, FullscreenCapture) {
  3055. ui::ScopedAnimationDurationScaleMode animation_scale(
  3056. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  3057. CaptureModeController* controller = StartCaptureSession(
  3058. CaptureModeSource::kFullscreen, CaptureModeType::kImage);
  3059. EXPECT_TRUE(controller->IsActive());
  3060. // Press anywhere to capture image.
  3061. auto* event_generator = GetEventGenerator();
  3062. event_generator->ClickLeftButton();
  3063. EXPECT_FALSE(controller->IsActive());
  3064. controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  3065. CaptureModeType::kVideo);
  3066. EXPECT_TRUE(controller->IsActive());
  3067. // Press anywhere to capture video.
  3068. event_generator->ClickLeftButton();
  3069. WaitForRecordingToStart();
  3070. EXPECT_FALSE(controller->IsActive());
  3071. }
  3072. // Tests that metrics are recorded properly for capture mode configurations when
  3073. // taking a screenshot.
  3074. TEST_F(CaptureModeTest, ScreenshotConfigurationHistogram) {
  3075. constexpr char kClamshellHistogram[] =
  3076. "Ash.CaptureModeController.CaptureConfiguration.ClamshellMode";
  3077. constexpr char kTabletHistogram[] =
  3078. "Ash.CaptureModeController.CaptureConfiguration.TabletMode";
  3079. base::HistogramTester histogram_tester;
  3080. // Use a set display size as we will be choosing points in this test.
  3081. UpdateDisplay("800x700");
  3082. // Create a window for window captures later.
  3083. std::unique_ptr<aura::Window> window1(
  3084. CreateTestWindow(gfx::Rect(600, 600, 100, 100)));
  3085. // Perform a fullscreen screenshot.
  3086. auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  3087. CaptureModeType::kImage);
  3088. controller->PerformCapture();
  3089. histogram_tester.ExpectBucketCount(
  3090. kClamshellHistogram, CaptureModeConfiguration::kFullscreenScreenshot, 1);
  3091. // Perform a region screenshot.
  3092. controller =
  3093. StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kImage);
  3094. const gfx::Rect capture_region(200, 200, 400, 400);
  3095. SelectRegion(capture_region);
  3096. controller->PerformCapture();
  3097. histogram_tester.ExpectBucketCount(
  3098. kClamshellHistogram, CaptureModeConfiguration::kRegionScreenshot, 1);
  3099. // Perform a window screenshot.
  3100. controller =
  3101. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kImage);
  3102. auto* event_generator = GetEventGenerator();
  3103. event_generator->MoveMouseToCenterOf(window1.get());
  3104. EXPECT_EQ(window1.get(),
  3105. controller->capture_mode_session()->GetSelectedWindow());
  3106. controller->PerformCapture();
  3107. histogram_tester.ExpectBucketCount(
  3108. kClamshellHistogram, CaptureModeConfiguration::kWindowScreenshot, 1);
  3109. // Switch to tablet mode.
  3110. auto* tablet_mode_controller = Shell::Get()->tablet_mode_controller();
  3111. tablet_mode_controller->SetEnabledForTest(true);
  3112. ASSERT_TRUE(tablet_mode_controller->InTabletMode());
  3113. // Perform a fullscreen screenshot.
  3114. controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  3115. CaptureModeType::kImage);
  3116. controller->PerformCapture();
  3117. histogram_tester.ExpectBucketCount(
  3118. kTabletHistogram, CaptureModeConfiguration::kFullscreenScreenshot, 1);
  3119. // Perform a region screenshot.
  3120. controller =
  3121. StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kImage);
  3122. controller->PerformCapture();
  3123. histogram_tester.ExpectBucketCount(
  3124. kTabletHistogram, CaptureModeConfiguration::kRegionScreenshot, 1);
  3125. // Perform a window screenshot.
  3126. controller =
  3127. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kImage);
  3128. event_generator->MoveMouseToCenterOf(window1.get());
  3129. EXPECT_EQ(window1.get(),
  3130. controller->capture_mode_session()->GetSelectedWindow());
  3131. controller->PerformCapture();
  3132. histogram_tester.ExpectBucketCount(
  3133. kTabletHistogram, CaptureModeConfiguration::kWindowScreenshot, 1);
  3134. }
  3135. // Tests that there is no crash when touching the capture label widget in tablet
  3136. // mode when capturing a window. Regression test for https://crbug.com/1152938.
  3137. TEST_F(CaptureModeTest, TabletTouchCaptureLabelWidgetWindowMode) {
  3138. SwitchToTabletMode();
  3139. // Enter capture window mode.
  3140. CaptureModeController* controller =
  3141. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kImage);
  3142. ASSERT_TRUE(controller->IsActive());
  3143. // Press and release on where the capture label widget would be.
  3144. auto* event_generator = GetEventGenerator();
  3145. DCHECK(GetCaptureModeLabelWidget());
  3146. event_generator->set_current_screen_location(
  3147. GetCaptureModeLabelWidget()->GetWindowBoundsInScreen().CenterPoint());
  3148. event_generator->PressTouch();
  3149. event_generator->ReleaseTouch();
  3150. // There are no windows and home screen window is excluded from window capture
  3151. // mode, so capture mode will still remain active.
  3152. EXPECT_TRUE(Shell::Get()->app_list_controller()->IsHomeScreenVisible());
  3153. EXPECT_TRUE(controller->IsActive());
  3154. }
  3155. // Tests that after rotating a display, the capture session widgets are updated
  3156. // and the capture region is reset.
  3157. TEST_F(CaptureModeTest, DisplayRotation) {
  3158. UpdateDisplay("1200x600");
  3159. auto* controller = StartImageRegionCapture();
  3160. SelectRegion(gfx::Rect(1200, 400));
  3161. OpenSettingsView();
  3162. // Rotate the primary display by 90 degrees. Test that the region, capture
  3163. // bar and capture settings fit within the rotated bounds, and the capture
  3164. // label widget is still centered in the region.
  3165. Shell::Get()->display_manager()->SetDisplayRotation(
  3166. WindowTreeHostManager::GetPrimaryDisplayId(), display::Display::ROTATE_90,
  3167. display::Display::RotationSource::USER);
  3168. const gfx::Rect rotated_root_bounds(600, 1200);
  3169. EXPECT_TRUE(rotated_root_bounds.Contains(controller->user_capture_region()));
  3170. const gfx::Rect capture_bar_bounds =
  3171. GetCaptureModeBarView()->GetBoundsInScreen();
  3172. const gfx::Rect settings_bounds =
  3173. CaptureModeSettingsTestApi().GetSettingsView()->GetBoundsInScreen();
  3174. EXPECT_TRUE(rotated_root_bounds.Contains(capture_bar_bounds));
  3175. EXPECT_TRUE(rotated_root_bounds.Contains(settings_bounds));
  3176. // Verify that the space between the bottom of the settings and the top
  3177. // of the capture bar is `kSpaceBetweenCaptureBarAndSettingsMenu`.
  3178. EXPECT_EQ(capture_bar_bounds.y() - settings_bounds.bottom(),
  3179. capture_mode::kSpaceBetweenCaptureBarAndSettingsMenu);
  3180. views::Widget* capture_label_widget = GetCaptureModeLabelWidget();
  3181. ASSERT_TRUE(capture_label_widget);
  3182. EXPECT_EQ(controller->user_capture_region().CenterPoint(),
  3183. capture_label_widget->GetWindowBoundsInScreen().CenterPoint());
  3184. }
  3185. TEST_F(CaptureModeTest, DisplayBoundsChange) {
  3186. UpdateDisplay("1200x600");
  3187. auto* controller = StartImageRegionCapture();
  3188. SelectRegion(gfx::Rect(1200, 400));
  3189. // Shrink the display. The capture region should shrink, and the capture bar
  3190. // should be adjusted to be centered.
  3191. UpdateDisplay("700x600");
  3192. EXPECT_EQ(gfx::Rect(700, 400), controller->user_capture_region());
  3193. EXPECT_EQ(350,
  3194. GetCaptureModeBarView()->GetBoundsInScreen().CenterPoint().x());
  3195. }
  3196. TEST_F(CaptureModeTest, ReenterOnSmallerDisplay) {
  3197. UpdateDisplay("1200x600,1201+0-700x600");
  3198. // Start off with the primary display as the targeted display. Create a region
  3199. // that fits the primary display but would be too big for the secondary
  3200. // display.
  3201. auto* event_generator = GetEventGenerator();
  3202. MoveMouseToAndUpdateCursorDisplay(gfx::Point(700, 300), event_generator);
  3203. auto* controller = StartImageRegionCapture();
  3204. SelectRegion(gfx::Rect(1200, 400));
  3205. EXPECT_EQ(gfx::Rect(1200, 400), controller->user_capture_region());
  3206. controller->Stop();
  3207. // Make the secondary display the targeted display. Test that the region has
  3208. // shrunk to fit the display.
  3209. MoveMouseToAndUpdateCursorDisplay(gfx::Point(1500, 300), event_generator);
  3210. StartImageRegionCapture();
  3211. EXPECT_EQ(gfx::Rect(700, 400), controller->user_capture_region());
  3212. }
  3213. // Tests tabbing when in capture window mode.
  3214. TEST_F(CaptureModeTest, KeyboardNavigationBasic) {
  3215. auto* controller =
  3216. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kImage);
  3217. using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
  3218. CaptureModeSessionTestApi test_api(controller->capture_mode_session());
  3219. // Initially nothing is focused.
  3220. EXPECT_EQ(FocusGroup::kNone, test_api.GetCurrentFocusGroup());
  3221. EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
  3222. // Tab once, we are now focusing the type and source buttons group on the
  3223. // capture bar.
  3224. auto* event_generator = GetEventGenerator();
  3225. SendKey(ui::VKEY_TAB, event_generator);
  3226. EXPECT_EQ(FocusGroup::kTypeSource, test_api.GetCurrentFocusGroup());
  3227. EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
  3228. // Tab four times to focus the last source button (window mode button).
  3229. SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/4);
  3230. EXPECT_EQ(FocusGroup::kTypeSource, test_api.GetCurrentFocusGroup());
  3231. EXPECT_EQ(4u, test_api.GetCurrentFocusIndex());
  3232. // Tab once to focus the settings and close buttons group on the capture bar.
  3233. SendKey(ui::VKEY_TAB, event_generator);
  3234. EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
  3235. EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
  3236. // Shift tab to focus the last source button again.
  3237. SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
  3238. EXPECT_EQ(FocusGroup::kTypeSource, test_api.GetCurrentFocusGroup());
  3239. EXPECT_EQ(4u, test_api.GetCurrentFocusIndex());
  3240. // Press esc to clear focus, but remain in capture mode.
  3241. SendKey(ui::VKEY_ESCAPE, event_generator);
  3242. EXPECT_EQ(FocusGroup::kNone, test_api.GetCurrentFocusGroup());
  3243. EXPECT_TRUE(controller->IsActive());
  3244. // Tests that pressing esc when there is no focus will exit capture mode.
  3245. SendKey(ui::VKEY_ESCAPE, event_generator);
  3246. EXPECT_FALSE(controller->IsActive());
  3247. }
  3248. // Tests tabbing through windows on multiple displays when in capture window
  3249. // mode.
  3250. TEST_F(CaptureModeTest, KeyboardNavigationTabThroughWindowsOnMultipleDisplays) {
  3251. UpdateDisplay("800x700,801+0-800x700");
  3252. std::vector<aura::Window*> root_windows = Shell::GetAllRootWindows();
  3253. ASSERT_EQ(2u, root_windows.size());
  3254. // Create three windows, one of them is a modal transient child.
  3255. std::unique_ptr<aura::Window> window1(
  3256. CreateTestWindow(gfx::Rect(0, 0, 200, 200)));
  3257. auto window1_transient = CreateTransientModalChildWindow(
  3258. gfx::Rect(20, 30, 200, 150), window1.get());
  3259. std::unique_ptr<aura::Window> window2(
  3260. CreateTestWindow(gfx::Rect(900, 0, 200, 200)));
  3261. auto* controller =
  3262. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kImage);
  3263. CaptureModeSession* capture_mode_session = controller->capture_mode_session();
  3264. using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
  3265. CaptureModeSessionTestApi test_api(capture_mode_session);
  3266. // Initially nothing is focused.
  3267. EXPECT_EQ(FocusGroup::kNone, test_api.GetCurrentFocusGroup());
  3268. EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
  3269. // Tab five times, we are now focusing the window mode button on the
  3270. // capture bar.
  3271. auto* event_generator = GetEventGenerator();
  3272. SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/5);
  3273. EXPECT_EQ(FocusGroup::kTypeSource, test_api.GetCurrentFocusGroup());
  3274. EXPECT_EQ(4u, test_api.GetCurrentFocusIndex());
  3275. // Enter space to select window mode.
  3276. SendKey(ui::VKEY_SPACE, event_generator);
  3277. EXPECT_EQ(FocusGroup::kTypeSource, test_api.GetCurrentFocusGroup());
  3278. EXPECT_EQ(CaptureModeSource::kWindow, controller->source());
  3279. // Tab once, we are now focusing |window2| and capture mode bar is on
  3280. // display2.
  3281. SendKey(ui::VKEY_TAB, event_generator);
  3282. EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
  3283. EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
  3284. EXPECT_EQ(window2.get(), capture_mode_session->GetSelectedWindow());
  3285. EXPECT_EQ(root_windows[1], capture_mode_session->current_root());
  3286. // Tab once, we are now focusing |window1_transient|. Since
  3287. // |window1_transient| is on display1, capture mode bar will be moved to
  3288. // display1 as well.
  3289. SendKey(ui::VKEY_TAB, event_generator);
  3290. EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
  3291. EXPECT_EQ(1u, test_api.GetCurrentFocusIndex());
  3292. EXPECT_EQ(window1_transient.get(), capture_mode_session->GetSelectedWindow());
  3293. EXPECT_EQ(root_windows[0], capture_mode_session->current_root());
  3294. // Tab once, we are now focusing |window1|. Capture mode bar still stays on
  3295. // display1.
  3296. SendKey(ui::VKEY_TAB, event_generator);
  3297. EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
  3298. EXPECT_EQ(2u, test_api.GetCurrentFocusIndex());
  3299. EXPECT_EQ(window1.get(), capture_mode_session->GetSelectedWindow());
  3300. EXPECT_EQ(root_windows[0], capture_mode_session->current_root());
  3301. // Press space, make sure nothing is changed and no crash.
  3302. SendKey(ui::VKEY_SPACE, event_generator);
  3303. EXPECT_TRUE(controller->IsActive());
  3304. EXPECT_EQ(window1.get(), capture_mode_session->GetSelectedWindow());
  3305. EXPECT_EQ(root_windows[0], capture_mode_session->current_root());
  3306. // Tab once to focus the settings and close buttons group on the capture bar.
  3307. SendKey(ui::VKEY_TAB, event_generator);
  3308. EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
  3309. EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
  3310. // Shift tab to focus |window1| again.
  3311. SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
  3312. EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
  3313. EXPECT_EQ(2u, test_api.GetCurrentFocusIndex());
  3314. EXPECT_EQ(window1.get(), capture_mode_session->GetSelectedWindow());
  3315. // Shift tab to focus |window1_transient|.
  3316. SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
  3317. EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
  3318. EXPECT_EQ(1u, test_api.GetCurrentFocusIndex());
  3319. EXPECT_EQ(window1_transient.get(), capture_mode_session->GetSelectedWindow());
  3320. EXPECT_EQ(root_windows[0], capture_mode_session->current_root());
  3321. // Shift tab to focus |window2|. Capture mode bar will be moved to display2 as
  3322. // well.
  3323. SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
  3324. EXPECT_EQ(FocusGroup::kCaptureWindow, test_api.GetCurrentFocusGroup());
  3325. EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
  3326. EXPECT_EQ(window2.get(), capture_mode_session->GetSelectedWindow());
  3327. EXPECT_EQ(root_windows[1], capture_mode_session->current_root());
  3328. // Press esc to clear focus, but remain in capture mode with |window2|
  3329. // selected.
  3330. SendKey(ui::VKEY_ESCAPE, event_generator);
  3331. EXPECT_EQ(FocusGroup::kNone, test_api.GetCurrentFocusGroup());
  3332. EXPECT_TRUE(controller->IsActive());
  3333. EXPECT_EQ(window2.get(), capture_mode_session->GetSelectedWindow());
  3334. EXPECT_EQ(root_windows[1], capture_mode_session->current_root());
  3335. // Press return. Since there's a selected window, capture mode will
  3336. // be ended after capturing the selected window.
  3337. SendKey(ui::VKEY_RETURN, event_generator);
  3338. EXPECT_FALSE(controller->IsActive());
  3339. }
  3340. // Tests that a click will remove focus.
  3341. TEST_F(CaptureModeTest, KeyboardNavigationClicksRemoveFocus) {
  3342. auto* controller = StartImageRegionCapture();
  3343. auto* event_generator = GetEventGenerator();
  3344. CaptureModeSessionTestApi test_api(controller->capture_mode_session());
  3345. SendKey(ui::VKEY_TAB, event_generator);
  3346. EXPECT_TRUE(test_api.HasFocus());
  3347. event_generator->ClickLeftButton();
  3348. EXPECT_FALSE(test_api.HasFocus());
  3349. }
  3350. // Tests that pressing space on a focused button will click it.
  3351. TEST_F(CaptureModeTest, KeyboardNavigationSpaceToClickButtons) {
  3352. auto* controller = StartImageRegionCapture();
  3353. SelectRegion(gfx::Rect(200, 200));
  3354. auto* event_generator = GetEventGenerator();
  3355. // Tab to the button which changes the capture type to video and hit space.
  3356. SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/2);
  3357. SendKey(ui::VKEY_SPACE, event_generator);
  3358. EXPECT_EQ(CaptureModeType::kVideo, controller->type());
  3359. // Shift tab and space to change the capture type back to image.
  3360. SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
  3361. SendKey(ui::VKEY_SPACE, event_generator);
  3362. EXPECT_EQ(CaptureModeType::kImage, controller->type());
  3363. // Tab to the fullscreen button and hit space.
  3364. SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/2);
  3365. SendKey(ui::VKEY_SPACE, event_generator);
  3366. EXPECT_EQ(CaptureModeSource::kFullscreen, controller->source());
  3367. // Tab to the region button and hit space to return to region capture mode.
  3368. SendKey(ui::VKEY_TAB, event_generator);
  3369. SendKey(ui::VKEY_SPACE, event_generator);
  3370. EXPECT_EQ(CaptureModeSource::kRegion, controller->source());
  3371. // Tab to the capture button and hit space to perform a capture, which exits
  3372. // capture mode.
  3373. SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/11);
  3374. SendKey(ui::VKEY_SPACE, event_generator);
  3375. EXPECT_FALSE(controller->IsActive());
  3376. }
  3377. // Tests that functionality to create and adjust a region with keyboard
  3378. // shortcuts works as intended.
  3379. TEST_F(CaptureModeTest, KeyboardNavigationSelectRegion) {
  3380. auto* controller = StartImageRegionCapture();
  3381. auto* event_generator = GetEventGenerator();
  3382. ASSERT_TRUE(controller->user_capture_region().IsEmpty());
  3383. // Test that hitting space will create a default region.
  3384. SendKey(ui::VKEY_SPACE, event_generator);
  3385. gfx::Rect capture_region = controller->user_capture_region();
  3386. EXPECT_FALSE(capture_region.IsEmpty());
  3387. // Test that hitting an arrow key will do nothing as the selection region is
  3388. // not focused initially.
  3389. SendKey(ui::VKEY_RIGHT, event_generator);
  3390. EXPECT_EQ(capture_region, controller->user_capture_region());
  3391. const int arrow_shift = capture_mode::kArrowKeyboardRegionChangeDp;
  3392. // Hit tab until the whole region is focused.
  3393. SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/6);
  3394. CaptureModeSessionTestApi test_api(controller->capture_mode_session());
  3395. EXPECT_EQ(CaptureModeSessionFocusCycler::FocusGroup::kSelection,
  3396. test_api.GetCurrentFocusGroup());
  3397. EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
  3398. // Arrow keys should shift the whole region.
  3399. SendKey(ui::VKEY_RIGHT, event_generator);
  3400. EXPECT_EQ(capture_region.origin() + gfx::Vector2d(arrow_shift, 0),
  3401. controller->user_capture_region().origin());
  3402. EXPECT_EQ(capture_region.size(), controller->user_capture_region().size());
  3403. SendKey(ui::VKEY_RIGHT, event_generator, ui::EF_SHIFT_DOWN);
  3404. EXPECT_EQ(
  3405. capture_region.origin() +
  3406. gfx::Vector2d(
  3407. arrow_shift + capture_mode::kShiftArrowKeyboardRegionChangeDp, 0),
  3408. controller->user_capture_region().origin());
  3409. EXPECT_EQ(capture_region.size(), controller->user_capture_region().size());
  3410. // Hit tab so that the top left affordance circle is focused. Left and up keys
  3411. // should enlarge the region, right and bottom keys should shrink the region.
  3412. capture_region = controller->user_capture_region();
  3413. SendKey(ui::VKEY_TAB, event_generator);
  3414. SendKey(ui::VKEY_LEFT, event_generator);
  3415. SendKey(ui::VKEY_UP, event_generator);
  3416. EXPECT_EQ(capture_region.size() + gfx::Size(arrow_shift, arrow_shift),
  3417. controller->user_capture_region().size());
  3418. SendKey(ui::VKEY_RIGHT, event_generator);
  3419. SendKey(ui::VKEY_DOWN, event_generator);
  3420. EXPECT_EQ(capture_region.size(), controller->user_capture_region().size());
  3421. // Tab until we focus the bottom right affordance circle. Left and up keys
  3422. // should shrink the region, right and bottom keys should enlarge the region.
  3423. SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/4);
  3424. SendKey(ui::VKEY_LEFT, event_generator);
  3425. SendKey(ui::VKEY_UP, event_generator);
  3426. EXPECT_EQ(capture_region.size() - gfx::Size(arrow_shift, arrow_shift),
  3427. controller->user_capture_region().size());
  3428. SendKey(ui::VKEY_RIGHT, event_generator);
  3429. SendKey(ui::VKEY_DOWN, event_generator);
  3430. EXPECT_EQ(capture_region.size(), controller->user_capture_region().size());
  3431. }
  3432. // Tests behavior regarding the default region when using keyboard navigation.
  3433. TEST_F(CaptureModeTest, KeyboardNavigationDefaultRegion) {
  3434. auto* controller = StartImageRegionCapture();
  3435. auto* event_generator = GetEventGenerator();
  3436. ASSERT_TRUE(controller->user_capture_region().IsEmpty());
  3437. // Hit space when nothing is focused to get the expected default capture
  3438. // region.
  3439. SendKey(ui::VKEY_SPACE, event_generator);
  3440. const gfx::Rect expected_default_region = controller->user_capture_region();
  3441. SelectRegion(gfx::Rect(20, 20, 200, 200));
  3442. // Hit space when there is an existing region. Tests that the region remains
  3443. // unchanged.
  3444. SendKey(ui::VKEY_SPACE, event_generator);
  3445. EXPECT_EQ(gfx::Rect(20, 20, 200, 200), controller->user_capture_region());
  3446. // Tab to the image toggle button. Tests that hitting space does not change
  3447. // the region size.
  3448. SelectRegion(gfx::Rect());
  3449. SendKey(ui::VKEY_TAB, event_generator);
  3450. CaptureModeSessionTestApi test_api(controller->capture_mode_session());
  3451. ASSERT_EQ(CaptureModeSessionFocusCycler::FocusGroup::kTypeSource,
  3452. test_api.GetCurrentFocusGroup());
  3453. ASSERT_EQ(0u, test_api.GetCurrentFocusIndex());
  3454. SendKey(ui::VKEY_SPACE, event_generator);
  3455. EXPECT_EQ(gfx::Rect(), controller->user_capture_region());
  3456. // Tests that hitting space while focusing the region toggle button when in
  3457. // region capture mode will make the capture region the default size.
  3458. // SelectRegion removes focus since it uses mouse clicks.
  3459. SelectRegion(gfx::Rect());
  3460. SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE,
  3461. /*count=*/4);
  3462. SendKey(ui::VKEY_SPACE, event_generator);
  3463. EXPECT_EQ(expected_default_region, controller->user_capture_region());
  3464. // Tests that hitting space while focusing the region toggle button when not
  3465. // in region capture mode does nothing to the capture region.
  3466. SelectRegion(gfx::Rect());
  3467. ClickOnView(GetWindowToggleButton(), event_generator);
  3468. SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE,
  3469. /*count=*/4);
  3470. ASSERT_EQ(CaptureModeSessionFocusCycler::FocusGroup::kTypeSource,
  3471. test_api.GetCurrentFocusGroup());
  3472. ASSERT_EQ(3u, test_api.GetCurrentFocusIndex());
  3473. SendKey(ui::VKEY_SPACE, event_generator);
  3474. EXPECT_EQ(gfx::Rect(), controller->user_capture_region());
  3475. }
  3476. // Tests that accessibility overrides are set as expected on capture mode
  3477. // widgets.
  3478. TEST_F(CaptureModeTest, AccessibilityFocusAnnotator) {
  3479. StartImageRegionCapture();
  3480. // Helper that takes in a current widget and checks if the accessibility next
  3481. // and previous focus widgets match the given.
  3482. auto check_a11y_overrides = [](const std::string& id, views::Widget* widget,
  3483. views::Widget* expected_previous,
  3484. views::Widget* expected_next) -> void {
  3485. SCOPED_TRACE(id);
  3486. views::View* contents_view = widget->GetContentsView();
  3487. views::ViewAccessibility& view_accessibility =
  3488. contents_view->GetViewAccessibility();
  3489. EXPECT_EQ(expected_previous, view_accessibility.GetPreviousFocus());
  3490. EXPECT_EQ(expected_next, view_accessibility.GetNextFocus());
  3491. };
  3492. // With no region, there is no capture label button and no settings menu
  3493. // opened, so the bar is the only focusable capture session widget.
  3494. views::Widget* bar_widget = GetCaptureModeBarWidget();
  3495. check_a11y_overrides("bar", bar_widget, nullptr, nullptr);
  3496. // With a region, the focus should go from the bar widget to the label widget
  3497. // and back.
  3498. SendKey(ui::VKEY_SPACE, GetEventGenerator());
  3499. views::Widget* label_widget = GetCaptureModeLabelWidget();
  3500. check_a11y_overrides("bar", bar_widget, label_widget, label_widget);
  3501. check_a11y_overrides("label", label_widget, bar_widget, bar_widget);
  3502. // With a settings menu open, the focus should go from the bar widget to the
  3503. // label widget to the settings widget and back to the bar widget.
  3504. ClickOnView(GetSettingsButton(), GetEventGenerator());
  3505. views::Widget* settings_widget = GetCaptureModeSettingsWidget();
  3506. ASSERT_TRUE(settings_widget);
  3507. check_a11y_overrides("bar", bar_widget, settings_widget, label_widget);
  3508. check_a11y_overrides("label", label_widget, bar_widget, settings_widget);
  3509. check_a11y_overrides("settings", settings_widget, label_widget, bar_widget);
  3510. }
  3511. // Tests that a captured image is written to the clipboard.
  3512. TEST_F(CaptureModeTest, ClipboardWrite) {
  3513. auto* clipboard = ui::Clipboard::GetForCurrentThread();
  3514. ASSERT_NE(clipboard, nullptr);
  3515. const ui::ClipboardSequenceNumberToken before_sequence_number =
  3516. clipboard->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste);
  3517. CaptureNotificationWaiter waiter;
  3518. CaptureModeController::Get()->CaptureScreenshotsOfAllDisplays();
  3519. waiter.Wait();
  3520. const ui::ClipboardSequenceNumberToken after_sequence_number =
  3521. clipboard->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste);
  3522. EXPECT_NE(before_sequence_number, after_sequence_number);
  3523. }
  3524. // Tests the reverse tabbing behavior of the keyboard navigation.
  3525. TEST_F(CaptureModeTest, ReverseTabbingTest) {
  3526. using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
  3527. auto* event_generator = GetEventGenerator();
  3528. for (CaptureModeSource source :
  3529. {CaptureModeSource::kFullscreen, CaptureModeSource::kRegion,
  3530. CaptureModeSource::kWindow}) {
  3531. auto* controller = StartCaptureSession(source, CaptureModeType::kImage);
  3532. CaptureModeSessionTestApi test_api(controller->capture_mode_session());
  3533. // Nothing is focused initially.
  3534. EXPECT_EQ(FocusGroup::kNone, test_api.GetCurrentFocusGroup());
  3535. EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
  3536. // Reverse tabbing once and the focus should be on the close button.
  3537. SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN);
  3538. EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
  3539. EXPECT_TRUE(GetCloseButton()->has_focus());
  3540. controller->Stop();
  3541. }
  3542. }
  3543. // A regression test for a UAF issue reported at https://crbug.com/1350743, in
  3544. // which if a the native widget of the settings menu gets deleted without
  3545. // calling `Close()` or `CloseNow()` on the widget, we get a UAF. This can
  3546. // happen when all the windows in the window tree hierarchy gets deleted e.g.
  3547. // when shutting down.
  3548. TEST_F(CaptureModeTest, SettingsMenuWidgetDestruction) {
  3549. CaptureModeTestApi().StartForFullscreen(true);
  3550. ClickOnView(GetSettingsButton(), GetEventGenerator());
  3551. auto* widget = GetCaptureModeSettingsWidget();
  3552. ASSERT_TRUE(widget);
  3553. delete widget->GetNativeWindow();
  3554. }
  3555. // A test class that uses a mock time task environment.
  3556. class CaptureModeMockTimeTest : public CaptureModeTest {
  3557. public:
  3558. CaptureModeMockTimeTest()
  3559. : CaptureModeTest(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
  3560. CaptureModeMockTimeTest(const CaptureModeMockTimeTest&) = delete;
  3561. CaptureModeMockTimeTest& operator=(const CaptureModeMockTimeTest&) = delete;
  3562. ~CaptureModeMockTimeTest() override = default;
  3563. };
  3564. // Tests that the consecutive screenshots histogram is recorded properly.
  3565. TEST_F(CaptureModeMockTimeTest, ConsecutiveScreenshotsHistograms) {
  3566. constexpr char kConsecutiveScreenshotsHistogram[] =
  3567. "Ash.CaptureModeController.ConsecutiveScreenshots";
  3568. base::HistogramTester histogram_tester;
  3569. auto take_n_screenshots = [this](int n) {
  3570. for (int i = 0; i < n; ++i) {
  3571. auto* controller = StartImageRegionCapture();
  3572. controller->PerformCapture();
  3573. }
  3574. };
  3575. // Take three consecutive screenshots. Should only record after 5 seconds.
  3576. StartImageRegionCapture();
  3577. const gfx::Rect capture_region(200, 200, 400, 400);
  3578. SelectRegion(capture_region);
  3579. take_n_screenshots(3);
  3580. histogram_tester.ExpectBucketCount(kConsecutiveScreenshotsHistogram, 3, 0);
  3581. task_environment()->FastForwardBy(base::Seconds(5));
  3582. histogram_tester.ExpectBucketCount(kConsecutiveScreenshotsHistogram, 3, 1);
  3583. // Take only one screenshot. This should not be recorded.
  3584. take_n_screenshots(1);
  3585. histogram_tester.ExpectBucketCount(kConsecutiveScreenshotsHistogram, 1, 0);
  3586. task_environment()->FastForwardBy(base::Seconds(5));
  3587. histogram_tester.ExpectBucketCount(kConsecutiveScreenshotsHistogram, 1, 0);
  3588. // Take a screenshot, change source and take another screenshot. This should
  3589. // count as 2 consecutive screenshots.
  3590. take_n_screenshots(1);
  3591. auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  3592. CaptureModeType::kImage);
  3593. controller->PerformCapture();
  3594. histogram_tester.ExpectBucketCount(kConsecutiveScreenshotsHistogram, 2, 0);
  3595. task_environment()->FastForwardBy(base::Seconds(5));
  3596. histogram_tester.ExpectBucketCount(kConsecutiveScreenshotsHistogram, 2, 1);
  3597. }
  3598. // Tests that the user capture region will be cleared up after a period of time.
  3599. TEST_F(CaptureModeMockTimeTest, ClearUserCaptureRegionBetweenSessions) {
  3600. UpdateDisplay("900x800");
  3601. auto* controller = StartImageRegionCapture();
  3602. EXPECT_EQ(gfx::Rect(), controller->user_capture_region());
  3603. const gfx::Rect capture_region(100, 100, 600, 700);
  3604. SelectRegion(capture_region);
  3605. EXPECT_EQ(capture_region, controller->user_capture_region());
  3606. controller->PerformCapture();
  3607. EXPECT_EQ(capture_region, controller->user_capture_region());
  3608. // Start region image capture again shortly after the previous capture
  3609. // session, we should still be able to reuse the previous capture region.
  3610. task_environment()->FastForwardBy(base::Minutes(1));
  3611. StartImageRegionCapture();
  3612. EXPECT_EQ(capture_region, controller->user_capture_region());
  3613. auto* event_generator = GetEventGenerator();
  3614. // Even if the capture is cancelled, we still remember the capture region.
  3615. SendKey(ui::VKEY_ESCAPE, event_generator);
  3616. EXPECT_EQ(capture_region, controller->user_capture_region());
  3617. // Wait for 8 second and then start region image capture again. We should have
  3618. // forgot the previous capture region.
  3619. task_environment()->FastForwardBy(base::Minutes(8));
  3620. StartImageRegionCapture();
  3621. EXPECT_EQ(gfx::Rect(), controller->user_capture_region());
  3622. }
  3623. // Tests that in Region mode, the capture bar hides and shows itself correctly.
  3624. TEST_F(CaptureModeTest, CaptureBarOpacity) {
  3625. UpdateDisplay("800x700");
  3626. auto* event_generator = GetEventGenerator();
  3627. auto* controller = StartImageRegionCapture();
  3628. EXPECT_TRUE(controller->IsActive());
  3629. ui::Layer* capture_bar_layer = GetCaptureModeBarWidget()->GetLayer();
  3630. // Check to see it starts off opaque.
  3631. EXPECT_EQ(1.f, capture_bar_layer->GetTargetOpacity());
  3632. // Make sure that the bar is transparent when selecting a region.
  3633. const gfx::Rect target_region(gfx::BoundingRect(
  3634. gfx::Point(0, 0),
  3635. GetCaptureModeBarView()->GetBoundsInScreen().top_right() +
  3636. gfx::Vector2d(0, -50)));
  3637. event_generator->MoveMouseTo(target_region.origin());
  3638. event_generator->PressLeftButton();
  3639. EXPECT_EQ(0.f, capture_bar_layer->GetTargetOpacity());
  3640. event_generator->MoveMouseTo(target_region.bottom_right());
  3641. EXPECT_EQ(0.f, capture_bar_layer->GetTargetOpacity());
  3642. event_generator->ReleaseLeftButton();
  3643. // When there is no overlap of the selected region and the bar, the bar should
  3644. // be opaque.
  3645. EXPECT_EQ(1.f, capture_bar_layer->GetTargetOpacity());
  3646. // Bar becomes transparent when the region is being moved.
  3647. event_generator->MoveMouseTo(target_region.origin() + gfx::Vector2d(50, 50));
  3648. event_generator->PressLeftButton();
  3649. EXPECT_EQ(0.f, capture_bar_layer->GetTargetOpacity());
  3650. event_generator->MoveMouseTo(target_region.bottom_center());
  3651. EXPECT_EQ(0.f, capture_bar_layer->GetTargetOpacity());
  3652. event_generator->ReleaseLeftButton();
  3653. // The region overlaps the capture bar, so we set the opacity of the bar to
  3654. // the overlapped opacity.
  3655. EXPECT_EQ(capture_mode::kCaptureUiOverlapOpacity,
  3656. capture_bar_layer->GetTargetOpacity());
  3657. // When there is overlap, the toolbar turns opaque on mouseover.
  3658. event_generator->MoveMouseTo(
  3659. GetCaptureModeBarView()->GetBoundsInScreen().CenterPoint());
  3660. EXPECT_EQ(1.f, capture_bar_layer->GetTargetOpacity());
  3661. // Capture bar drops back to the overlapped opacity when the mouse is no
  3662. // longer hovering.
  3663. event_generator->MoveMouseTo(
  3664. GetCaptureModeBarView()->GetBoundsInScreen().top_center() +
  3665. gfx::Vector2d(0, -50));
  3666. EXPECT_EQ(capture_mode::kCaptureUiOverlapOpacity,
  3667. capture_bar_layer->GetTargetOpacity());
  3668. // Check that the opacity is reset when we select another region.
  3669. SelectRegion(target_region);
  3670. EXPECT_EQ(1.f, capture_bar_layer->GetTargetOpacity());
  3671. }
  3672. TEST_F(CaptureModeTest, CaptureBarOpacityOnHoveringOnCaptureLabel) {
  3673. UpdateDisplay("800x700");
  3674. auto* event_generator = GetEventGenerator();
  3675. auto* controller = StartImageRegionCapture();
  3676. EXPECT_TRUE(controller->IsActive());
  3677. ui::Layer* capture_bar_layer = GetCaptureModeBarWidget()->GetLayer();
  3678. // Set the capture region to make it overlap with the capture bar. And then
  3679. // move the mouse to the outside of the capture bar, verify it has the
  3680. // overlapped opacity.
  3681. const gfx::Rect capture_region(200, 500, 130, 130);
  3682. SelectRegion(capture_region);
  3683. event_generator->MoveMouseTo({10, 10});
  3684. EXPECT_EQ(capture_mode::kCaptureUiOverlapOpacity,
  3685. capture_bar_layer->GetTargetOpacity());
  3686. // Move mouse on top of the capture label, verify the bar becomes fully
  3687. // opaque.
  3688. event_generator->MoveMouseTo(
  3689. GetCaptureModeLabelWidget()->GetWindowBoundsInScreen().CenterPoint());
  3690. EXPECT_EQ(1.f, capture_bar_layer->GetTargetOpacity());
  3691. }
  3692. // Tests that the quick action histogram is recorded properly.
  3693. TEST_F(CaptureModeTest, QuickActionHistograms) {
  3694. constexpr char kQuickActionHistogramName[] =
  3695. "Ash.CaptureModeController.QuickAction";
  3696. base::HistogramTester histogram_tester;
  3697. auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  3698. CaptureModeType::kImage);
  3699. EXPECT_TRUE(controller->IsActive());
  3700. {
  3701. CaptureNotificationWaiter waiter;
  3702. controller->PerformCapture();
  3703. waiter.Wait();
  3704. }
  3705. // Verify clicking delete on screenshot notification.
  3706. base::RunLoop loop;
  3707. SetUpFileDeletionVerifier(&loop);
  3708. const int delete_button = 1;
  3709. ClickNotification(delete_button);
  3710. loop.Run();
  3711. EXPECT_FALSE(GetPreviewNotification());
  3712. histogram_tester.ExpectBucketCount(kQuickActionHistogramName,
  3713. CaptureQuickAction::kDelete, 1);
  3714. controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  3715. CaptureModeType::kImage);
  3716. {
  3717. CaptureNotificationWaiter waiter;
  3718. controller->PerformCapture();
  3719. waiter.Wait();
  3720. }
  3721. // Click on the notification body. This should take us to the files app.
  3722. ClickNotification(absl::nullopt);
  3723. EXPECT_FALSE(GetPreviewNotification());
  3724. histogram_tester.ExpectBucketCount(kQuickActionHistogramName,
  3725. CaptureQuickAction::kFiles, 1);
  3726. controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  3727. CaptureModeType::kImage);
  3728. {
  3729. CaptureNotificationWaiter waiter;
  3730. controller->PerformCapture();
  3731. waiter.Wait();
  3732. }
  3733. const int edit_button = 0;
  3734. // Verify clicking edit on screenshot notification.
  3735. ClickNotification(edit_button);
  3736. EXPECT_FALSE(GetPreviewNotification());
  3737. histogram_tester.ExpectBucketCount(kQuickActionHistogramName,
  3738. CaptureQuickAction::kBacklight, 1);
  3739. }
  3740. TEST_F(CaptureModeTest, CannotDoMultipleRecordings) {
  3741. StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
  3742. auto* controller = CaptureModeController::Get();
  3743. StartVideoRecordingImmediately();
  3744. EXPECT_TRUE(controller->is_recording_in_progress());
  3745. EXPECT_EQ(CaptureModeType::kVideo, controller->type());
  3746. // Start a new session with the current type which set to kVideo, the type
  3747. // should be switched automatically to kImage, and video toggle button should
  3748. // be disabled.
  3749. controller->Start(CaptureModeEntryType::kQuickSettings);
  3750. EXPECT_TRUE(controller->IsActive());
  3751. EXPECT_EQ(CaptureModeType::kImage, controller->type());
  3752. EXPECT_TRUE(GetImageToggleButton()->GetToggled());
  3753. EXPECT_FALSE(GetVideoToggleButton()->GetToggled());
  3754. EXPECT_FALSE(GetVideoToggleButton()->GetEnabled());
  3755. // Clicking on the video button should do nothing.
  3756. ClickOnView(GetVideoToggleButton(), GetEventGenerator());
  3757. EXPECT_TRUE(GetImageToggleButton()->GetToggled());
  3758. EXPECT_FALSE(GetVideoToggleButton()->GetToggled());
  3759. EXPECT_EQ(CaptureModeType::kImage, controller->type());
  3760. // Things should go back to normal when there's no recording going on.
  3761. controller->Stop();
  3762. controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
  3763. StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
  3764. EXPECT_EQ(CaptureModeType::kVideo, controller->type());
  3765. EXPECT_FALSE(GetImageToggleButton()->GetToggled());
  3766. EXPECT_TRUE(GetVideoToggleButton()->GetToggled());
  3767. EXPECT_TRUE(GetVideoToggleButton()->GetEnabled());
  3768. }
  3769. // Tests the basic settings menu functionality.
  3770. TEST_F(CaptureModeTest, SettingsMenuVisibilityBasic) {
  3771. auto* event_generator = GetEventGenerator();
  3772. auto* controller = StartImageRegionCapture();
  3773. EXPECT_TRUE(controller->IsActive());
  3774. // Session starts with settings menu not initialized.
  3775. EXPECT_FALSE(GetCaptureModeSettingsWidget());
  3776. // Test clicking the settings button toggles the button as well as
  3777. // opens/closes the settings menu.
  3778. ClickOnView(GetSettingsButton(), event_generator);
  3779. EXPECT_TRUE(GetCaptureModeSettingsWidget());
  3780. EXPECT_TRUE(GetSettingsButton()->GetToggled());
  3781. ClickOnView(GetSettingsButton(), event_generator);
  3782. EXPECT_FALSE(GetCaptureModeSettingsWidget());
  3783. EXPECT_FALSE(GetSettingsButton()->GetToggled());
  3784. }
  3785. // Tests how interacting with the rest of the screen (i.e. clicking outside of
  3786. // the bar/menu, on other buttons) affects whether the settings menu should
  3787. // close or not.
  3788. TEST_F(CaptureModeTest, SettingsMenuVisibilityClicking) {
  3789. UpdateDisplay("800x700");
  3790. auto* event_generator = GetEventGenerator();
  3791. auto* controller = StartImageRegionCapture();
  3792. EXPECT_TRUE(controller->IsActive());
  3793. // Test clicking on the option of settings menu doesn't close the
  3794. // settings menu.
  3795. ClickOnView(GetSettingsButton(), event_generator);
  3796. ClickOnView(GetCaptureModeSettingsView(), event_generator);
  3797. EXPECT_TRUE(GetCaptureModeSettingsWidget());
  3798. EXPECT_TRUE(GetSettingsButton()->GetToggled());
  3799. CaptureModeSettingsTestApi test_api;
  3800. ClickOnView(test_api.GetAudioOffOption(), event_generator);
  3801. EXPECT_TRUE(GetCaptureModeSettingsWidget());
  3802. EXPECT_TRUE(GetSettingsButton()->GetToggled());
  3803. // Test clicking on the capture bar closes the settings menu.
  3804. event_generator->MoveMouseTo(
  3805. GetCaptureModeBarView()->GetBoundsInScreen().top_center() +
  3806. gfx::Vector2d(0, 2));
  3807. event_generator->ClickLeftButton();
  3808. EXPECT_FALSE(GetCaptureModeSettingsWidget());
  3809. EXPECT_FALSE(GetSettingsButton()->GetToggled());
  3810. // Test clicking on a different source closes the settings menu.
  3811. ClickOnView(GetSettingsButton(), event_generator);
  3812. ClickOnView(GetFullscreenToggleButton(), event_generator);
  3813. EXPECT_FALSE(GetCaptureModeSettingsWidget());
  3814. // Test clicking on a different type closes the settings menu.
  3815. ClickOnView(GetSettingsButton(), event_generator);
  3816. ClickOnView(GetVideoToggleButton(), event_generator);
  3817. EXPECT_FALSE(GetCaptureModeSettingsWidget());
  3818. // Exit the capture session with the settings menu open, and test to make sure
  3819. // the new session starts with the settings menu hidden.
  3820. ClickOnView(GetSettingsButton(), event_generator);
  3821. SendKey(ui::VKEY_ESCAPE, event_generator);
  3822. StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kImage);
  3823. EXPECT_FALSE(GetCaptureModeSettingsWidget());
  3824. // Take a screenshot with the settings menu open, and test to make sure the
  3825. // new session starts with the settings menu hidden.
  3826. ClickOnView(GetSettingsButton(), event_generator);
  3827. // Take screenshot.
  3828. SendKey(ui::VKEY_RETURN, event_generator);
  3829. StartImageRegionCapture();
  3830. EXPECT_FALSE(GetCaptureModeSettingsWidget());
  3831. }
  3832. // Tests capture bar and settings menu visibility / opacity when capture region
  3833. // is being or after drawn.
  3834. TEST_F(CaptureModeTest, CaptureBarAndSettingsMenuVisibilityDrawingRegion) {
  3835. UpdateDisplay("800x700");
  3836. auto* event_generator = GetEventGenerator();
  3837. auto* controller = StartImageRegionCapture();
  3838. auto* capture_bar_widget = GetCaptureModeBarWidget();
  3839. ui::Layer* capture_bar_layer = capture_bar_widget->GetLayer();
  3840. EXPECT_TRUE(controller->IsActive());
  3841. auto* session = CaptureModeController::Get()->capture_mode_session();
  3842. // Test the settings menu and capture bar are hidden when the user clicks to
  3843. // start selecting a region.
  3844. ClickOnView(GetSettingsButton(), event_generator);
  3845. EXPECT_TRUE(GetCaptureModeSettingsWidget());
  3846. const gfx::Rect target_region(gfx::BoundingRect(
  3847. gfx::Point(0, 0),
  3848. capture_bar_widget->GetWindowBoundsInScreen().top_right() +
  3849. gfx::Vector2d(0, -50)));
  3850. // Moving the cursor outside the bounds of the settings menu should update the
  3851. // cursor to `kPointer`, since the only possible operation here when clicking
  3852. // is to dismiss the settings menu rather than take a screenshot or update the
  3853. // region.
  3854. event_generator->MoveMouseTo(target_region.origin());
  3855. auto* cursor_manager = Shell::Get()->cursor_manager();
  3856. using ui::mojom::CursorType;
  3857. EXPECT_EQ(CursorType::kPointer, cursor_manager->GetCursor().type());
  3858. // Pressing outside the bounds of the settings should dismiss it immediately,
  3859. // update the cursor to `kCell` (to signal that it's now possible to select a
  3860. // region), but region selection doesn't start until the next click event.
  3861. event_generator->PressLeftButton();
  3862. EXPECT_FALSE(GetCaptureModeSettingsWidget());
  3863. EXPECT_EQ(CursorType::kCell, cursor_manager->GetCursor().type());
  3864. EXPECT_FALSE(session->is_selecting_region());
  3865. event_generator->ReleaseLeftButton();
  3866. EXPECT_FALSE(session->is_selecting_region());
  3867. event_generator->PressLeftButton();
  3868. EXPECT_TRUE(session->is_selecting_region());
  3869. event_generator->MoveMouseTo(target_region.bottom_right());
  3870. EXPECT_EQ(0.f, capture_bar_layer->GetTargetOpacity());
  3871. event_generator->ReleaseLeftButton();
  3872. EXPECT_FALSE(GetCaptureModeSettingsWidget());
  3873. // Test that the settings menu will dismiss immediately when clicking
  3874. // somewhere in the middle of the capture region.
  3875. ClickOnView(GetSettingsButton(), event_generator);
  3876. event_generator->MoveMouseTo(target_region.origin() + gfx::Vector2d(50, 50));
  3877. event_generator->PressLeftButton();
  3878. EXPECT_FALSE(GetCaptureModeSettingsWidget());
  3879. event_generator->ReleaseLeftButton();
  3880. event_generator->PressLeftButton();
  3881. EXPECT_EQ(CursorType::kMove, cursor_manager->GetCursor().type());
  3882. EXPECT_FALSE(session->is_selecting_region());
  3883. EXPECT_TRUE(session->is_drag_in_progress());
  3884. // This creates a region that overlaps with the capture bar. The capture bar
  3885. // should be fully transparent while dragging the region is in progress.
  3886. event_generator->MoveMouseTo(target_region.bottom_center());
  3887. EXPECT_EQ(0.f, capture_bar_layer->GetTargetOpacity());
  3888. event_generator->ReleaseLeftButton();
  3889. // With an overlapping region (as dragged to above), the capture bar opacity
  3890. // is changed based on hover. If the settings menu is open/visible, the
  3891. // capture bar will always be visible no matter if the mouse is hovered on it
  3892. // or not.
  3893. event_generator->MoveMouseTo(target_region.origin());
  3894. EXPECT_EQ(capture_mode::kCaptureUiOverlapOpacity,
  3895. capture_bar_layer->GetTargetOpacity());
  3896. // Move mouse on top of the capture bar, verify that capture bar becomes
  3897. // visible.
  3898. event_generator->MoveMouseTo(
  3899. capture_bar_widget->GetWindowBoundsInScreen().CenterPoint());
  3900. EXPECT_EQ(1.f, capture_bar_layer->GetTargetOpacity());
  3901. ClickOnView(GetSettingsButton(), event_generator);
  3902. EXPECT_TRUE(GetCaptureModeSettingsWidget());
  3903. EXPECT_EQ(1.f, capture_bar_layer->GetTargetOpacity());
  3904. // Move mouse onto the settings menu, confirm the capture bar is still
  3905. // visible.
  3906. event_generator->MoveMouseTo(
  3907. GetCaptureModeSettingsView()->GetBoundsInScreen().CenterPoint());
  3908. EXPECT_EQ(1.f, capture_bar_layer->GetTargetOpacity());
  3909. // Move mouse to the outside of the capture bar and settings, verify that
  3910. // settings menu are still open and both capture bar and settings have full
  3911. // opaque.
  3912. event_generator->MoveMouseTo(target_region.origin());
  3913. auto* settings_menu = GetCaptureModeSettingsView();
  3914. EXPECT_TRUE(settings_menu);
  3915. EXPECT_EQ(1.f, capture_bar_layer->GetTargetOpacity());
  3916. EXPECT_EQ(1.f, settings_menu->layer()->GetTargetOpacity());
  3917. // Close settings menu, and move mouse to the outside of the capture bar,
  3918. // verify capture bar has the overlapped opacity.
  3919. ClickOnView(GetSettingsButton(), event_generator);
  3920. event_generator->MoveMouseTo(target_region.origin());
  3921. EXPECT_EQ(capture_mode::kCaptureUiOverlapOpacity,
  3922. capture_bar_layer->GetTargetOpacity());
  3923. }
  3924. TEST_F(CaptureModeTest, CaptureFolderSetting) {
  3925. auto* controller = CaptureModeController::Get();
  3926. auto* test_delegate = controller->delegate_for_testing();
  3927. const auto default_downloads_folder =
  3928. test_delegate->GetUserDefaultDownloadsFolder();
  3929. auto capture_folder = controller->GetCurrentCaptureFolder();
  3930. EXPECT_EQ(capture_folder.path, default_downloads_folder);
  3931. EXPECT_TRUE(capture_folder.is_default_downloads_folder);
  3932. const base::FilePath custom_folder(FILE_PATH_LITERAL("/home/tests"));
  3933. controller->SetCustomCaptureFolder(custom_folder);
  3934. capture_folder = controller->GetCurrentCaptureFolder();
  3935. EXPECT_EQ(capture_folder.path, custom_folder);
  3936. EXPECT_FALSE(capture_folder.is_default_downloads_folder);
  3937. }
  3938. TEST_F(CaptureModeTest, CaptureFolderSetToDefaultDownloads) {
  3939. auto* controller = CaptureModeController::Get();
  3940. auto* test_delegate = controller->delegate_for_testing();
  3941. const base::FilePath custom_folder(FILE_PATH_LITERAL("/home/tests"));
  3942. controller->SetCustomCaptureFolder(custom_folder);
  3943. auto capture_folder = controller->GetCurrentCaptureFolder();
  3944. EXPECT_FALSE(capture_folder.is_default_downloads_folder);
  3945. // If the user selects the default downloads folder manually, we should be
  3946. // able to detect that.
  3947. const auto default_downloads_folder =
  3948. test_delegate->GetUserDefaultDownloadsFolder();
  3949. controller->SetCustomCaptureFolder(default_downloads_folder);
  3950. capture_folder = controller->GetCurrentCaptureFolder();
  3951. EXPECT_EQ(capture_folder.path, default_downloads_folder);
  3952. EXPECT_TRUE(capture_folder.is_default_downloads_folder);
  3953. }
  3954. TEST_F(CaptureModeTest, UsesDefaultFolderWithCustomFolderSet) {
  3955. auto* controller = CaptureModeController::Get();
  3956. auto* test_delegate = controller->delegate_for_testing();
  3957. const base::FilePath custom_folder(FILE_PATH_LITERAL("/home/tests"));
  3958. controller->SetCustomCaptureFolder(custom_folder);
  3959. auto capture_folder = controller->GetCurrentCaptureFolder();
  3960. EXPECT_FALSE(capture_folder.is_default_downloads_folder);
  3961. // If the user selects to force use the default downloads folder even while
  3962. // a custom folder is set, we should respect that, but we shouldn't clear the
  3963. // custom folder.
  3964. controller->SetUsesDefaultCaptureFolder(true);
  3965. const auto default_downloads_folder =
  3966. test_delegate->GetUserDefaultDownloadsFolder();
  3967. capture_folder = controller->GetCurrentCaptureFolder();
  3968. EXPECT_EQ(capture_folder.path, default_downloads_folder);
  3969. EXPECT_TRUE(capture_folder.is_default_downloads_folder);
  3970. // Setting another custom folder value, would reset the
  3971. // "UsesDefaultCaptureFolder" value, and the new custom folder will be used.
  3972. const base::FilePath custom_folder2(FILE_PATH_LITERAL("/home/tests2"));
  3973. controller->SetCustomCaptureFolder(custom_folder2);
  3974. capture_folder = controller->GetCurrentCaptureFolder();
  3975. EXPECT_EQ(capture_folder.path, custom_folder2);
  3976. EXPECT_FALSE(capture_folder.is_default_downloads_folder);
  3977. }
  3978. TEST_F(CaptureModeTest, CaptureFolderSetToEmptyPath) {
  3979. auto* controller = CaptureModeController::Get();
  3980. auto* test_delegate = controller->delegate_for_testing();
  3981. const base::FilePath custom_folder(FILE_PATH_LITERAL("/home/tests"));
  3982. controller->SetCustomCaptureFolder(custom_folder);
  3983. auto capture_folder = controller->GetCurrentCaptureFolder();
  3984. EXPECT_FALSE(capture_folder.is_default_downloads_folder);
  3985. // If we set the custom path to an empty folder to clear, we should revert
  3986. // back to the default downloads folder.
  3987. controller->SetCustomCaptureFolder(base::FilePath());
  3988. const auto default_downloads_folder =
  3989. test_delegate->GetUserDefaultDownloadsFolder();
  3990. capture_folder = controller->GetCurrentCaptureFolder();
  3991. EXPECT_EQ(capture_folder.path, default_downloads_folder);
  3992. EXPECT_TRUE(capture_folder.is_default_downloads_folder);
  3993. }
  3994. TEST_F(CaptureModeTest, SimulateUserCancelingDlpWarningDialog) {
  3995. auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  3996. CaptureModeType::kVideo);
  3997. StartVideoRecordingImmediately();
  3998. EXPECT_TRUE(controller->is_recording_in_progress());
  3999. // Simulate the user canceling the DLP warning dialog at the end of the
  4000. // recording which is shown to the user to alert about restricted content
  4001. // showing up on the screen during the recording. In this case, the user
  4002. // requests the deletion of the file.
  4003. auto* test_delegate =
  4004. static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
  4005. test_delegate->set_should_save_after_dlp_check(false);
  4006. base::RunLoop loop;
  4007. SetUpFileDeletionVerifier(&loop);
  4008. controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
  4009. loop.Run();
  4010. // No notification should show in this case, nor any thing on Tote.
  4011. EXPECT_FALSE(GetPreviewNotification());
  4012. ash::HoldingSpaceTestApi holding_space_api;
  4013. EXPECT_TRUE(holding_space_api.GetScreenCaptureViews().empty());
  4014. }
  4015. namespace {
  4016. // -----------------------------------------------------------------------------
  4017. // TestVideoCaptureOverlay:
  4018. // Defines a fake video capture overlay to be used in testing the behavior of
  4019. // the cursor overlay. The VideoRecordingWatcher will control this overlay via
  4020. // mojo.
  4021. using Overlay = viz::mojom::FrameSinkVideoCaptureOverlay;
  4022. class TestVideoCaptureOverlay : public Overlay {
  4023. public:
  4024. explicit TestVideoCaptureOverlay(mojo::PendingReceiver<Overlay> receiver)
  4025. : receiver_(this, std::move(receiver)) {}
  4026. ~TestVideoCaptureOverlay() override = default;
  4027. const gfx::RectF& last_bounds() const { return last_bounds_; }
  4028. bool IsHidden() const { return last_bounds_ == gfx::RectF(); }
  4029. // viz::mojom::FrameSinkVideoCaptureOverlay:
  4030. void SetImageAndBounds(const SkBitmap& image,
  4031. const gfx::RectF& bounds) override {
  4032. last_bounds_ = bounds;
  4033. }
  4034. void SetBounds(const gfx::RectF& bounds) override { last_bounds_ = bounds; }
  4035. private:
  4036. mojo::Receiver<viz::mojom::FrameSinkVideoCaptureOverlay> receiver_;
  4037. gfx::RectF last_bounds_;
  4038. };
  4039. // -----------------------------------------------------------------------------
  4040. // CaptureModeCursorOverlayTest:
  4041. // Defines a test fixure to test the behavior of the cursor overlay.
  4042. class CaptureModeCursorOverlayTest : public CaptureModeTest {
  4043. public:
  4044. CaptureModeCursorOverlayTest() = default;
  4045. ~CaptureModeCursorOverlayTest() override = default;
  4046. aura::Window* window() const { return window_.get(); }
  4047. TestVideoCaptureOverlay* fake_overlay() const { return fake_overlay_.get(); }
  4048. // CaptureModeTest:
  4049. void SetUp() override {
  4050. CaptureModeTest::SetUp();
  4051. window_ = CreateTestWindow(gfx::Rect(200, 200));
  4052. }
  4053. void TearDown() override {
  4054. window_.reset();
  4055. CaptureModeTest::TearDown();
  4056. }
  4057. CaptureModeController* StartRecordingAndSetupFakeOverlay(
  4058. CaptureModeSource source) {
  4059. auto* controller = StartCaptureSession(source, CaptureModeType::kVideo);
  4060. auto* event_generator = GetEventGenerator();
  4061. if (source == CaptureModeSource::kWindow)
  4062. event_generator->MoveMouseToCenterOf(window_.get());
  4063. StartVideoRecordingImmediately();
  4064. EXPECT_TRUE(controller->is_recording_in_progress());
  4065. auto* recording_watcher = controller->video_recording_watcher_for_testing();
  4066. mojo::PendingRemote<Overlay> overlay_pending_remote;
  4067. fake_overlay_ = std::make_unique<TestVideoCaptureOverlay>(
  4068. overlay_pending_remote.InitWithNewPipeAndPassReceiver());
  4069. recording_watcher->BindCursorOverlayForTesting(
  4070. std::move(overlay_pending_remote));
  4071. // The overlay should be initially hidden until a mourse event is received.
  4072. FlushOverlay();
  4073. EXPECT_TRUE(fake_overlay()->IsHidden());
  4074. // Generating some mouse events may or may not show the overlay, depending
  4075. // on the conditions of the test. Each test will verify its expectation
  4076. // after this returns.
  4077. event_generator->MoveMouseBy(10, 10);
  4078. FlushOverlay();
  4079. return controller;
  4080. }
  4081. void FlushOverlay() {
  4082. auto* controller = CaptureModeController::Get();
  4083. DCHECK(controller->is_recording_in_progress());
  4084. controller->video_recording_watcher_for_testing()
  4085. ->FlushCursorOverlayForTesting();
  4086. }
  4087. // The docked magnifier is one of the features that force the software-
  4088. // composited cursor to be used when enabled. We use it to test the behavior
  4089. // of the cursor overlay in that case.
  4090. void SetDockedMagnifierEnabled(bool enabled) {
  4091. Shell::Get()->docked_magnifier_controller()->SetEnabled(enabled);
  4092. }
  4093. // Checks that capturing a screenshot hides the cursor. After the capture is
  4094. // complete, checks that the cursor returns to the previous state, i.e.
  4095. // hidden for tablet mode but visible for clamshell mode.
  4096. void CaptureScreenshotAndCheckCursorVisibility(
  4097. CaptureModeController* controller) {
  4098. EXPECT_EQ(controller->type(), CaptureModeType::kImage);
  4099. auto* shell = Shell::Get();
  4100. auto* cursor_manager = shell->cursor_manager();
  4101. bool in_tablet_mode = shell->tablet_mode_controller()->InTabletMode();
  4102. // The capture mode session locks the cursor for the whole active session
  4103. // except in the tablet mode unless the cursor is visible.
  4104. EXPECT_EQ(!in_tablet_mode, cursor_manager->IsCursorLocked());
  4105. EXPECT_EQ(!in_tablet_mode, cursor_manager->IsCursorVisible());
  4106. EXPECT_TRUE(controller->IsActive());
  4107. // Make sure the cursor is hidden while capturing the screenshot.
  4108. CaptureNotificationWaiter waiter;
  4109. controller->PerformCapture();
  4110. EXPECT_FALSE(cursor_manager->IsCursorVisible());
  4111. EXPECT_FALSE(controller->IsActive());
  4112. // The cursor visibility should be restored after the capture is done.
  4113. waiter.Wait();
  4114. EXPECT_EQ(!in_tablet_mode, cursor_manager->IsCursorVisible());
  4115. EXPECT_FALSE(cursor_manager->IsCursorLocked());
  4116. }
  4117. private:
  4118. std::unique_ptr<aura::Window> window_;
  4119. std::unique_ptr<TestVideoCaptureOverlay> fake_overlay_;
  4120. };
  4121. } // namespace
  4122. TEST_F(CaptureModeCursorOverlayTest, TabletModeHidesCursorOverlay) {
  4123. StartRecordingAndSetupFakeOverlay(CaptureModeSource::kFullscreen);
  4124. EXPECT_FALSE(fake_overlay()->IsHidden());
  4125. // Entering tablet mode should hide the cursor overlay.
  4126. SwitchToTabletMode();
  4127. FlushOverlay();
  4128. EXPECT_TRUE(fake_overlay()->IsHidden());
  4129. // Exiting tablet mode should reshow the overlay.
  4130. LeaveTabletMode();
  4131. FlushOverlay();
  4132. EXPECT_FALSE(fake_overlay()->IsHidden());
  4133. }
  4134. // Tests that the cursor is hidden while taking a screenshot in tablet mode and
  4135. // remains hidden afterward.
  4136. TEST_F(CaptureModeCursorOverlayTest, TabletModeHidesCursor) {
  4137. // Enter tablet mode.
  4138. SwitchToTabletMode();
  4139. auto* cursor_manager = Shell::Get()->cursor_manager();
  4140. CaptureModeController* controller = StartCaptureSession(
  4141. CaptureModeSource::kFullscreen, CaptureModeType::kImage);
  4142. // Test the hardware cursor.
  4143. CaptureScreenshotAndCheckCursorVisibility(controller);
  4144. // Test the software cursor enabled by docked magnifier.
  4145. SetDockedMagnifierEnabled(true);
  4146. EXPECT_TRUE(IsCursorCompositingEnabled());
  4147. controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  4148. CaptureModeType::kImage);
  4149. CaptureScreenshotAndCheckCursorVisibility(controller);
  4150. // Exiting tablet mode.
  4151. LeaveTabletMode();
  4152. EXPECT_TRUE(cursor_manager->IsCursorVisible());
  4153. }
  4154. // Tests that a cursor is hidden while taking a fullscreen screenshot
  4155. // (crbug.com/1186652).
  4156. TEST_F(CaptureModeCursorOverlayTest, CursorInFullscreenScreenshot) {
  4157. auto* cursor_manager = Shell::Get()->cursor_manager();
  4158. EXPECT_FALSE(cursor_manager->IsCursorLocked());
  4159. CaptureModeController* controller = StartCaptureSession(
  4160. CaptureModeSource::kFullscreen, CaptureModeType::kImage);
  4161. auto* event_generator = GetEventGenerator();
  4162. event_generator->MoveMouseTo(gfx::Point(175, 175));
  4163. // Test the hardware cursor.
  4164. CaptureScreenshotAndCheckCursorVisibility(controller);
  4165. // Test the software cursor enabled by docked magnifier.
  4166. SetDockedMagnifierEnabled(true);
  4167. EXPECT_TRUE(IsCursorCompositingEnabled());
  4168. controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  4169. CaptureModeType::kImage);
  4170. CaptureScreenshotAndCheckCursorVisibility(controller);
  4171. }
  4172. // Tests that a cursor is hidden while taking a region screenshot
  4173. // (crbug.com/1186652).
  4174. TEST_F(CaptureModeCursorOverlayTest, CursorInPartialRegionScreenshot) {
  4175. // Use a set display size as we will be choosing points in this test.
  4176. UpdateDisplay("800x700");
  4177. auto* cursor_manager = Shell::Get()->cursor_manager();
  4178. EXPECT_FALSE(cursor_manager->IsCursorLocked());
  4179. auto* event_generator = GetEventGenerator();
  4180. auto* controller = StartImageRegionCapture();
  4181. // Create the initial capture region.
  4182. const gfx::Rect target_region(gfx::Rect(50, 50, 200, 200));
  4183. SelectRegion(target_region);
  4184. event_generator->MoveMouseTo(gfx::Point(175, 175));
  4185. // Test the hardware cursor.
  4186. CaptureScreenshotAndCheckCursorVisibility(controller);
  4187. // Test the software cursor enabled by docked magnifier.
  4188. SetDockedMagnifierEnabled(true);
  4189. EXPECT_TRUE(IsCursorCompositingEnabled());
  4190. controller = StartImageRegionCapture();
  4191. CaptureScreenshotAndCheckCursorVisibility(controller);
  4192. }
  4193. TEST_F(CaptureModeCursorOverlayTest, SoftwareCursorInitiallyEnabled) {
  4194. // The software cursor is enabled before recording starts.
  4195. SetDockedMagnifierEnabled(true);
  4196. EXPECT_TRUE(IsCursorCompositingEnabled());
  4197. // Hence the overlay will be hidden initially.
  4198. StartRecordingAndSetupFakeOverlay(CaptureModeSource::kFullscreen);
  4199. EXPECT_TRUE(fake_overlay()->IsHidden());
  4200. }
  4201. TEST_F(CaptureModeCursorOverlayTest, SoftwareCursorInFullscreenRecording) {
  4202. StartRecordingAndSetupFakeOverlay(CaptureModeSource::kFullscreen);
  4203. EXPECT_FALSE(fake_overlay()->IsHidden());
  4204. // When the software-composited cursor is enabled, the overlay is hidden to
  4205. // avoid having two overlapping cursors in the video.
  4206. SetDockedMagnifierEnabled(true);
  4207. EXPECT_TRUE(IsCursorCompositingEnabled());
  4208. FlushOverlay();
  4209. EXPECT_TRUE(fake_overlay()->IsHidden());
  4210. SetDockedMagnifierEnabled(false);
  4211. EXPECT_FALSE(IsCursorCompositingEnabled());
  4212. FlushOverlay();
  4213. EXPECT_FALSE(fake_overlay()->IsHidden());
  4214. }
  4215. TEST_F(CaptureModeCursorOverlayTest, SoftwareCursorInPartialRegionRecording) {
  4216. CaptureModeController::Get()->SetUserCaptureRegion(gfx::Rect(20, 20),
  4217. /*by_user=*/true);
  4218. StartRecordingAndSetupFakeOverlay(CaptureModeSource::kRegion);
  4219. EXPECT_FALSE(fake_overlay()->IsHidden());
  4220. // The behavior in this case is exactly the same as in fullscreen recording.
  4221. SetDockedMagnifierEnabled(true);
  4222. EXPECT_TRUE(IsCursorCompositingEnabled());
  4223. FlushOverlay();
  4224. EXPECT_TRUE(fake_overlay()->IsHidden());
  4225. }
  4226. TEST_F(CaptureModeCursorOverlayTest, SoftwareCursorInWindowRecording) {
  4227. StartRecordingAndSetupFakeOverlay(CaptureModeSource::kWindow);
  4228. EXPECT_FALSE(fake_overlay()->IsHidden());
  4229. // When recording a window, the software cursor has no effect of the cursor
  4230. // overlay, since the cursor widget is not in the recorded window subtree, so
  4231. // it cannot be captured by the frame sink capturer. We have to provide cursor
  4232. // capturing through the overlay.
  4233. SetDockedMagnifierEnabled(true);
  4234. EXPECT_TRUE(IsCursorCompositingEnabled());
  4235. FlushOverlay();
  4236. EXPECT_FALSE(fake_overlay()->IsHidden());
  4237. }
  4238. TEST_F(CaptureModeCursorOverlayTest, OverlayHidesWhenOutOfBounds) {
  4239. StartRecordingAndSetupFakeOverlay(CaptureModeSource::kWindow);
  4240. EXPECT_FALSE(fake_overlay()->IsHidden());
  4241. const gfx::Point bottom_right =
  4242. window()->GetBoundsInRootWindow().bottom_right();
  4243. auto* generator = GetEventGenerator();
  4244. // Generate a click event to overcome throttling.
  4245. generator->MoveMouseTo(bottom_right);
  4246. generator->ClickLeftButton();
  4247. FlushOverlay();
  4248. EXPECT_TRUE(fake_overlay()->IsHidden());
  4249. }
  4250. // Verifies that the cursor overlay bounds calculation takes into account the
  4251. // cursor image scale factor. https://crbug.com/1222494.
  4252. TEST_F(CaptureModeCursorOverlayTest, OverlayBoundsAccountForCursorScaleFactor) {
  4253. UpdateDisplay("500x400");
  4254. StartRecordingAndSetupFakeOverlay(CaptureModeSource::kFullscreen);
  4255. EXPECT_FALSE(fake_overlay()->IsHidden());
  4256. auto* cursor_manager = Shell::Get()->cursor_manager();
  4257. auto set_cursor = [cursor_manager](const gfx::Size& cursor_image_size,
  4258. float cursor_image_scale_factor) {
  4259. const auto cursor_type = ui::mojom::CursorType::kCustom;
  4260. gfx::NativeCursor cursor{cursor_type};
  4261. SkBitmap cursor_image;
  4262. cursor_image.allocN32Pixels(cursor_image_size.width(),
  4263. cursor_image_size.height());
  4264. cursor.set_image_scale_factor(cursor_image_scale_factor);
  4265. cursor.set_custom_bitmap(cursor_image);
  4266. auto* platform_cursor_factory =
  4267. ui::OzonePlatform::GetInstance()->GetCursorFactory();
  4268. cursor.SetPlatformCursor(platform_cursor_factory->CreateImageCursor(
  4269. cursor_type, cursor_image, cursor.custom_hotspot()));
  4270. cursor_manager->SetCursor(cursor);
  4271. };
  4272. struct {
  4273. gfx::Size cursor_size;
  4274. float cursor_image_scale_factor;
  4275. } kTestCases[] = {
  4276. {
  4277. gfx::Size(50, 50),
  4278. /*cursor_image_scale_factor=*/2.f,
  4279. },
  4280. {
  4281. gfx::Size(25, 25),
  4282. /*cursor_image_scale_factor=*/1.f,
  4283. },
  4284. };
  4285. // Both of the above test cases should yield the same cursor overlay relative
  4286. // bounds when the cursor is at the center of the screen.
  4287. // Origin is 0.5f (center)
  4288. // Size is 25 (cursor image dip size) / {500,400} = {0.05f, 0.0625f}
  4289. const gfx::RectF expected_overlay_bounds{0.5f, 0.5f, 0.05f, 0.0625f};
  4290. const gfx::Point screen_center =
  4291. window()->GetRootWindow()->bounds().CenterPoint();
  4292. auto* generator = GetEventGenerator();
  4293. for (const auto& test_case : kTestCases) {
  4294. set_cursor(test_case.cursor_size, test_case.cursor_image_scale_factor);
  4295. // Lock the cursor to prevent mouse events from changing it back to a
  4296. // default kPointer cursor type.
  4297. cursor_manager->LockCursor();
  4298. // Generate a click event to overcome throttling.
  4299. generator->MoveMouseTo(screen_center);
  4300. generator->ClickLeftButton();
  4301. FlushOverlay();
  4302. EXPECT_FALSE(fake_overlay()->IsHidden());
  4303. EXPECT_EQ(expected_overlay_bounds, fake_overlay()->last_bounds());
  4304. // Unlock the cursor back.
  4305. cursor_manager->UnlockCursor();
  4306. }
  4307. }
  4308. // -----------------------------------------------------------------------------
  4309. // TODO(afakhry): Add more cursor overlay tests.
  4310. // Test fixture to verify capture mode + projector integration.
  4311. namespace {
  4312. constexpr char kProjectorCreationFlowHistogramName[] =
  4313. "Ash.Projector.CreationFlow.ClamshellMode";
  4314. } // namespace
  4315. class ProjectorCaptureModeIntegrationTests
  4316. : public CaptureModeTest,
  4317. public ::testing::WithParamInterface<CaptureModeSource> {
  4318. public:
  4319. ProjectorCaptureModeIntegrationTests() = default;
  4320. ~ProjectorCaptureModeIntegrationTests() override = default;
  4321. static constexpr gfx::Rect kUserRegion{20, 50, 60, 70};
  4322. MockProjectorClient* projector_client() {
  4323. return projector_helper_.projector_client();
  4324. }
  4325. aura::Window* window() const { return window_.get(); }
  4326. // CaptureModeTest:
  4327. void SetUp() override {
  4328. CaptureModeTest::SetUp();
  4329. projector_helper_.SetUp();
  4330. window_ = CreateTestWindow(gfx::Rect(20, 30, 200, 200));
  4331. CaptureModeController::Get()->SetUserCaptureRegion(kUserRegion,
  4332. /*by_user=*/true);
  4333. }
  4334. void TearDown() override {
  4335. window_.reset();
  4336. CaptureModeTest::TearDown();
  4337. }
  4338. void StartProjectorModeSession() {
  4339. projector_helper_.StartProjectorModeSession();
  4340. }
  4341. void StartRecordingForProjectorFromSource(CaptureModeSource source) {
  4342. StartProjectorModeSession();
  4343. auto* controller = CaptureModeController::Get();
  4344. controller->SetSource(source);
  4345. switch (source) {
  4346. case CaptureModeSource::kFullscreen:
  4347. case CaptureModeSource::kRegion:
  4348. break;
  4349. case CaptureModeSource::kWindow:
  4350. auto* generator = GetEventGenerator();
  4351. generator->MoveMouseTo(window_->GetBoundsInScreen().CenterPoint());
  4352. break;
  4353. }
  4354. CaptureModeTestApi().PerformCapture();
  4355. WaitForRecordingToStart();
  4356. EXPECT_TRUE(controller->is_recording_in_progress());
  4357. }
  4358. void VerifyOverlayEnabledState(aura::Window* overlay_window,
  4359. bool overlay_enabled_state) {
  4360. if (overlay_enabled_state) {
  4361. EXPECT_TRUE(overlay_window->IsVisible());
  4362. EXPECT_EQ(overlay_window->event_targeting_policy(),
  4363. aura::EventTargetingPolicy::kTargetAndDescendants);
  4364. } else {
  4365. EXPECT_FALSE(overlay_window->IsVisible());
  4366. EXPECT_EQ(overlay_window->event_targeting_policy(),
  4367. aura::EventTargetingPolicy::kNone);
  4368. }
  4369. }
  4370. void VerifyOverlayStacking(aura::Window* overlay_window,
  4371. aura::Window* window_being_recorded,
  4372. CaptureModeSource source) {
  4373. auto* parent = overlay_window->parent();
  4374. if (source == CaptureModeSource::kWindow) {
  4375. // The overlay window should always be the top-most child of the window
  4376. // being recorded when in window mode.
  4377. ASSERT_EQ(parent, window_being_recorded);
  4378. EXPECT_EQ(window_being_recorded->children().back(), overlay_window);
  4379. } else {
  4380. auto* menu_container =
  4381. window_being_recorded->GetRootWindow()->GetChildById(
  4382. kShellWindowId_MenuContainer);
  4383. ASSERT_EQ(parent, menu_container);
  4384. EXPECT_EQ(menu_container->children().front(), overlay_window);
  4385. }
  4386. }
  4387. void VerifyOverlayWindow(aura::Window* overlay_window,
  4388. CaptureModeSource source) {
  4389. auto* window_being_recorded = GetWindowBeingRecorded();
  4390. VerifyOverlayStacking(overlay_window, window_being_recorded, source);
  4391. switch (source) {
  4392. case CaptureModeSource::kFullscreen:
  4393. case CaptureModeSource::kWindow:
  4394. EXPECT_EQ(overlay_window->bounds(),
  4395. gfx::Rect(window_being_recorded->bounds().size()));
  4396. break;
  4397. case CaptureModeSource::kRegion:
  4398. EXPECT_EQ(overlay_window->bounds(), kUserRegion);
  4399. break;
  4400. }
  4401. }
  4402. aura::Window* GetWindowBeingRecorded() const {
  4403. auto* controller = CaptureModeController::Get();
  4404. DCHECK(controller->is_recording_in_progress());
  4405. return controller->video_recording_watcher_for_testing()
  4406. ->window_being_recorded();
  4407. }
  4408. protected:
  4409. ProjectorCaptureModeIntegrationHelper projector_helper_;
  4410. std::unique_ptr<aura::Window> window_;
  4411. base::HistogramTester histogram_tester_;
  4412. };
  4413. // static
  4414. constexpr gfx::Rect ProjectorCaptureModeIntegrationTests::kUserRegion;
  4415. TEST_F(ProjectorCaptureModeIntegrationTests, EntryPoint) {
  4416. // With the most recent source type set to kImage, starting capture mode for
  4417. // the projector workflow will still force it to kVideo.
  4418. auto* controller = CaptureModeController::Get();
  4419. controller->SetType(CaptureModeType::kImage);
  4420. // Also, audio recording is initially disabled. However, the projector flow
  4421. // forces it enabled.
  4422. EXPECT_FALSE(controller->enable_audio_recording());
  4423. StartProjectorModeSession();
  4424. EXPECT_TRUE(controller->IsActive());
  4425. auto* session = controller->capture_mode_session();
  4426. EXPECT_TRUE(session->is_in_projector_mode());
  4427. EXPECT_TRUE(controller->enable_audio_recording());
  4428. constexpr char kEntryPointHistogram[] =
  4429. "Ash.CaptureModeController.EntryPoint.ClamshellMode";
  4430. histogram_tester_.ExpectBucketCount(kEntryPointHistogram,
  4431. CaptureModeEntryType::kProjector, 1);
  4432. }
  4433. // Tests that the settings view is simplified in projector mode.
  4434. TEST_F(ProjectorCaptureModeIntegrationTests, CaptureModeSettings) {
  4435. auto* controller = CaptureModeController::Get();
  4436. StartProjectorModeSession();
  4437. auto* event_generator = GetEventGenerator();
  4438. ClickOnView(GetSettingsButton(), event_generator);
  4439. CaptureModeSettingsTestApi test_api;
  4440. // The "Save-to" menu group should never be added.
  4441. CaptureModeMenuGroup* save_to_menu_group = test_api.GetSaveToMenuGroup();
  4442. EXPECT_FALSE(save_to_menu_group);
  4443. // The audio-off option should never be added.
  4444. EXPECT_FALSE(test_api.GetAudioOffOption());
  4445. CaptureModeMenuGroup* audio_input_menu_group =
  4446. test_api.GetAudioInputMenuGroup();
  4447. EXPECT_TRUE(audio_input_menu_group->IsOptionChecked(kAudioMicrophone));
  4448. EXPECT_TRUE(controller->enable_audio_recording());
  4449. }
  4450. // Tests the keyboard navigation for projector mode. The `image_toggle_button_`
  4451. // in `CaptureModeTypeView` and the `Off` audio input option in
  4452. // `CaptureModeSettingsView` are not available in projector mode.
  4453. TEST_F(ProjectorCaptureModeIntegrationTests, KeyboardNavigationBasic) {
  4454. auto* controller = CaptureModeController::Get();
  4455. // Use `kFullscreen` here to minimize the number of tabs to reach the setting
  4456. // button.
  4457. controller->SetSource(CaptureModeSource::kFullscreen);
  4458. StartProjectorModeSession();
  4459. using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
  4460. CaptureModeSessionTestApi test_api(controller->capture_mode_session());
  4461. EXPECT_FALSE(GetImageToggleButton());
  4462. // Tab once, check the current focused view is the video toggle button.
  4463. auto* event_generator = GetEventGenerator();
  4464. SendKey(ui::VKEY_TAB, event_generator);
  4465. EXPECT_EQ(test_api.GetCurrentFocusedView()->GetView(),
  4466. GetVideoToggleButton());
  4467. // Now tab four times to focus the settings button and enter space to open the
  4468. // setting menu.
  4469. SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/4);
  4470. SendKey(ui::VKEY_SPACE, event_generator);
  4471. EXPECT_EQ(FocusGroup::kPendingSettings, test_api.GetCurrentFocusGroup());
  4472. CaptureModeSettingsView* settings_menu =
  4473. test_api.GetCaptureModeSettingsView();
  4474. ASSERT_TRUE(settings_menu);
  4475. CaptureModeSettingsTestApi settings_test_api;
  4476. // The `Off` option should not be visible.
  4477. EXPECT_FALSE(settings_test_api.GetAudioOffOption());
  4478. // Tab twice, the current focused view is the `Microphone` option.
  4479. SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/2);
  4480. EXPECT_EQ(test_api.GetCurrentFocusedView()->GetView(),
  4481. settings_test_api.GetMicrophoneOption());
  4482. }
  4483. TEST_F(ProjectorCaptureModeIntegrationTests, BarButtonsState) {
  4484. auto* controller = CaptureModeController::Get();
  4485. StartProjectorModeSession();
  4486. EXPECT_TRUE(controller->IsActive());
  4487. // The image toggle button shouldn't be available, whereas the video toggle
  4488. // button should be enabled and active.
  4489. EXPECT_FALSE(GetImageToggleButton());
  4490. EXPECT_TRUE(GetVideoToggleButton()->GetEnabled());
  4491. EXPECT_TRUE(GetVideoToggleButton()->GetToggled());
  4492. }
  4493. TEST_F(ProjectorCaptureModeIntegrationTests, StartEndRecording) {
  4494. auto* controller = CaptureModeController::Get();
  4495. controller->SetSource(CaptureModeSource::kFullscreen);
  4496. StartProjectorModeSession();
  4497. EXPECT_TRUE(controller->IsActive());
  4498. histogram_tester_.ExpectUniqueSample(kProjectorCreationFlowHistogramName,
  4499. ProjectorCreationFlow::kSessionStarted,
  4500. /*count=*/1);
  4501. // Hit Enter to begin recording. The recording session should be marked for
  4502. // projector.
  4503. PressAndReleaseKey(ui::VKEY_RETURN);
  4504. EXPECT_CALL(*projector_client(), StartSpeechRecognition());
  4505. WaitForRecordingToStart();
  4506. histogram_tester_.ExpectBucketCount(kProjectorCreationFlowHistogramName,
  4507. ProjectorCreationFlow::kRecordingStarted,
  4508. /*count=*/1);
  4509. EXPECT_FALSE(controller->IsActive());
  4510. EXPECT_TRUE(controller->is_recording_in_progress());
  4511. EXPECT_TRUE(controller->video_recording_watcher_for_testing()
  4512. ->is_in_projector_mode());
  4513. EXPECT_CALL(*projector_client(), StopSpeechRecognition());
  4514. controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
  4515. WaitForCaptureFileToBeSaved();
  4516. histogram_tester_.ExpectBucketCount(kProjectorCreationFlowHistogramName,
  4517. ProjectorCreationFlow::kRecordingEnded,
  4518. /*count=*/1);
  4519. histogram_tester_.ExpectBucketCount(kProjectorCreationFlowHistogramName,
  4520. ProjectorCreationFlow::kSessionStopped,
  4521. /*count=*/1);
  4522. histogram_tester_.ExpectTotalCount(kProjectorCreationFlowHistogramName,
  4523. /*count=*/4);
  4524. }
  4525. TEST_F(ProjectorCaptureModeIntegrationTests,
  4526. ProjectorSessionNeverStartsWhenCaptureModeIsBlocked) {
  4527. auto* controller = CaptureModeController::Get();
  4528. controller->SetSource(CaptureModeSource::kFullscreen);
  4529. auto* test_delegate =
  4530. static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
  4531. test_delegate->set_is_allowed_by_policy(false);
  4532. ProjectorController::Get()->StartProjectorSession("projector_data");
  4533. // Both sessions will never start.
  4534. EXPECT_FALSE(controller->IsActive());
  4535. EXPECT_FALSE(ProjectorSession::Get()->is_active());
  4536. EXPECT_FALSE(controller->is_recording_in_progress());
  4537. }
  4538. TEST_F(ProjectorCaptureModeIntegrationTests,
  4539. ProjectorSessionNeverStartsWhenVideoRecordingIsOnGoing) {
  4540. auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  4541. CaptureModeType::kVideo);
  4542. EXPECT_CALL(
  4543. *projector_client(),
  4544. OnNewScreencastPreconditionChanged(NewScreencastPrecondition(
  4545. NewScreencastPreconditionState::kDisabled,
  4546. {NewScreencastPreconditionReason::kScreenRecordingInProgress})));
  4547. controller->StartVideoRecordingImmediatelyForTesting();
  4548. EXPECT_TRUE(controller->is_recording_in_progress());
  4549. EXPECT_FALSE(ProjectorSession::Get()->is_active());
  4550. EXPECT_NE(ProjectorController::Get()->GetNewScreencastPrecondition().state,
  4551. NewScreencastPreconditionState::kEnabled);
  4552. // There is another OnNewScreencastPreconditionChanged() call during tear
  4553. // down.
  4554. EXPECT_CALL(*projector_client(),
  4555. OnNewScreencastPreconditionChanged(NewScreencastPrecondition(
  4556. NewScreencastPreconditionState::kEnabled, {})));
  4557. }
  4558. namespace {
  4559. enum AbortReason {
  4560. kBlockedByDlp,
  4561. kBlockedByPolicy,
  4562. kUserPressedEsc,
  4563. };
  4564. struct {
  4565. const std::string scope_trace;
  4566. const AbortReason reason;
  4567. } kTestCases[] = {
  4568. {"Blocked by DLP", kBlockedByDlp},
  4569. {"Blocked by policy", kBlockedByPolicy},
  4570. {"User Pressed Esc", kUserPressedEsc},
  4571. };
  4572. } // namespace
  4573. TEST_F(ProjectorCaptureModeIntegrationTests,
  4574. ProjectorSessionAbortedBeforeCountDownStarts) {
  4575. auto* controller = CaptureModeController::Get();
  4576. controller->SetSource(CaptureModeSource::kFullscreen);
  4577. for (const auto& test_case : kTestCases) {
  4578. SCOPED_TRACE(test_case.scope_trace);
  4579. StartProjectorModeSession();
  4580. auto* test_delegate = static_cast<TestCaptureModeDelegate*>(
  4581. controller->delegate_for_testing());
  4582. switch (test_case.reason) {
  4583. case kBlockedByDlp:
  4584. test_delegate->set_is_allowed_by_dlp(false);
  4585. PressAndReleaseKey(ui::VKEY_RETURN);
  4586. break;
  4587. case kBlockedByPolicy:
  4588. test_delegate->set_is_allowed_by_policy(false);
  4589. PressAndReleaseKey(ui::VKEY_RETURN);
  4590. break;
  4591. case kUserPressedEsc:
  4592. PressAndReleaseKey(ui::VKEY_ESCAPE);
  4593. break;
  4594. }
  4595. // The session will end immediately without a count down.
  4596. EXPECT_FALSE(controller->IsActive());
  4597. EXPECT_FALSE(ProjectorSession::Get()->is_active());
  4598. EXPECT_FALSE(controller->is_recording_in_progress());
  4599. // Prepare for next iteration by resetting things back to default.
  4600. test_delegate->ResetAllowancesToDefault();
  4601. }
  4602. histogram_tester_.ExpectBucketCount(kProjectorCreationFlowHistogramName,
  4603. ProjectorCreationFlow::kSessionStarted,
  4604. /*count=*/3);
  4605. histogram_tester_.ExpectBucketCount(kProjectorCreationFlowHistogramName,
  4606. ProjectorCreationFlow::kRecordingAborted,
  4607. /*count=*/3);
  4608. histogram_tester_.ExpectBucketCount(kProjectorCreationFlowHistogramName,
  4609. ProjectorCreationFlow::kSessionStopped,
  4610. /*count=*/3);
  4611. histogram_tester_.ExpectTotalCount(kProjectorCreationFlowHistogramName,
  4612. /*count=*/9);
  4613. }
  4614. TEST_F(ProjectorCaptureModeIntegrationTests,
  4615. ProjectorSessionAbortedAfterCountDownStarts) {
  4616. ui::ScopedAnimationDurationScaleMode animation_scale(
  4617. ui::ScopedAnimationDurationScaleMode::FAST_DURATION);
  4618. auto* controller = CaptureModeController::Get();
  4619. controller->SetSource(CaptureModeSource::kFullscreen);
  4620. for (const auto& test_case : kTestCases) {
  4621. SCOPED_TRACE(test_case.scope_trace);
  4622. StartProjectorModeSession();
  4623. PressAndReleaseKey(ui::VKEY_RETURN);
  4624. auto* test_delegate = static_cast<TestCaptureModeDelegate*>(
  4625. controller->delegate_for_testing());
  4626. switch (test_case.reason) {
  4627. case kBlockedByDlp:
  4628. test_delegate->set_is_allowed_by_dlp(false);
  4629. break;
  4630. case kBlockedByPolicy:
  4631. test_delegate->set_is_allowed_by_policy(false);
  4632. break;
  4633. case kUserPressedEsc:
  4634. PressAndReleaseKey(ui::VKEY_ESCAPE);
  4635. break;
  4636. }
  4637. WaitForSessionToEnd();
  4638. EXPECT_FALSE(ProjectorSession::Get()->is_active());
  4639. EXPECT_FALSE(controller->is_recording_in_progress());
  4640. // Prepare for next iteration by resetting things back to default.
  4641. test_delegate->ResetAllowancesToDefault();
  4642. }
  4643. histogram_tester_.ExpectBucketCount(kProjectorCreationFlowHistogramName,
  4644. ProjectorCreationFlow::kSessionStarted,
  4645. /*count=*/3);
  4646. histogram_tester_.ExpectBucketCount(kProjectorCreationFlowHistogramName,
  4647. ProjectorCreationFlow::kRecordingAborted,
  4648. /*count=*/3);
  4649. histogram_tester_.ExpectBucketCount(kProjectorCreationFlowHistogramName,
  4650. ProjectorCreationFlow::kSessionStopped,
  4651. /*count=*/3);
  4652. histogram_tester_.ExpectTotalCount(kProjectorCreationFlowHistogramName,
  4653. /*count=*/9);
  4654. }
  4655. TEST_F(ProjectorCaptureModeIntegrationTests, RecordingOverlayWidget) {
  4656. auto* controller = CaptureModeController::Get();
  4657. controller->SetSource(CaptureModeSource::kFullscreen);
  4658. StartProjectorModeSession();
  4659. EXPECT_TRUE(controller->IsActive());
  4660. PressAndReleaseKey(ui::VKEY_RETURN);
  4661. WaitForRecordingToStart();
  4662. CaptureModeTestApi test_api;
  4663. RecordingOverlayController* overlay_controller =
  4664. test_api.GetRecordingOverlayController();
  4665. EXPECT_FALSE(overlay_controller->is_enabled());
  4666. auto* overlay_window = overlay_controller->GetOverlayNativeWindow();
  4667. VerifyOverlayEnabledState(overlay_window, /*overlay_enabled_state=*/false);
  4668. auto* projector_controller = ProjectorControllerImpl::Get();
  4669. projector_controller->EnableAnnotatorTool();
  4670. EXPECT_TRUE(overlay_controller->is_enabled());
  4671. VerifyOverlayEnabledState(overlay_window, /*overlay_enabled_state=*/true);
  4672. projector_controller->ResetTools();
  4673. EXPECT_FALSE(overlay_controller->is_enabled());
  4674. VerifyOverlayEnabledState(overlay_window, /*overlay_enabled_state=*/false);
  4675. }
  4676. TEST_F(ProjectorCaptureModeIntegrationTests, RecordingOverlayDockedMagnifier) {
  4677. auto* controller = CaptureModeController::Get();
  4678. controller->SetSource(CaptureModeSource::kFullscreen);
  4679. StartProjectorModeSession();
  4680. EXPECT_TRUE(controller->IsActive());
  4681. PressAndReleaseKey(ui::VKEY_RETURN);
  4682. WaitForRecordingToStart();
  4683. CaptureModeTestApi test_api;
  4684. RecordingOverlayController* overlay_controller =
  4685. test_api.GetRecordingOverlayController();
  4686. auto* projector_controller = ProjectorControllerImpl::Get();
  4687. projector_controller->EnableAnnotatorTool();
  4688. EXPECT_TRUE(overlay_controller->is_enabled());
  4689. auto* overlay_window = overlay_controller->GetOverlayNativeWindow();
  4690. // Before the docked magnifier gets enabled, the overlay's bounds should match
  4691. // the root window's bounds.
  4692. auto* root_window = overlay_window->GetRootWindow();
  4693. const gfx::Rect root_window_bounds = root_window->bounds();
  4694. EXPECT_EQ(root_window_bounds, overlay_window->GetBoundsInRootWindow());
  4695. // Once the magnifier is enabled, the overlay should be pushed down so that
  4696. // it doesn't cover the magnifier viewport.
  4697. auto* docked_magnifier = Shell::Get()->docked_magnifier_controller();
  4698. docked_magnifier->SetEnabled(true);
  4699. const gfx::Rect expected_bounds = gfx::SubtractRects(
  4700. root_window_bounds,
  4701. docked_magnifier->GetTotalMagnifierBoundsForRoot(root_window));
  4702. EXPECT_EQ(expected_bounds, overlay_window->GetBoundsInRootWindow());
  4703. // It should go back to original bounds once the magnifier is disabled.
  4704. docked_magnifier->SetEnabled(false);
  4705. EXPECT_EQ(root_window_bounds, overlay_window->GetBoundsInRootWindow());
  4706. }
  4707. TEST_P(ProjectorCaptureModeIntegrationTests, RecordingOverlayWidgetBounds) {
  4708. const auto capture_source = GetParam();
  4709. StartRecordingForProjectorFromSource(capture_source);
  4710. CaptureModeTestApi test_api;
  4711. RecordingOverlayController* overlay_controller =
  4712. test_api.GetRecordingOverlayController();
  4713. EXPECT_FALSE(overlay_controller->is_enabled());
  4714. auto* overlay_window = overlay_controller->GetOverlayNativeWindow();
  4715. VerifyOverlayWindow(overlay_window, capture_source);
  4716. }
  4717. // Regression test for https://crbug.com/1322655.
  4718. TEST_P(ProjectorCaptureModeIntegrationTests,
  4719. RecordingOverlayWidgetBoundsSecondDisplay) {
  4720. UpdateDisplay("800x700,801+0-800x700");
  4721. const gfx::Point point_in_second_display = gfx::Point(1000, 500);
  4722. auto* event_generator = GetEventGenerator();
  4723. MoveMouseToAndUpdateCursorDisplay(point_in_second_display, event_generator);
  4724. window()->SetBoundsInScreen(
  4725. gfx::Rect(900, 0, 600, 500),
  4726. display::Screen::GetScreen()->GetDisplayNearestWindow(
  4727. Shell::GetAllRootWindows()[1]));
  4728. const auto capture_source = GetParam();
  4729. StartRecordingForProjectorFromSource(capture_source);
  4730. const auto roots = Shell::GetAllRootWindows();
  4731. EXPECT_EQ(roots[1], GetWindowBeingRecorded()->GetRootWindow());
  4732. CaptureModeTestApi test_api;
  4733. RecordingOverlayController* overlay_controller =
  4734. test_api.GetRecordingOverlayController();
  4735. EXPECT_FALSE(overlay_controller->is_enabled());
  4736. auto* overlay_window = overlay_controller->GetOverlayNativeWindow();
  4737. VerifyOverlayWindow(overlay_window, capture_source);
  4738. }
  4739. namespace {
  4740. // Defines a class that intercepts the events at the post-target handling phase
  4741. // and caches the last event target to which the event was routed.
  4742. class EventTargetCatcher : public ui::EventHandler {
  4743. public:
  4744. EventTargetCatcher() {
  4745. Shell::GetPrimaryRootWindow()->AddPostTargetHandler(this);
  4746. }
  4747. EventTargetCatcher(const EventTargetCatcher&) = delete;
  4748. EventTargetCatcher& operator=(const EventTargetCatcher&) = delete;
  4749. ~EventTargetCatcher() override {
  4750. Shell::GetPrimaryRootWindow()->RemovePostTargetHandler(this);
  4751. }
  4752. ui::EventTarget* last_event_target() { return last_event_target_; }
  4753. // ui::EventHandler:
  4754. void OnEvent(ui::Event* event) override {
  4755. ui::EventHandler::OnEvent(event);
  4756. last_event_target_ = event->target();
  4757. }
  4758. private:
  4759. ui::EventTarget* last_event_target_ = nullptr;
  4760. };
  4761. } // namespace
  4762. TEST_F(ProjectorCaptureModeIntegrationTests, RecordingOverlayWidgetTargeting) {
  4763. auto* controller = CaptureModeController::Get();
  4764. controller->SetSource(CaptureModeSource::kFullscreen);
  4765. StartProjectorModeSession();
  4766. EXPECT_TRUE(controller->IsActive());
  4767. PressAndReleaseKey(ui::VKEY_RETURN);
  4768. WaitForRecordingToStart();
  4769. CaptureModeTestApi test_api;
  4770. RecordingOverlayController* overlay_controller =
  4771. test_api.GetRecordingOverlayController();
  4772. auto* projector_controller = ProjectorControllerImpl::Get();
  4773. projector_controller->EnableAnnotatorTool();
  4774. EXPECT_TRUE(overlay_controller->is_enabled());
  4775. auto* overlay_window = overlay_controller->GetOverlayNativeWindow();
  4776. VerifyOverlayEnabledState(overlay_window, /*overlay_enabled_state=*/true);
  4777. // Open the annotation tray bubble.
  4778. auto* root_window = Shell::GetPrimaryRootWindow();
  4779. auto* status_area_widget =
  4780. RootWindowController::ForWindow(root_window)->GetStatusAreaWidget();
  4781. ProjectorAnnotationTray* annotations_tray =
  4782. status_area_widget->projector_annotation_tray();
  4783. annotations_tray->ShowBubble();
  4784. EXPECT_TRUE(annotations_tray->GetBubbleView());
  4785. // Clicking anywhere outside the projector shelf pod should be targeted to the
  4786. // overlay widget window and close the annotation tray bubble.
  4787. EventTargetCatcher event_target_catcher;
  4788. auto* event_generator = GetEventGenerator();
  4789. event_generator->set_current_screen_location(gfx::Point(10, 10));
  4790. event_generator->ClickLeftButton();
  4791. EXPECT_EQ(overlay_window, event_target_catcher.last_event_target());
  4792. EXPECT_FALSE(annotations_tray->GetBubbleView());
  4793. // Now move the mouse over the projector shelf pod, the overlay should not
  4794. // consume the event, and it should instead go through to that pod.
  4795. EXPECT_TRUE(annotations_tray->visible_preferred());
  4796. event_generator->MoveMouseTo(
  4797. annotations_tray->GetBoundsInScreen().CenterPoint());
  4798. EXPECT_EQ(annotations_tray->GetWidget()->GetNativeWindow(),
  4799. event_target_catcher.last_event_target());
  4800. // The overlay status hasn't changed.
  4801. VerifyOverlayEnabledState(overlay_window, /*overlay_enabled_state=*/true);
  4802. // Now move the mouse and then click on the stop recording button, the overlay
  4803. // should not consume the event. The video recording should be ended.
  4804. StopRecordingButtonTray* stop_recording_button =
  4805. status_area_widget->stop_recording_button_tray();
  4806. const gfx::Point stop_button_center_point =
  4807. stop_recording_button->GetBoundsInScreen().CenterPoint();
  4808. event_generator->MoveMouseTo(stop_button_center_point);
  4809. event_generator->ClickLeftButton();
  4810. EXPECT_FALSE(controller->is_recording_in_progress());
  4811. }
  4812. // Tests that auto hidden shelf can be brought back if user moves mouse to the
  4813. // shelf activation area even while annotation is active.
  4814. TEST_F(ProjectorCaptureModeIntegrationTests,
  4815. BringBackAutoHiddenShelfWhileAnnotationIsOn) {
  4816. auto* root_window = Shell::GetPrimaryRootWindow();
  4817. // Set `shelf` to always auto-hidden.
  4818. Shelf* shelf = RootWindowController::ForWindow(root_window)->shelf();
  4819. shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
  4820. auto* controller = CaptureModeController::Get();
  4821. controller->SetSource(CaptureModeSource::kFullscreen);
  4822. StartProjectorModeSession();
  4823. EXPECT_TRUE(controller->IsActive());
  4824. PressAndReleaseKey(ui::VKEY_RETURN);
  4825. WaitForRecordingToStart();
  4826. auto* event_generator = GetEventGenerator();
  4827. auto* projector_controller = ProjectorControllerImpl::Get();
  4828. const gfx::Rect root_window_bounds_in_screen =
  4829. root_window->GetBoundsInScreen();
  4830. const int display_width = root_window_bounds_in_screen.width();
  4831. const int display_height = root_window_bounds_in_screen.height();
  4832. const gfx::Point display_center = root_window_bounds_in_screen.CenterPoint();
  4833. struct {
  4834. const std::string scope_trace;
  4835. const ShelfAlignment shelf_alignment;
  4836. } kTestCases[] = {
  4837. {"Shelf has botton alignment", ShelfAlignment::kBottom},
  4838. {"Shelf has left alignment", ShelfAlignment::kLeft},
  4839. {"Shelf has right alignment", ShelfAlignment::kRight},
  4840. };
  4841. for (const auto& test_case : kTestCases) {
  4842. SCOPED_TRACE(test_case.scope_trace);
  4843. // Enable annotation.
  4844. projector_controller->EnableAnnotatorTool();
  4845. // Verify shelf is invisible right now.
  4846. EXPECT_FALSE(shelf->IsVisible());
  4847. shelf->SetAlignment(test_case.shelf_alignment);
  4848. switch (test_case.shelf_alignment) {
  4849. case ShelfAlignment::kBottom:
  4850. case ShelfAlignment::kBottomLocked:
  4851. event_generator->MoveMouseTo(0, display_height);
  4852. break;
  4853. case ShelfAlignment::kLeft:
  4854. event_generator->MoveMouseTo(0, display_height);
  4855. break;
  4856. case ShelfAlignment::kRight:
  4857. event_generator->MoveMouseTo(display_width, display_height);
  4858. break;
  4859. }
  4860. // Verify after mouse is moved on top of the shelf activation area, shelf is
  4861. // brought back and visible once the animation to show shelf is finished.
  4862. ShellTestApi().WaitForWindowFinishAnimating(shelf->GetWindow());
  4863. EXPECT_TRUE(shelf->IsVisible());
  4864. // Disable annotation.
  4865. projector_controller->ResetTools();
  4866. // Move mouse to the outside of the shelf activation area, and wait for the
  4867. // animation to hide shelf to finish.
  4868. event_generator->MoveMouseTo(display_center);
  4869. ShellTestApi().WaitForWindowFinishAnimating(shelf->GetWindow());
  4870. }
  4871. }
  4872. // Tests that neither preview notification nor recording in tote is shown if in
  4873. // projector mode.
  4874. TEST_P(ProjectorCaptureModeIntegrationTests,
  4875. NotShowRecordingInToteOrNotificationForProjectorMode) {
  4876. const auto capture_source = GetParam();
  4877. StartRecordingForProjectorFromSource(capture_source);
  4878. CaptureModeTestApi().StopVideoRecording();
  4879. WaitForCaptureFileToBeSaved();
  4880. EXPECT_FALSE(GetPreviewNotification());
  4881. ash::HoldingSpaceTestApi holding_space_api;
  4882. EXPECT_TRUE(holding_space_api.GetScreenCaptureViews().empty());
  4883. }
  4884. // Tests that metrics are recorded correctly for capture configuration entering
  4885. // from projector in both clamshell and tablet mode.
  4886. TEST_P(ProjectorCaptureModeIntegrationTests,
  4887. ProjectorCaptureConfigurationMetrics) {
  4888. const auto capture_source = GetParam();
  4889. constexpr char kProjectorCaptureConfigurationHistogramBase[] =
  4890. "Ash.CaptureModeController.Projector.CaptureConfiguration";
  4891. ash::CaptureModeTestApi test_api;
  4892. const bool kTabletEnabledStates[]{false, true};
  4893. for (const bool tablet_enabled : kTabletEnabledStates) {
  4894. if (tablet_enabled) {
  4895. SwitchToTabletMode();
  4896. EXPECT_TRUE(Shell::Get()->IsInTabletMode());
  4897. } else {
  4898. EXPECT_FALSE(Shell::Get()->IsInTabletMode());
  4899. }
  4900. histogram_tester_.ExpectBucketCount(
  4901. GetCaptureModeHistogramName(
  4902. kProjectorCaptureConfigurationHistogramBase),
  4903. GetConfiguration(CaptureModeType::kVideo, capture_source), 0);
  4904. StartRecordingForProjectorFromSource(capture_source);
  4905. WaitForSeconds(1);
  4906. test_api.StopVideoRecording();
  4907. EXPECT_FALSE(CaptureModeController::Get()->is_recording_in_progress());
  4908. histogram_tester_.ExpectUniqueSample(
  4909. GetCaptureModeHistogramName(
  4910. kProjectorCaptureConfigurationHistogramBase),
  4911. GetConfiguration(CaptureModeType::kVideo, capture_source), 1);
  4912. WaitForCaptureFileToBeSaved();
  4913. }
  4914. }
  4915. // Tests that metrics are recorded correctly for screen recording length
  4916. // entering from projector in both clamshell and tablet mode.
  4917. TEST_P(ProjectorCaptureModeIntegrationTests,
  4918. ProjectorScreenRecordingLengthMetrics) {
  4919. const auto capture_source = GetParam();
  4920. constexpr char kProjectorRecordTimeHistogramBase[] =
  4921. "Ash.CaptureModeController.Projector.ScreenRecordingLength";
  4922. ash::CaptureModeTestApi test_api;
  4923. const bool kTabletEnabledStates[]{false, true};
  4924. for (const bool tablet_enabled : kTabletEnabledStates) {
  4925. if (tablet_enabled) {
  4926. SwitchToTabletMode();
  4927. EXPECT_TRUE(Shell::Get()->IsInTabletMode());
  4928. } else {
  4929. EXPECT_FALSE(Shell::Get()->IsInTabletMode());
  4930. }
  4931. StartRecordingForProjectorFromSource(capture_source);
  4932. WaitForSeconds(5);
  4933. test_api.StopVideoRecording();
  4934. EXPECT_FALSE(CaptureModeController::Get()->is_recording_in_progress());
  4935. WaitForCaptureFileToBeSaved();
  4936. histogram_tester_.ExpectUniqueSample(
  4937. GetCaptureModeHistogramName(kProjectorRecordTimeHistogramBase),
  4938. /*seconds=*/5, /*count=*/1);
  4939. }
  4940. }
  4941. // Tests that metrics are recorded correctly for capture region adjustment
  4942. // entering from projector in both clamshell and tablet mode.
  4943. TEST_F(ProjectorCaptureModeIntegrationTests,
  4944. ProjectorCaptureRegionAdjustmentTest) {
  4945. constexpr char kProjectorCaptureRegionAdjustmentHistogramBase[] =
  4946. "Ash.CaptureModeController.Projector.CaptureRegionAdjusted";
  4947. auto histogram_name = GetCaptureModeHistogramName(
  4948. kProjectorCaptureRegionAdjustmentHistogramBase);
  4949. histogram_tester_.ExpectBucketCount(
  4950. GetCaptureModeHistogramName(
  4951. kProjectorCaptureRegionAdjustmentHistogramBase),
  4952. 0, 0);
  4953. auto resize_and_reset_region = [](ui::test::EventGenerator* event_generator,
  4954. const gfx::Point& top_right) {
  4955. // Enlarges the region and then resize it back to its original size.
  4956. event_generator->set_current_screen_location(top_right);
  4957. event_generator->DragMouseTo(top_right + gfx::Vector2d(50, 50));
  4958. event_generator->DragMouseTo(top_right);
  4959. };
  4960. auto move_and_reset_region = [](ui::test::EventGenerator* event_generator,
  4961. const gfx::Point& drag_point) {
  4962. // Moves the region and then moves it back to its original position.
  4963. event_generator->set_current_screen_location(drag_point);
  4964. event_generator->DragMouseTo(drag_point + gfx::Vector2d(-50, -50));
  4965. event_generator->DragMouseTo(drag_point);
  4966. };
  4967. ash::CaptureModeTestApi test_api;
  4968. auto* event_generator = GetEventGenerator();
  4969. const gfx::Rect target_region(gfx::Rect(100, 100, 200, 200));
  4970. auto top_right = target_region.top_right();
  4971. const bool kTabletEnabledStates[] = {false, true};
  4972. for (const bool tablet_enabled : kTabletEnabledStates) {
  4973. if (tablet_enabled) {
  4974. SwitchToTabletMode();
  4975. EXPECT_TRUE(Shell::Get()->IsInTabletMode());
  4976. } else {
  4977. EXPECT_FALSE(Shell::Get()->IsInTabletMode());
  4978. }
  4979. StartProjectorModeSession();
  4980. auto* controller = CaptureModeController::Get();
  4981. controller->SetSource(CaptureModeSource::kRegion);
  4982. test_api.SetUserSelectedRegion(target_region);
  4983. // Resize the region twice by dragging the top right of the region out and
  4984. // then back again.
  4985. resize_and_reset_region(event_generator, top_right);
  4986. // Move the region twice by dragging within the region.
  4987. const gfx::Point drag_point(300, 300);
  4988. move_and_reset_region(event_generator, drag_point);
  4989. test_api.PerformCapture();
  4990. WaitForSeconds(1);
  4991. test_api.StopVideoRecording();
  4992. EXPECT_FALSE(controller->is_recording_in_progress());
  4993. histogram_tester_.ExpectBucketCount(
  4994. GetCaptureModeHistogramName(
  4995. kProjectorCaptureRegionAdjustmentHistogramBase),
  4996. 4, 1);
  4997. WaitForCaptureFileToBeSaved();
  4998. }
  4999. }
  5000. INSTANTIATE_TEST_SUITE_P(All,
  5001. ProjectorCaptureModeIntegrationTests,
  5002. testing::Values(CaptureModeSource::kFullscreen,
  5003. CaptureModeSource::kRegion,
  5004. CaptureModeSource::kWindow));
  5005. // -----------------------------------------------------------------------------
  5006. // CaptureModeSettingsTest:
  5007. // Test fixture for CaptureMode settings view.
  5008. class CaptureModeSettingsTest : public CaptureModeTest {
  5009. public:
  5010. CaptureModeSettingsTest() = default;
  5011. ~CaptureModeSettingsTest() override = default;
  5012. // CaptureModeTest:
  5013. void SetUp() override {
  5014. CaptureModeTest::SetUp();
  5015. FakeFolderSelectionDialogFactory::Start();
  5016. }
  5017. void TearDown() override {
  5018. FakeFolderSelectionDialogFactory::Stop();
  5019. CaptureModeTest::TearDown();
  5020. }
  5021. CaptureModeSettingsView* GetCaptureModeSettingsView() const {
  5022. auto* session = CaptureModeController::Get()->capture_mode_session();
  5023. DCHECK(session);
  5024. return CaptureModeSessionTestApi(session).GetCaptureModeSettingsView();
  5025. }
  5026. void WaitForSettingsMenuToBeRefreshed() {
  5027. base::RunLoop run_loop;
  5028. CaptureModeSettingsTestApi().SetOnSettingsMenuRefreshedCallback(
  5029. run_loop.QuitClosure());
  5030. run_loop.Run();
  5031. }
  5032. };
  5033. enum class NudgeDismissalCause {
  5034. kPressSettingsButton,
  5035. kCaptureViaEnterKey,
  5036. kCaptureViaClickOnScreen,
  5037. kCaptureViaLabelButton,
  5038. };
  5039. // Test fixture to test that various causes that lead to the dismissal of the
  5040. // user nudge, they dismiss it forever.
  5041. class CaptureModeNudgeDismissalTest
  5042. : public CaptureModeSettingsTest,
  5043. public ::testing::WithParamInterface<NudgeDismissalCause> {
  5044. public:
  5045. // Starts a session appropriate for the test param.
  5046. CaptureModeController* StartSession() {
  5047. switch (GetParam()) {
  5048. case NudgeDismissalCause::kPressSettingsButton:
  5049. case NudgeDismissalCause::kCaptureViaEnterKey:
  5050. case NudgeDismissalCause::kCaptureViaClickOnScreen:
  5051. return StartCaptureSession(CaptureModeSource::kFullscreen,
  5052. CaptureModeType::kImage);
  5053. case NudgeDismissalCause::kCaptureViaLabelButton:
  5054. auto* controller = CaptureModeController::Get();
  5055. controller->SetUserCaptureRegion(gfx::Rect(200, 300), /*by_user=*/true);
  5056. StartCaptureSession(CaptureModeSource::kRegion,
  5057. CaptureModeType::kImage);
  5058. return controller;
  5059. }
  5060. }
  5061. void DoDismissalAction() {
  5062. auto* controller = CaptureModeController::Get();
  5063. auto* event_generator = GetEventGenerator();
  5064. switch (GetParam()) {
  5065. case NudgeDismissalCause::kPressSettingsButton:
  5066. ClickOnView(GetSettingsButton(), event_generator);
  5067. break;
  5068. case NudgeDismissalCause::kCaptureViaEnterKey:
  5069. PressAndReleaseKey(ui::VKEY_RETURN);
  5070. EXPECT_FALSE(controller->IsActive());
  5071. break;
  5072. case NudgeDismissalCause::kCaptureViaClickOnScreen:
  5073. event_generator->MoveMouseToCenterOf(Shell::GetPrimaryRootWindow());
  5074. event_generator->ClickLeftButton();
  5075. EXPECT_FALSE(controller->IsActive());
  5076. break;
  5077. case NudgeDismissalCause::kCaptureViaLabelButton:
  5078. auto* label_button_widget =
  5079. CaptureModeSessionTestApi(controller->capture_mode_session())
  5080. .GetCaptureLabelWidget();
  5081. EXPECT_TRUE(label_button_widget);
  5082. ClickOnView(label_button_widget->GetContentsView(), event_generator);
  5083. break;
  5084. }
  5085. }
  5086. };
  5087. TEST_P(CaptureModeNudgeDismissalTest, NudgeDismissedForever) {
  5088. auto* controller = StartSession();
  5089. auto* capture_session = controller->capture_mode_session();
  5090. auto* capture_toast_controller = capture_session->capture_toast_controller();
  5091. auto* nudge_controller = GetUserNudgeController();
  5092. ASSERT_TRUE(nudge_controller);
  5093. EXPECT_TRUE(nudge_controller->is_visible());
  5094. EXPECT_TRUE(capture_toast_controller->capture_toast_widget());
  5095. ASSERT_TRUE(capture_toast_controller->current_toast_type());
  5096. EXPECT_EQ(*(capture_toast_controller->current_toast_type()),
  5097. CaptureToastType::kUserNudge);
  5098. // Trigger the action that dismisses the nudge forever, it should be removed
  5099. // in this session (if the action doesn't stop the session) and any future
  5100. // sessions.
  5101. DoDismissalAction();
  5102. if (controller->IsActive()) {
  5103. EXPECT_FALSE(GetUserNudgeController());
  5104. // Close the session in preparation for opening a new one.
  5105. controller->Stop();
  5106. }
  5107. // Reopen a new session, the nudge should not show anymore.
  5108. StartImageRegionCapture();
  5109. EXPECT_FALSE(GetUserNudgeController());
  5110. }
  5111. INSTANTIATE_TEST_SUITE_P(
  5112. All,
  5113. CaptureModeNudgeDismissalTest,
  5114. testing::Values(NudgeDismissalCause::kPressSettingsButton,
  5115. NudgeDismissalCause::kCaptureViaEnterKey,
  5116. NudgeDismissalCause::kCaptureViaClickOnScreen,
  5117. NudgeDismissalCause::kCaptureViaLabelButton));
  5118. TEST_F(CaptureModeSettingsTest, NudgeChangesRootWithBar) {
  5119. UpdateDisplay("800x700,801+0-800x700");
  5120. auto* event_generator = GetEventGenerator();
  5121. MoveMouseToAndUpdateCursorDisplay(gfx::Point(100, 500), event_generator);
  5122. auto* controller = StartCaptureSession(CaptureModeSource::kFullscreen,
  5123. CaptureModeType::kImage);
  5124. auto* session = controller->capture_mode_session();
  5125. auto* capture_toast_controller = session->capture_toast_controller();
  5126. EXPECT_EQ(Shell::GetAllRootWindows()[0], session->current_root());
  5127. EXPECT_EQ(capture_toast_controller->capture_toast_widget()
  5128. ->GetNativeWindow()
  5129. ->GetRootWindow(),
  5130. session->current_root());
  5131. MoveMouseToAndUpdateCursorDisplay(gfx::Point(1000, 500), event_generator);
  5132. EXPECT_EQ(Shell::GetAllRootWindows()[1], session->current_root());
  5133. EXPECT_EQ(capture_toast_controller->capture_toast_widget()
  5134. ->GetNativeWindow()
  5135. ->GetRootWindow(),
  5136. session->current_root());
  5137. }
  5138. TEST_F(CaptureModeSettingsTest, NudgeBehaviorWhenSelectingRegion) {
  5139. UpdateDisplay("800x700,801+0-800x700");
  5140. auto* event_generator = GetEventGenerator();
  5141. MoveMouseToAndUpdateCursorDisplay(gfx::Point(100, 500), event_generator);
  5142. auto* controller = StartImageRegionCapture();
  5143. auto* session = controller->capture_mode_session();
  5144. EXPECT_EQ(Shell::GetAllRootWindows()[0], session->current_root());
  5145. // Nudge hides while selecting a region, but doesn't change roots until the
  5146. // region change is committed.
  5147. auto* nudge_controller = GetUserNudgeController();
  5148. MoveMouseToAndUpdateCursorDisplay(gfx::Point(1000, 500), event_generator);
  5149. event_generator->PressLeftButton();
  5150. EXPECT_FALSE(nudge_controller->is_visible());
  5151. event_generator->MoveMouseBy(50, 60);
  5152. event_generator->ReleaseLeftButton();
  5153. EXPECT_EQ(Shell::GetAllRootWindows()[1], session->current_root());
  5154. // The nudge shows again, and is on the second display.
  5155. EXPECT_TRUE(nudge_controller->is_visible());
  5156. EXPECT_EQ(session->capture_toast_controller()
  5157. ->capture_toast_widget()
  5158. ->GetNativeWindow()
  5159. ->GetRootWindow(),
  5160. session->current_root());
  5161. }
  5162. TEST_F(CaptureModeSettingsTest, NudgeDoesNotShowForAllUserTypes) {
  5163. struct {
  5164. std::string trace;
  5165. user_manager::UserType user_type;
  5166. bool can_see_nudge;
  5167. } kTestCases[] = {
  5168. {"regular user", user_manager::USER_TYPE_REGULAR, true},
  5169. {"child", user_manager::USER_TYPE_CHILD, true},
  5170. {"guest", user_manager::USER_TYPE_GUEST, false},
  5171. {"public account", user_manager::USER_TYPE_PUBLIC_ACCOUNT, false},
  5172. {"kiosk app", user_manager::USER_TYPE_KIOSK_APP, false},
  5173. {"arc kiosk app", user_manager::USER_TYPE_ARC_KIOSK_APP, false},
  5174. {"web kiosk app", user_manager::USER_TYPE_WEB_KIOSK_APP, false},
  5175. {"active dir", user_manager::USER_TYPE_ACTIVE_DIRECTORY, false},
  5176. };
  5177. for (const auto& test_case : kTestCases) {
  5178. SCOPED_TRACE(test_case.trace);
  5179. ClearLogin();
  5180. SimulateUserLogin("example@gmail.com", test_case.user_type);
  5181. auto* controller = StartImageRegionCapture();
  5182. EXPECT_EQ(test_case.can_see_nudge, controller->CanShowUserNudge());
  5183. auto* nudge_controller = GetUserNudgeController();
  5184. EXPECT_EQ(test_case.can_see_nudge, !!nudge_controller);
  5185. controller->Stop();
  5186. }
  5187. }
  5188. // Tests that it's possbile to take a screenshot using the keyboard shortcut at
  5189. // the login screen without any crashes. https://crbug.com/1266728.
  5190. TEST_F(CaptureModeSettingsTest, TakeScreenshotAtLoginScreen) {
  5191. ClearLogin();
  5192. PressAndReleaseKey(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_CONTROL_DOWN);
  5193. WaitForCaptureFileToBeSaved();
  5194. }
  5195. // Tests that clicking on audio input buttons updates the state in the
  5196. // controller, and persists between sessions.
  5197. TEST_F(CaptureModeSettingsTest, AudioInputSettingsMenu) {
  5198. auto* controller = StartImageRegionCapture();
  5199. auto* event_generator = GetEventGenerator();
  5200. // Test that the audio recording preference is defaulted to off.
  5201. ClickOnView(GetSettingsButton(), event_generator);
  5202. EXPECT_FALSE(controller->enable_audio_recording());
  5203. CaptureModeSettingsTestApi test_api;
  5204. CaptureModeMenuGroup* audio_input_menu_group =
  5205. test_api.GetAudioInputMenuGroup();
  5206. EXPECT_TRUE(audio_input_menu_group->IsOptionChecked(kAudioOff));
  5207. EXPECT_FALSE(audio_input_menu_group->IsOptionChecked(kAudioMicrophone));
  5208. // Click on the |microphone| option. It should be checked after click along
  5209. // with |off| is unchecked. Recording preference is set to microphone.
  5210. views::View* microphone_option = test_api.GetMicrophoneOption();
  5211. ClickOnView(microphone_option, event_generator);
  5212. EXPECT_TRUE(audio_input_menu_group->IsOptionChecked(kAudioMicrophone));
  5213. EXPECT_FALSE(audio_input_menu_group->IsOptionChecked(kAudioOff));
  5214. EXPECT_TRUE(controller->enable_audio_recording());
  5215. // Test that the user selected audio preference for audio recording is
  5216. // remembered between sessions.
  5217. SendKey(ui::VKEY_ESCAPE, event_generator);
  5218. StartImageRegionCapture();
  5219. EXPECT_TRUE(controller->enable_audio_recording());
  5220. }
  5221. TEST_F(CaptureModeSettingsTest, SelectFolderFromDialog) {
  5222. auto* controller = StartImageRegionCapture();
  5223. auto* event_generator = GetEventGenerator();
  5224. ClickOnView(GetSettingsButton(), event_generator);
  5225. // Initially there should only be an option for the default downloads folder.
  5226. CaptureModeSettingsTestApi test_api;
  5227. EXPECT_TRUE(test_api.GetDefaultDownloadsOption());
  5228. EXPECT_FALSE(test_api.GetCustomFolderOptionIfAny());
  5229. CaptureModeMenuGroup* save_to_menu_group = test_api.GetSaveToMenuGroup();
  5230. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
  5231. ClickOnView(test_api.GetSelectFolderMenuItem(), event_generator);
  5232. EXPECT_TRUE(IsFolderSelectionDialogShown());
  5233. EXPECT_FALSE(IsAllCaptureSessionUisVisible());
  5234. auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
  5235. auto* dialog_window = dialog_factory->GetDialogWindow();
  5236. auto* window_state = WindowState::Get(dialog_window);
  5237. ASSERT_TRUE(window_state);
  5238. EXPECT_FALSE(window_state->CanMaximize());
  5239. EXPECT_FALSE(window_state->CanMinimize());
  5240. EXPECT_FALSE(window_state->CanResize());
  5241. // Accepting the dialog with a folder selection should dismiss it and add a
  5242. // new option for the custom selected folder in the settings menu.
  5243. const base::FilePath custom_folder(
  5244. CreateCustomFolderInUserDownloadsPath("test"));
  5245. dialog_factory->AcceptPath(custom_folder);
  5246. WaitForSettingsMenuToBeRefreshed();
  5247. EXPECT_FALSE(IsFolderSelectionDialogShown());
  5248. EXPECT_TRUE(IsAllCaptureSessionUisVisible());
  5249. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kCustomFolder));
  5250. EXPECT_FALSE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
  5251. EXPECT_EQ(u"test",
  5252. save_to_menu_group->GetOptionLabelForTesting(kCustomFolder));
  5253. // This should update the folder that will be used by the controller.
  5254. auto capture_folder = controller->GetCurrentCaptureFolder();
  5255. EXPECT_EQ(capture_folder.path, custom_folder);
  5256. EXPECT_FALSE(capture_folder.is_default_downloads_folder);
  5257. }
  5258. // Tests that folder selection dialog can be opened without crash while in
  5259. // window capture mode.
  5260. TEST_F(CaptureModeSettingsTest, SelectFolderInWindowCaptureMode) {
  5261. std::unique_ptr<aura::Window> window1(
  5262. CreateTestWindow(gfx::Rect(0, 0, 200, 300)));
  5263. StartCaptureSession(CaptureModeSource::kWindow, CaptureModeType::kImage);
  5264. auto* event_generator = GetEventGenerator();
  5265. ClickOnView(GetSettingsButton(), event_generator);
  5266. CaptureModeSettingsTestApi test_api;
  5267. ClickOnView(test_api.GetSelectFolderMenuItem(), event_generator);
  5268. EXPECT_TRUE(IsFolderSelectionDialogShown());
  5269. }
  5270. TEST_F(CaptureModeSettingsTest, DismissDialogWithoutSelection) {
  5271. auto* controller = StartImageRegionCapture();
  5272. const auto old_capture_folder = controller->GetCurrentCaptureFolder();
  5273. // Open the settings menu, and click the "Select folder" menu item.
  5274. auto* event_generator = GetEventGenerator();
  5275. ClickOnView(GetSettingsButton(), event_generator);
  5276. CaptureModeSettingsTestApi test_api;
  5277. ClickOnView(test_api.GetSelectFolderMenuItem(), event_generator);
  5278. EXPECT_TRUE(IsFolderSelectionDialogShown());
  5279. // Cancel and dismiss the dialog. There should be no change in the folder
  5280. // selection.
  5281. auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
  5282. dialog_factory->CancelDialog();
  5283. EXPECT_FALSE(IsFolderSelectionDialogShown());
  5284. EXPECT_FALSE(test_api.GetCustomFolderOptionIfAny());
  5285. CaptureModeMenuGroup* save_to_menu_group = test_api.GetSaveToMenuGroup();
  5286. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
  5287. const auto new_capture_folder = controller->GetCurrentCaptureFolder();
  5288. EXPECT_EQ(old_capture_folder.path, new_capture_folder.path);
  5289. EXPECT_EQ(old_capture_folder.is_default_downloads_folder,
  5290. new_capture_folder.is_default_downloads_folder);
  5291. }
  5292. TEST_F(CaptureModeSettingsTest, AcceptUpdatedCustomFolderFromDialog) {
  5293. // Begin a new session with a pre-configured custom folder.
  5294. auto* controller = CaptureModeController::Get();
  5295. const base::FilePath custom_folder(
  5296. CreateCustomFolderInUserDownloadsPath("test"));
  5297. controller->SetCustomCaptureFolder(custom_folder);
  5298. StartImageRegionCapture();
  5299. // Open the settings menu and check there already exists an item for that
  5300. // pre-configured custom folder.
  5301. auto* event_generator = GetEventGenerator();
  5302. ClickOnView(GetSettingsButton(), event_generator);
  5303. WaitForSettingsMenuToBeRefreshed();
  5304. CaptureModeSettingsTestApi test_api;
  5305. EXPECT_TRUE(test_api.GetDefaultDownloadsOption());
  5306. auto* custom_folder_view = test_api.GetCustomFolderOptionIfAny();
  5307. EXPECT_TRUE(custom_folder_view);
  5308. CaptureModeMenuGroup* save_to_menu_group = test_api.GetSaveToMenuGroup();
  5309. EXPECT_FALSE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
  5310. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kCustomFolder));
  5311. // Now open the folder selection dialog and select a different folder. The
  5312. // existing *same* item in the menu should be updated.
  5313. ClickOnView(test_api.GetSelectFolderMenuItem(), event_generator);
  5314. EXPECT_TRUE(IsFolderSelectionDialogShown());
  5315. auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
  5316. const base::FilePath new_folder(
  5317. CreateCustomFolderInUserDownloadsPath("test1"));
  5318. dialog_factory->AcceptPath(new_folder);
  5319. WaitForSettingsMenuToBeRefreshed();
  5320. EXPECT_FALSE(IsFolderSelectionDialogShown());
  5321. EXPECT_EQ(custom_folder_view, test_api.GetCustomFolderOptionIfAny());
  5322. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kCustomFolder));
  5323. EXPECT_FALSE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
  5324. EXPECT_EQ(u"test1",
  5325. save_to_menu_group->GetOptionLabelForTesting(kCustomFolder));
  5326. // This should update the folder that will be used by the controller.
  5327. const auto capture_folder = controller->GetCurrentCaptureFolder();
  5328. EXPECT_EQ(capture_folder.path, new_folder);
  5329. EXPECT_FALSE(capture_folder.is_default_downloads_folder);
  5330. }
  5331. TEST_F(CaptureModeSettingsTest,
  5332. InitializeSettingsViewWithUnavailableCustomFolder) {
  5333. // Begin a new session with a pre-configured unavailable custom folder.
  5334. auto* controller = CaptureModeController::Get();
  5335. const base::FilePath default_folder =
  5336. controller->delegate_for_testing()->GetUserDefaultDownloadsFolder();
  5337. const base::FilePath custom_folder(FILE_PATH_LITERAL("/home/random"));
  5338. controller->SetCustomCaptureFolder(custom_folder);
  5339. StartImageRegionCapture();
  5340. // Open the settings menu and check there already exists an item for that
  5341. // pre-configured custom folder. Since the custom folder is unavailable, the
  5342. // item should be disabled and dimmed. The item of the default folder should
  5343. // be checked.
  5344. auto* event_generator = GetEventGenerator();
  5345. ClickOnView(GetSettingsButton(), event_generator);
  5346. WaitForSettingsMenuToBeRefreshed();
  5347. CaptureModeSettingsTestApi test_api;
  5348. EXPECT_TRUE(test_api.GetDefaultDownloadsOption());
  5349. auto* custom_folder_view = test_api.GetCustomFolderOptionIfAny();
  5350. EXPECT_TRUE(custom_folder_view);
  5351. CaptureModeMenuGroup* save_to_menu_group = test_api.GetSaveToMenuGroup();
  5352. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
  5353. EXPECT_FALSE(save_to_menu_group->IsOptionChecked(kCustomFolder));
  5354. EXPECT_FALSE(custom_folder_view->GetEnabled());
  5355. EXPECT_EQ(u"random",
  5356. save_to_menu_group->GetOptionLabelForTesting(kCustomFolder));
  5357. // Now open the folder selection dialog and select an available folder. The
  5358. // item of the custom folder should be checked and enabled.
  5359. ClickOnView(test_api.GetSelectFolderMenuItem(), event_generator);
  5360. EXPECT_TRUE(IsFolderSelectionDialogShown());
  5361. auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
  5362. const base::FilePath new_folder(
  5363. CreateCustomFolderInUserDownloadsPath("test"));
  5364. dialog_factory->AcceptPath(new_folder);
  5365. WaitForSettingsMenuToBeRefreshed();
  5366. EXPECT_EQ(custom_folder_view, test_api.GetCustomFolderOptionIfAny());
  5367. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kCustomFolder));
  5368. EXPECT_FALSE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
  5369. EXPECT_TRUE(custom_folder_view->GetEnabled());
  5370. EXPECT_EQ(u"test",
  5371. save_to_menu_group->GetOptionLabelForTesting(kCustomFolder));
  5372. }
  5373. TEST_F(CaptureModeSettingsTest, DeleteCustomFolderFromDialog) {
  5374. // Begin a new session with a pre-configured custom folder.
  5375. auto* controller = CaptureModeController::Get();
  5376. const base::FilePath custom_folder(
  5377. CreateCustomFolderInUserDownloadsPath("test"));
  5378. controller->SetCustomCaptureFolder(custom_folder);
  5379. StartImageRegionCapture();
  5380. // Open the settings menu and check there exists an item for that custom
  5381. // folder. And the item is checked to indicate the current folder in use to
  5382. // save the captured files is the custom folder.
  5383. auto* event_generator = GetEventGenerator();
  5384. ClickOnView(GetSettingsButton(), event_generator);
  5385. WaitForSettingsMenuToBeRefreshed();
  5386. CaptureModeSettingsTestApi test_api;
  5387. EXPECT_TRUE(test_api.GetDefaultDownloadsOption());
  5388. auto* custom_folder_view = test_api.GetCustomFolderOptionIfAny();
  5389. EXPECT_TRUE(custom_folder_view);
  5390. CaptureModeMenuGroup* save_to_menu_group = test_api.GetSaveToMenuGroup();
  5391. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kCustomFolder));
  5392. // Now open the folder selection dialog and delete the custom folder. Check
  5393. // the item on the settings menu for custom folder is still there but disabled
  5394. // and dimmed. The item of the default folder is checked now.
  5395. ClickOnView(test_api.GetSelectFolderMenuItem(), event_generator);
  5396. EXPECT_TRUE(IsFolderSelectionDialogShown());
  5397. auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
  5398. {
  5399. base::ScopedAllowBlockingForTesting allow_blocking;
  5400. const bool result = base::DeleteFile(custom_folder);
  5401. DCHECK(result);
  5402. }
  5403. dialog_factory->CancelDialog();
  5404. WaitForSettingsMenuToBeRefreshed();
  5405. EXPECT_TRUE(custom_folder_view);
  5406. EXPECT_FALSE(save_to_menu_group->IsOptionChecked(kCustomFolder));
  5407. EXPECT_FALSE(custom_folder_view->GetEnabled());
  5408. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
  5409. }
  5410. TEST_F(CaptureModeSettingsTest, AcceptDefaultDownloadsFolderFromDialog) {
  5411. // Begin a new session with a pre-configured custom folder.
  5412. auto* controller = CaptureModeController::Get();
  5413. controller->SetCustomCaptureFolder(
  5414. base::FilePath(FILE_PATH_LITERAL("/home/tests/foo")));
  5415. StartImageRegionCapture();
  5416. auto* event_generator = GetEventGenerator();
  5417. ClickOnView(GetSettingsButton(), event_generator);
  5418. WaitForSettingsMenuToBeRefreshed();
  5419. CaptureModeSettingsTestApi test_api;
  5420. ClickOnView(test_api.GetSelectFolderMenuItem(), event_generator);
  5421. // Selecting the same folder as the default downloads folder should result in
  5422. // removing the custom folder option from the menu.
  5423. auto* test_delegate = controller->delegate_for_testing();
  5424. const auto default_downloads_folder =
  5425. test_delegate->GetUserDefaultDownloadsFolder();
  5426. auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
  5427. dialog_factory->AcceptPath(default_downloads_folder);
  5428. EXPECT_FALSE(IsFolderSelectionDialogShown());
  5429. EXPECT_TRUE(test_api.GetDefaultDownloadsOption());
  5430. EXPECT_FALSE(test_api.GetCustomFolderOptionIfAny());
  5431. CaptureModeMenuGroup* save_to_menu_group = test_api.GetSaveToMenuGroup();
  5432. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
  5433. }
  5434. TEST_F(CaptureModeSettingsTest, SwitchWhichFolderToUserFromOptions) {
  5435. // Begin a new session with a pre-configured custom folder.
  5436. auto* controller = CaptureModeController::Get();
  5437. const base::FilePath custom_path(
  5438. (CreateCustomFolderInUserDownloadsPath("test")));
  5439. controller->SetCustomCaptureFolder(custom_path);
  5440. StartImageRegionCapture();
  5441. auto* event_generator = GetEventGenerator();
  5442. ClickOnView(GetSettingsButton(), event_generator);
  5443. WaitForSettingsMenuToBeRefreshed();
  5444. // Clicking the "Downloads" option will set it as the folder of choice, but
  5445. // won't clear the custom folder.
  5446. CaptureModeSettingsTestApi test_api;
  5447. ClickOnView(test_api.GetDefaultDownloadsOption(), event_generator);
  5448. CaptureModeMenuGroup* save_to_menu_group = test_api.GetSaveToMenuGroup();
  5449. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
  5450. EXPECT_FALSE(save_to_menu_group->IsOptionChecked(kCustomFolder));
  5451. const auto default_downloads_folder =
  5452. controller->delegate_for_testing()->GetUserDefaultDownloadsFolder();
  5453. auto capture_folder = controller->GetCurrentCaptureFolder();
  5454. EXPECT_EQ(capture_folder.path, default_downloads_folder);
  5455. EXPECT_TRUE(capture_folder.is_default_downloads_folder);
  5456. EXPECT_EQ(custom_path, controller->GetCustomCaptureFolder());
  5457. // Clicking on the custom folder option will switch back to using it.
  5458. ClickOnView(test_api.GetCustomFolderOptionIfAny(), event_generator);
  5459. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kCustomFolder));
  5460. EXPECT_FALSE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
  5461. capture_folder = controller->GetCurrentCaptureFolder();
  5462. EXPECT_EQ(capture_folder.path, custom_path);
  5463. EXPECT_FALSE(capture_folder.is_default_downloads_folder);
  5464. }
  5465. // Tests that when there's no overlap betwwen capture label widget and settings
  5466. // widget, capture label widget is shown/hidden correctly after open/close the
  5467. // folder selection window.
  5468. TEST_F(CaptureModeSettingsTest, CaptureLabelViewNotOverlapsWithSettingsView) {
  5469. // Update the display size to make sure capture label widget will not
  5470. // overlap with settings widget
  5471. UpdateDisplay("1200x1000");
  5472. auto* controller = StartImageRegionCapture();
  5473. auto* event_generator = GetEventGenerator();
  5474. // Tests that the capture label widget doesn't overlap with settings widget.
  5475. // Both capture label widget and settings widget are visible.
  5476. views::Widget* capture_label_widget = GetCaptureModeLabelWidget();
  5477. ClickOnView(GetSettingsButton(), event_generator);
  5478. views::Widget* settings_widget = GetCaptureModeSettingsWidget();
  5479. EXPECT_FALSE(capture_label_widget->GetWindowBoundsInScreen().Intersects(
  5480. settings_widget->GetWindowBoundsInScreen()));
  5481. EXPECT_TRUE(capture_label_widget->IsVisible());
  5482. EXPECT_TRUE(settings_widget->IsVisible());
  5483. // Open folder selection window, check that both capture label widget and
  5484. // settings widget are invisible.
  5485. CaptureModeSettingsTestApi test_api;
  5486. auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
  5487. ClickOnView(test_api.GetSelectFolderMenuItem(), event_generator);
  5488. EXPECT_TRUE(IsFolderSelectionDialogShown());
  5489. EXPECT_FALSE(capture_label_widget->IsVisible());
  5490. EXPECT_FALSE(settings_widget->IsVisible());
  5491. // Now close folder selection window, check that capture label widget and
  5492. // settings widget become visible.
  5493. dialog_factory->CancelDialog();
  5494. EXPECT_FALSE(IsFolderSelectionDialogShown());
  5495. EXPECT_TRUE(capture_label_widget->IsVisible());
  5496. EXPECT_EQ(capture_label_widget->GetLayer()->GetTargetOpacity(), 1.f);
  5497. EXPECT_TRUE(settings_widget->IsVisible());
  5498. // Close settings widget. Capture label widget is visible.
  5499. ClickOnView(GetSettingsButton(), event_generator);
  5500. EXPECT_TRUE(capture_label_widget->IsVisible());
  5501. controller->Stop();
  5502. }
  5503. // Tests that when capture label widget overlaps with settings widget, capture
  5504. // label widget is shown/hidden correctly after open/close the folder selection
  5505. // window, open/close settings menu. Regression test for
  5506. // https://crbug.com/1279606.
  5507. TEST_F(CaptureModeSettingsTest, CaptureLabelViewOverlapsWithSettingsView) {
  5508. // Update display size to make capture label widget overlap with settings
  5509. // widget.
  5510. UpdateDisplay("1100x700");
  5511. auto* controller = StartImageRegionCapture();
  5512. auto* event_generator = GetEventGenerator();
  5513. // Tests that capture label widget overlaps with settings widget and is
  5514. // hidden after setting widget is shown.
  5515. auto* capture_label_widget = GetCaptureModeLabelWidget();
  5516. ClickOnView(GetSettingsButton(), event_generator);
  5517. auto* settings_widget = GetCaptureModeSettingsWidget();
  5518. EXPECT_TRUE(capture_label_widget->GetWindowBoundsInScreen().Intersects(
  5519. settings_widget->GetWindowBoundsInScreen()));
  5520. EXPECT_FALSE(GetCaptureModeLabelWidget()->IsVisible());
  5521. EXPECT_TRUE(settings_widget->IsVisible());
  5522. // Open folder selection window, capture label widget is invisible.
  5523. CaptureModeSettingsTestApi test_api;
  5524. auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
  5525. ClickOnView(test_api.GetSelectFolderMenuItem(), event_generator);
  5526. EXPECT_TRUE(IsFolderSelectionDialogShown());
  5527. EXPECT_FALSE(capture_label_widget->IsVisible());
  5528. // Close folder selection window, capture label widget is invisible.
  5529. dialog_factory->CancelDialog();
  5530. EXPECT_FALSE(IsFolderSelectionDialogShown());
  5531. EXPECT_FALSE(capture_label_widget->IsVisible());
  5532. // Tests that capture label widget is visible after settings widget is
  5533. // closed.
  5534. ClickOnView(GetSettingsButton(), event_generator);
  5535. EXPECT_TRUE(capture_label_widget->IsVisible());
  5536. EXPECT_EQ(capture_label_widget->GetLayer()->GetTargetOpacity(), 1.f);
  5537. controller->Stop();
  5538. }
  5539. // Tests the basic keyboard navigation functions for the settings menu.
  5540. TEST_F(CaptureModeSettingsTest, KeyboardNavigationForSettingsMenu) {
  5541. auto* controller =
  5542. StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kImage);
  5543. using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
  5544. CaptureModeSessionTestApi session_test_api(
  5545. controller->capture_mode_session());
  5546. // Tab six times to focus the settings button.
  5547. auto* event_generator = GetEventGenerator();
  5548. SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/6);
  5549. EXPECT_EQ(FocusGroup::kSettingsClose,
  5550. session_test_api.GetCurrentFocusGroup());
  5551. EXPECT_EQ(0u, session_test_api.GetCurrentFocusIndex());
  5552. // Enter space to open the settings menu. The current focus group should be
  5553. // `kPendingSettings`.
  5554. SendKey(ui::VKEY_SPACE, event_generator);
  5555. ASSERT_TRUE(GetCaptureModeSettingsView());
  5556. EXPECT_EQ(FocusGroup::kPendingSettings,
  5557. session_test_api.GetCurrentFocusGroup());
  5558. CaptureModeSettingsTestApi settings_test_api;
  5559. CaptureModeMenuGroup* audio_input_menu_group =
  5560. settings_test_api.GetAudioInputMenuGroup();
  5561. // Tab once to focus the first item on the settings menu (`Audio input`
  5562. // header).
  5563. SendKey(ui::VKEY_TAB, event_generator);
  5564. EXPECT_EQ(FocusGroup::kSettingsMenu, session_test_api.GetCurrentFocusGroup());
  5565. EXPECT_EQ(0u, session_test_api.GetCurrentFocusIndex());
  5566. // Tab once to focus the `Off` option on the settings menu. Check `Off` option
  5567. // is the checked option not the `Microphone`.
  5568. SendKey(ui::VKEY_TAB, event_generator);
  5569. EXPECT_TRUE(audio_input_menu_group->IsOptionChecked(kAudioOff));
  5570. EXPECT_FALSE(audio_input_menu_group->IsOptionChecked(kAudioMicrophone));
  5571. // Now tab once to focus the `Microphone` option and enter space to select it.
  5572. // Check now `Microphone` option is the checked option not the `Off`.
  5573. SendKey(ui::VKEY_TAB, event_generator);
  5574. SendKey(ui::VKEY_SPACE, event_generator);
  5575. EXPECT_FALSE(audio_input_menu_group->IsOptionChecked(kAudioOff));
  5576. EXPECT_TRUE(audio_input_menu_group->IsOptionChecked(kAudioMicrophone));
  5577. // Tab three times to focus the `Select folder...` menu item and enter space
  5578. // to open the selection window.
  5579. SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/3);
  5580. SendKey(ui::VKEY_SPACE, event_generator);
  5581. auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
  5582. EXPECT_TRUE(IsFolderSelectionDialogShown());
  5583. // Close selection window.
  5584. dialog_factory->CancelDialog();
  5585. EXPECT_FALSE(IsFolderSelectionDialogShown());
  5586. // Now tab once to focus on the settings button and enter space on it to close
  5587. // the settings menu.
  5588. SendKey(ui::VKEY_TAB, event_generator);
  5589. EXPECT_EQ(FocusGroup::kSettingsClose,
  5590. session_test_api.GetCurrentFocusGroup());
  5591. EXPECT_EQ(0u, session_test_api.GetCurrentFocusIndex());
  5592. SendKey(ui::VKEY_SPACE, event_generator);
  5593. EXPECT_FALSE(GetCaptureModeSettingsView());
  5594. }
  5595. // Tests that the disabled option in the settings menu will be skipped while
  5596. // tabbing through.
  5597. TEST_F(CaptureModeSettingsTest,
  5598. KeyboardNavigationForSettingsMenuWithDisabledOption) {
  5599. // Begin a new session with a pre-configured unavailable custom folder.
  5600. auto* controller = CaptureModeController::Get();
  5601. const base::FilePath custom_folder(FILE_PATH_LITERAL("/home/random"));
  5602. controller->SetCustomCaptureFolder(custom_folder);
  5603. StartImageRegionCapture();
  5604. using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
  5605. CaptureModeSessionTestApi session_test_api(
  5606. controller->capture_mode_session());
  5607. // Tab six times to focus the settings button and enter space to open the
  5608. // setting menu.
  5609. auto* event_generator = GetEventGenerator();
  5610. SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/6);
  5611. SendKey(ui::VKEY_SPACE, event_generator);
  5612. EXPECT_EQ(FocusGroup::kPendingSettings,
  5613. session_test_api.GetCurrentFocusGroup());
  5614. CaptureModeSettingsView* settings_menu = GetCaptureModeSettingsView();
  5615. ASSERT_TRUE(settings_menu);
  5616. // Since the custom folder is unavailable, the `kCustomFolder` should be
  5617. // disabled and won't be returned via
  5618. // `CaptureModeSettingsViews::GetHighlightableItems`.
  5619. CaptureModeSettingsTestApi settings_test_api;
  5620. auto* custom_folder_view = settings_test_api.GetCustomFolderOptionIfAny();
  5621. ASSERT_TRUE(custom_folder_view);
  5622. EXPECT_FALSE(custom_folder_view->GetEnabled());
  5623. std::vector<CaptureModeSessionFocusCycler::HighlightableView*>
  5624. highlightable_items = settings_menu->GetHighlightableItems();
  5625. EXPECT_TRUE(
  5626. std::find_if(highlightable_items.begin(), highlightable_items.end(),
  5627. [custom_folder_view](
  5628. CaptureModeSessionFocusCycler::HighlightableView* item) {
  5629. return item->GetView() == custom_folder_view;
  5630. }) == highlightable_items.end());
  5631. // Tab five times to focus the default `Downloads` option.
  5632. SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/5);
  5633. EXPECT_EQ(session_test_api.GetCurrentFocusedView()->GetView(),
  5634. settings_test_api.GetDefaultDownloadsOption());
  5635. // Tab once to check the disabled `kCustomFolder` option is skipped and now
  5636. // the `Select folder...` menu item gets focused.
  5637. SendKey(ui::VKEY_TAB, event_generator);
  5638. EXPECT_EQ(session_test_api.GetCurrentFocusedView()->GetView(),
  5639. settings_test_api.GetSelectFolderMenuItem());
  5640. }
  5641. // Tests that selecting the default `Downloads` folder as the custom folder via
  5642. // keyboard navigation doesn't lead to a crash. Regression test for
  5643. // https://crbug.com/1269373.
  5644. TEST_F(CaptureModeSettingsTest,
  5645. KeyboardNavigationForRemovingCustomFolderOption) {
  5646. // Begin a new session with a pre-configured custom folder.
  5647. auto* controller = CaptureModeController::Get();
  5648. const base::FilePath custom_folder(
  5649. CreateCustomFolderInUserDownloadsPath("test"));
  5650. controller->SetCustomCaptureFolder(custom_folder);
  5651. StartImageRegionCapture();
  5652. using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
  5653. CaptureModeSessionTestApi test_api(controller->capture_mode_session());
  5654. // Tab six times to focus the settings button, then enter space to open the
  5655. // setting menu. Wait for the setting menu to be refreshed.
  5656. auto* event_generator = GetEventGenerator();
  5657. SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/6);
  5658. SendKey(ui::VKEY_SPACE, event_generator);
  5659. WaitForSettingsMenuToBeRefreshed();
  5660. EXPECT_EQ(FocusGroup::kPendingSettings, test_api.GetCurrentFocusGroup());
  5661. CaptureModeSettingsView* settings_menu = GetCaptureModeSettingsView();
  5662. ASSERT_TRUE(settings_menu);
  5663. // Tab seven times to focus the `Select folder...` menu item and enter space
  5664. // to open the selection window.
  5665. SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/7);
  5666. SendKey(ui::VKEY_SPACE, event_generator);
  5667. EXPECT_TRUE(IsFolderSelectionDialogShown());
  5668. // The current focus group is `FocusGroup::kSettingsMenu` and focus index is
  5669. // 6u.
  5670. EXPECT_EQ(FocusGroup::kSettingsMenu, test_api.GetCurrentFocusGroup());
  5671. EXPECT_EQ(6u, test_api.GetCurrentFocusIndex());
  5672. // Select the default `Downloads` folder as the custom folder which will
  5673. // have custom folder option get removed.
  5674. auto* test_delegate = controller->delegate_for_testing();
  5675. const auto default_downloads_folder =
  5676. test_delegate->GetUserDefaultDownloadsFolder();
  5677. auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
  5678. dialog_factory->AcceptPath(default_downloads_folder);
  5679. // Press space to ensure the selection window can be opened after the custom
  5680. // folder is removed from the settings menu.
  5681. SendKey(ui::VKEY_SPACE, event_generator);
  5682. EXPECT_TRUE(IsFolderSelectionDialogShown());
  5683. dialog_factory->CancelDialog();
  5684. // Tab once to make sure there's no crash and the focus gets moved to
  5685. // settings button.
  5686. SendKey(ui::VKEY_TAB, event_generator);
  5687. EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup());
  5688. EXPECT_EQ(0u, test_api.GetCurrentFocusIndex());
  5689. }
  5690. // Tests that first time selecting a custom folder via keyboard navigation.
  5691. // After the custom folder is selected, tabbing one more time will move focus
  5692. // from the settings menu to the settings button.
  5693. TEST_F(CaptureModeSettingsTest, KeyboardNavigationForAddingCustomFolderOption) {
  5694. auto* controller = CaptureModeController::Get();
  5695. StartImageRegionCapture();
  5696. using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
  5697. CaptureModeSessionTestApi session_test_api(
  5698. controller->capture_mode_session());
  5699. // Tab six times to focus the settings button, then enter space to open the
  5700. // setting menu.
  5701. auto* event_generator = GetEventGenerator();
  5702. SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/6);
  5703. SendKey(ui::VKEY_SPACE, event_generator);
  5704. EXPECT_EQ(FocusGroup::kPendingSettings,
  5705. session_test_api.GetCurrentFocusGroup());
  5706. CaptureModeSettingsView* settings_menu = GetCaptureModeSettingsView();
  5707. ASSERT_TRUE(settings_menu);
  5708. // Tab six times to focus the `Select folder...` menu item and enter space
  5709. // to open the selection window.
  5710. SendKey(ui::VKEY_TAB, event_generator, /*shift_down=*/false, /*count=*/6);
  5711. SendKey(ui::VKEY_SPACE, event_generator);
  5712. EXPECT_TRUE(IsFolderSelectionDialogShown());
  5713. // The current focus group is `FocusGroup::kSettingsMenu` and focus index is
  5714. // 5u.
  5715. EXPECT_EQ(FocusGroup::kSettingsMenu, session_test_api.GetCurrentFocusGroup());
  5716. EXPECT_EQ(5u, session_test_api.GetCurrentFocusIndex());
  5717. // Select the custom folder. Wait for the settings menu to be refreshed. The
  5718. // custom folder option should be added to the settings menu and checked.
  5719. const base::FilePath custom_folder(
  5720. CreateCustomFolderInUserDownloadsPath("test"));
  5721. controller->SetCustomCaptureFolder(custom_folder);
  5722. auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
  5723. dialog_factory->AcceptPath(custom_folder);
  5724. WaitForSettingsMenuToBeRefreshed();
  5725. CaptureModeSettingsTestApi settings_test_api;
  5726. EXPECT_TRUE(settings_test_api.GetCustomFolderOptionIfAny());
  5727. // Press space to ensure the selection window can be opened after the custom
  5728. // folder is added to the settings menu.
  5729. SendKey(ui::VKEY_SPACE, event_generator);
  5730. EXPECT_TRUE(IsFolderSelectionDialogShown());
  5731. dialog_factory->CancelDialog();
  5732. // Tab once to make sure the focus gets moved to settings button.
  5733. SendKey(ui::VKEY_TAB, event_generator);
  5734. EXPECT_EQ(FocusGroup::kSettingsClose,
  5735. session_test_api.GetCurrentFocusGroup());
  5736. EXPECT_EQ(0u, session_test_api.GetCurrentFocusIndex());
  5737. }
  5738. // -----------------------------------------------------------------------------
  5739. // CaptureModeHistogramTest:
  5740. // Test fixture to verify screen capture histograms depending on the test
  5741. // param (true for tablet mode, false for clamshell mode).
  5742. class CaptureModeHistogramTest : public CaptureModeSettingsTest,
  5743. public ::testing::WithParamInterface<bool> {
  5744. public:
  5745. CaptureModeHistogramTest() = default;
  5746. ~CaptureModeHistogramTest() override = default;
  5747. // CaptureModeSettingsTest:
  5748. void SetUp() override {
  5749. CaptureModeSettingsTest::SetUp();
  5750. if (GetParam())
  5751. SwitchToTabletMode();
  5752. }
  5753. void StartSessionForVideo() {
  5754. StartCaptureSession(CaptureModeSource::kFullscreen,
  5755. CaptureModeType::kVideo);
  5756. }
  5757. void StartRecording() { CaptureModeTestApi().PerformCapture(); }
  5758. void StopRecording() { CaptureModeTestApi().StopVideoRecording(); }
  5759. void OpenView(const views::View* view,
  5760. ui::test::EventGenerator* event_generator) {
  5761. if (GetParam())
  5762. TouchOnView(view, event_generator);
  5763. else
  5764. ClickOnView(view, event_generator);
  5765. }
  5766. };
  5767. TEST_P(CaptureModeHistogramTest, VideoRecordingAudioMetric) {
  5768. constexpr char kHistogramNameBase[] =
  5769. "Ash.CaptureModeController.CaptureAudioOnMetric";
  5770. base::HistogramTester histogram_tester;
  5771. histogram_tester.ExpectBucketCount(
  5772. GetCaptureModeHistogramName(kHistogramNameBase), false, 0);
  5773. histogram_tester.ExpectBucketCount(
  5774. GetCaptureModeHistogramName(kHistogramNameBase), true, 0);
  5775. // Perform a video recording with audio off. A false should be recorded.
  5776. StartSessionForVideo();
  5777. CaptureModeTestApi().SetAudioRecordingEnabled(false);
  5778. StartRecording();
  5779. histogram_tester.ExpectBucketCount(
  5780. GetCaptureModeHistogramName(kHistogramNameBase), false, 1);
  5781. histogram_tester.ExpectBucketCount(
  5782. GetCaptureModeHistogramName(kHistogramNameBase), true, 0);
  5783. StopRecording();
  5784. WaitForCaptureFileToBeSaved();
  5785. // Perform a video recording with audio on. A true should be recorded.
  5786. StartSessionForVideo();
  5787. CaptureModeTestApi().SetAudioRecordingEnabled(true);
  5788. StartRecording();
  5789. histogram_tester.ExpectBucketCount(
  5790. GetCaptureModeHistogramName(kHistogramNameBase), false, 1);
  5791. histogram_tester.ExpectBucketCount(
  5792. GetCaptureModeHistogramName(kHistogramNameBase), true, 1);
  5793. StopRecording();
  5794. }
  5795. TEST_P(CaptureModeHistogramTest, CaptureModeSwitchToDefaultReasonMetric) {
  5796. constexpr char kHistogramNameBase[] =
  5797. "Ash.CaptureModeController.SwitchToDefaultReason";
  5798. base::HistogramTester histogram_tester;
  5799. auto* controller = CaptureModeController::Get();
  5800. const auto downloads_folder =
  5801. controller->delegate_for_testing()->GetUserDefaultDownloadsFolder();
  5802. const base::FilePath non_available_custom_folder(
  5803. FILE_PATH_LITERAL("/home/test"));
  5804. const base::FilePath available_custom_folder =
  5805. CreateCustomFolderInUserDownloadsPath("test");
  5806. histogram_tester.ExpectBucketCount(
  5807. GetCaptureModeHistogramName(kHistogramNameBase),
  5808. CaptureModeSwitchToDefaultReason::kFolderUnavailable, 0);
  5809. histogram_tester.ExpectBucketCount(
  5810. GetCaptureModeHistogramName(kHistogramNameBase),
  5811. CaptureModeSwitchToDefaultReason::kUserSelectedFromFolderSelectionDialog,
  5812. 0);
  5813. histogram_tester.ExpectBucketCount(
  5814. GetCaptureModeHistogramName(kHistogramNameBase),
  5815. CaptureModeSwitchToDefaultReason::kUserSelectedFromSettingsMenu, 0);
  5816. StartImageRegionCapture();
  5817. // Set the custom folder to an unavailable folder the switch to default
  5818. // reason should be recorded as kFolderUnavailable.
  5819. controller->SetCustomCaptureFolder(non_available_custom_folder);
  5820. EXPECT_EQ(controller->GetCurrentCaptureFolder().path,
  5821. non_available_custom_folder);
  5822. auto* event_generator = GetEventGenerator();
  5823. OpenView(GetSettingsButton(), event_generator);
  5824. WaitForSettingsMenuToBeRefreshed();
  5825. CaptureModeSettingsTestApi test_api;
  5826. CaptureModeMenuGroup* save_to_menu_group = test_api.GetSaveToMenuGroup();
  5827. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
  5828. histogram_tester.ExpectBucketCount(
  5829. GetCaptureModeHistogramName(kHistogramNameBase),
  5830. CaptureModeSwitchToDefaultReason::kFolderUnavailable, 1);
  5831. // Select the save-to location to default downloads folder from folder
  5832. // selection dialog and the switch to default reason should be recorded as
  5833. // kUserSelectedFromSettingsMenu.
  5834. controller->SetCustomCaptureFolder(available_custom_folder);
  5835. EXPECT_EQ(controller->GetCurrentCaptureFolder().path,
  5836. available_custom_folder);
  5837. OpenView(test_api.GetSelectFolderMenuItem(), event_generator);
  5838. EXPECT_TRUE(IsFolderSelectionDialogShown());
  5839. auto* dialog_factory = FakeFolderSelectionDialogFactory::Get();
  5840. dialog_factory->AcceptPath(downloads_folder);
  5841. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
  5842. histogram_tester.ExpectBucketCount(
  5843. GetCaptureModeHistogramName(kHistogramNameBase),
  5844. CaptureModeSwitchToDefaultReason::kUserSelectedFromFolderSelectionDialog,
  5845. 1);
  5846. // Select the save-to location to default downloads folder from settings
  5847. // menu and the switch to default reason should be recorded as
  5848. // kUserSelectedFromFolderSelectionDialog.
  5849. controller->SetCustomCaptureFolder(available_custom_folder);
  5850. EXPECT_EQ(controller->GetCurrentCaptureFolder().path,
  5851. available_custom_folder);
  5852. OpenView(test_api.GetDefaultDownloadsOption(), event_generator);
  5853. EXPECT_TRUE(save_to_menu_group->IsOptionChecked(kDownloadsFolder));
  5854. histogram_tester.ExpectBucketCount(
  5855. GetCaptureModeHistogramName(kHistogramNameBase),
  5856. CaptureModeSwitchToDefaultReason::kUserSelectedFromSettingsMenu, 1);
  5857. }
  5858. INSTANTIATE_TEST_SUITE_P(All, CaptureModeHistogramTest, ::testing::Bool());
  5859. } // namespace ash