/* Ċ Ġ* ĠCopyright Ġ 2 0 1 9 ĠThe ĠAndroid ĠOpen ĠSource ĠProject Ċ Ġ* Ċ Ġ* ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); Ċ Ġ* Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . Ċ Ġ* ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat Ċ Ġ* Ċ Ġ* ĠĠĠĠĠ Ġhttp :// www . apache . org / licenses / LICENSE - 2 . 0 Ċ Ġ* Ċ Ġ* ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware Ċ Ġ* Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , Ċ Ġ* ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . Ċ Ġ* ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand Ċ Ġ* Ġlimitations Ġunder Ġthe ĠLicense . Ċ Ġ*/ Ċ Ċ package Ġandroidx . compose . ui . input . pointer Ċ Ċ import Ġandroid . content . Context Ċ import Ġandroid . view . Motion Event Ċ import Ġandroid . view . ViewGroup Ċ import Ġandroid . widget . Frame Layout Ċ import Ġandroidx . activity . Component Activity Ċ import Ġandroidx . compose . runtime . Composable Ċ import Ġandroidx . compose . runtime . Experimental Compose Api Ċ import Ġandroidx . compose . runtime . Re composer Ċ import Ġandroidx . compose . runtime . empty Content Ċ import Ġandroidx . compose . runtime . getValue Ċ import Ġandroidx . compose . runtime . mutable State Of Ċ import Ġandroidx . compose . runtime . remember Ċ import Ġandroidx . compose . runtime . setValue Ċ import Ġandroidx . compose . runtime . snapshots . Snapshot Ċ import Ġandroidx . test . filters . Small Test Ċ import Ġandroidx . compose . ui . geometry . Offset Ċ import Ġandroidx . compose . ui . unit . Int Size Ċ import Ġandroidx . compose . ui . unit . milliseconds Ċ import Ġandroidx . compose . ui . Layout Ċ import Ġandroidx . compose . ui . Modifier Ċ import Ġandroidx . compose . ui . composed Ċ import Ġandroidx . compose . ui . gesture . Pointer Coords Ċ import Ġandroidx . compose . ui . gesture . Pointer Properties Ċ import Ġandroidx . compose . ui . on Position ed Ċ import Ġandroidx . compose . ui . platform . Android Compose View Ċ import Ġandroidx . compose . ui . platform . Pointer Event Pass Ċ import Ġandroidx . compose . ui . platform . Pointer Input Change Ċ import Ġandroidx . compose . ui . platform . changed To Down Ċ import Ġandroidx . compose . ui . platform . consume Down Change Ċ import Ġandroidx . compose . ui . platform . consume Position Change Ċ import Ġandroidx . compose . ui . platform . position Change Ċ import Ġandroidx . compose . ui . platform . setContent Ċ import Ġandroidx . compose . ui . view interop . Android View Ċ import Ġcom . google . common . truth . Truth . assertThat Ċ import Ġcom . n ha ar man . mock it ok otlin 2 . any Ċ import Ġcom . n ha ar man . mock it ok otlin 2 . never Ċ import Ġcom . n ha ar man . mock it ok otlin 2 . spy Ċ import Ġcom . n ha ar man . mock it ok otlin 2 . verify Ċ import Ġorg . junit . Before Ċ import Ġorg . junit . Ignore Ċ import Ġorg . junit . Rule Ċ import Ġorg . junit . Test Ċ import Ġorg . junit . runner . RunWith Ċ import Ġorg . junit . runners . JUnit 4 Ċ import Ġjava . util . concurrent . Count DownLatch Ċ import Ġjava . util . concurrent . TimeUnit Ċ Ċ @ Small Test Ċ @ RunWith ( JUnit 4 :: class ) Ċ class ĠAndroid Pointer Input Test Ġ{ ĊĠĠĠ Ġ@ Suppress (" DE PREC ATION ") ĊĠĠĠ Ġ@ get : Rule ĊĠĠĠ Ġval Ġrule Ġ= Ġandroidx . test . rule . Activity Test Rule < Android Pointer Input Test Activity >( ĊĠĠĠĠĠĠĠ ĠAndroid Pointer Input Test Activity :: class . java ĊĠĠĠ Ġ) ĊĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġandroid Compose View : ĠAndroid Compose View ĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġcontainer : ĠViewGroup ĊĊĠĠĠ Ġ@ Before ĊĠĠĠ Ġfun Ġsetup () Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġactivity Ġ= Ġrule . activity ĊĠĠĠĠĠĠĠ Ġcontainer Ġ= Ġspy ( Frame Layout ( activity )). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlayout Params Ġ= ĠViewGroup . LayoutParams ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠViewGroup . LayoutParams . MATCH _ PARENT , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠViewGroup . LayoutParams . MATCH _ PARENT ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġrule . run On Ui Thread Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġactivity . set ContentView ( container ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġdispatch Touch Event _ no Pointer Input Modifiers _ returns False () Ġ{ ĊĊĠĠĠĠĠĠĠ Ġ// ĠArrange ĊĊĠĠĠĠĠĠĠ Ġcount Down Ġ{ Ġl atch Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġrule . run On Ui Thread Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontainer . setContent ( Re composer . current ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠFill Layout ( Modifier ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. on Position ed Ġ{ Ġl atch . count Down () Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġrule . run On Ui Thread Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġandroid Compose View Ġ= Ġcontainer . getChild At ( 0 ) Ġas ĠAndroid Compose View ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmotion Event Ġ= ĠMotion Event ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠMotion Event . ACTION _ DOWN , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 1 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠarrayOf ( Pointer Properties ( 0 )), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠarrayOf ( Pointer Coords ( 0 f , Ġ 0 f )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠAct ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġactual Ġ= Ġandroid Compose View . dispatch Touch Event ( motion Event ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠAssert ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertThat ( actual ). isFalse () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġdispatch Touch Event _ pointer Input Modifier _ returns True () Ġ{ ĊĊĠĠĠĠĠĠĠ Ġ// ĠArrange ĊĊĠĠĠĠĠĠĠ Ġcount Down Ġ{ Ġl atch Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġrule . run On Ui Thread Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontainer . setContent ( Re composer . current ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠFill Layout ( Modifier ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. consume Movement Gesture Filter () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. on Position ed Ġ{ Ġl atch . count Down () Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġrule . run On Ui Thread Ġ{ ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġandroid Compose View Ġ= Ġcontainer . getChild At ( 0 ) Ġas ĠAndroid Compose View ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlocation In Window Ġ= ĠInt Array ( 2 ). also Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġandroid Compose View . getLocation In Window ( it ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmotion Event Ġ= ĠMotion Event ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠMotion Event . ACTION _ DOWN , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 1 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠarrayOf ( Pointer Properties ( 0 )), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠarrayOf ( Pointer Coords ( location In Window [ 0 ]. toFloat (), Ġlocation In Window [ 1 ]. toFloat ())) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠAct ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġactual Ġ= Ġandroid Compose View . dispatch Touch Event ( motion Event ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠAssert ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertThat ( actual ). isTrue () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġdispatch Touch Event _ movement Not Cons umed _ request Dis allow Intercept Touch Event Not Called () Ġ{ ĊĠĠĠĠĠĠĠ Ġdispatch Touch Event _ movement Consumption In Compose ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġconsume Movement Ġ= Ġfalse , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcalls Request Dis allow Intercept Touch Event Ġ= Ġfalse ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġdispatch Touch Event _ movement Cons umed _ request Dis allow Intercept Touch Event Called () Ġ{ ĊĠĠĠĠĠĠĠ Ġdispatch Touch Event _ movement Consumption In Compose ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġconsume Movement Ġ= Ġtrue , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcalls Request Dis allow Intercept Touch Event Ġ= Ġtrue ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġdispatch Touch Event _ not Measured Layouts Are Measured First () Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġsize Ġ= Ġmutable State Of ( 1 0 ) ĊĠĠĠĠĠĠĠ Ġval Ġl atch Ġ= ĠCount DownLatch ( 1 ) ĊĠĠĠĠĠĠĠ Ġvar Ġconsumed Down Position : ĠOffset ? Ġ= Ġnull ĊĠĠĠĠĠĠĠ Ġrule . run On Ui Thread Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcontainer . setContent ( Re composer . current ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLayout ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ{}, ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠModifier ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. consume Down Gesture Filter Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġconsumed Down Position Ġ= Ġit ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. on Position ed Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġl atch . count Down () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) Ġ{ Ġ_, Ġ_ Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsize Px Ġ= Ġsize . value ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlayout ( size Px , Ġsize Px ) Ġ{} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ ĠassertThat ( latch . await ( 1 , ĠTimeUnit . SECONDS )). isTrue () ĊĊĠĠĠĠĠĠĠ Ġrule . run On Ui Thread Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġandroid Compose View Ġ= Ġcontainer . getChild At ( 0 ) Ġas ĠAndroid Compose View ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġwe Ġupdate Ġsize Ġfrom Ġ 1 0 Ġto Ġ 2 0 Ġpixels ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsize . value Ġ= Ġ 2 0 ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġthis Ġcall Ġwill Ġsynchronous ly Ġmark Ġthe ĠLayout Node Ġas Ġneeds Ġre measure ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ@ Opt In ( Experimental Compose Api :: class ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠSnapshot . send Apply Notifications () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġowner Position Ġ= Ġandroid Compose View . calculate Position () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmotion Event Ġ= ĠMotion Event ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠMotion Event . ACTION _ DOWN , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 1 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠarrayOf ( Pointer Properties ( 0 )), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠarrayOf ( Pointer Coords ( owner Position . x Ġ+ Ġ 1 5 f , Ġowner Position . y Ġ+ Ġ 1 5 f )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġwe Ġexpect Ġit Ġto Ġfirst Ġre measure Ġand Ġonly Ġthen Ġprocess ĊĠĠĠĠĠĠĠĠĠĠĠ Ġandroid Compose View . dispatch Touch Event ( motion Event ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertThat ( consumed Down Position ). isEqualTo ( Offset ( 1 5 f , Ġ 1 5 f )) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// ĠCurrently Ġignored Ġbecause Ġit Ġfails Ġwhen Ġrun Ġvia Ġcommand Ġline . Ġ ĠRuns Ġsuccessfully Ġin ĠAndroid ĊĠĠĠ Ġ// ĠStudio . ĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġ// ĠTODO ( b / 1 5 8 0 9 9 9 1 8 ): ĠFor Ġsome Ġreason , Ġthis Ġtest Ġfails Ġwhen Ġrun Ġfrom Ġcommand Ġline Ġbut Ġpasses ĊĠĠĠ Ġ// Ġ Ġwhen Ġrun Ġfrom ĠAndroid ĠStudio . Ġ ĠThis Ġseems Ġto Ġbe Ġcaused Ġby Ġb / 1 5 8 0 9 9 9 1 8 . Ġ ĠOnce Ġthat Ġis ĊĠĠĠ Ġ// Ġ Ġfixed , Ġ@ Ignore Ġcan Ġbe Ġremoved . ĊĠĠĠ Ġ@ Ignore ĊĠĠĠ Ġfun Ġdispatch Touch Event _ through Layers Of Android And Compose _ hits Child Pointer Input Filter () Ġ{ ĊĊĠĠĠĠĠĠĠ Ġ// ĠArrange ĊĊĠĠĠĠĠĠĠ Ġval Ġcontext Ġ= Ġrule . activity ĊĊĠĠĠĠĠĠĠ Ġval Ġlog Ġ= Ġmutable ListOf < List < Pointer Input Change >>() ĊĊĠĠĠĠĠĠĠ Ġcount Down Ġ{ Ġl atch Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġrule . run On Ui Thread Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontainer . setContent ( Re composer . current ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAndroid With Compose ( context , Ġ 1 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAndroid With Compose ( context , Ġ 1 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAndroid With Compose ( context , Ġ 1 0 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLayout ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ{}, ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠModifier ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. log Events Gesture Filter ( log ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. on Position ed Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġl atch . count Down () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) Ġ{ Ġ_, Ġ_ Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlayout ( 5 , Ġ 5 ) Ġ{} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġrule . run On Ui Thread Ġ{ ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġandroid Compose View Ġ= Ġcontainer . getChild At ( 0 ) Ġas ĠAndroid Compose View ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlocation In Window Ġ= ĠInt Array ( 2 ). also Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġandroid Compose View . getLocation In Window ( it ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmotion Event Ġ= ĠMotion Event ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠMotion Event . ACTION _ DOWN , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 1 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠarrayOf ( Pointer Properties ( 0 )), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠarrayOf ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠPointer Coords ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlocation In Window [ 0 ]. toFloat () Ġ+ Ġ 1 Ġ+ Ġ 1 0 Ġ+ Ġ 1 0 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlocation In Window [ 1 ]. toFloat () Ġ+ Ġ 1 Ġ+ Ġ 1 0 Ġ+ Ġ 1 0 0 ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠAct ĊĠĠĠĠĠĠĠĠĠĠĠ Ġandroid Compose View . dispatch Touch Event ( motion Event ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠAssert ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertThat ( log ). has Size ( 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertThat ( log [ 0 ]). isEqualTo ( listOf ( down ( 0 , Ġ 0 . milliseconds , Ġ 0 f , Ġ 0 f ))) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġdispatch Touch Event _ movement Consumption In Compose ( ĊĠĠĠĠĠĠĠ Ġconsume Movement : ĠBoolean , ĊĠĠĠĠĠĠĠ Ġcalls Request Dis allow Intercept Touch Event : ĠBoolean ĊĠĠĠ Ġ) Ġ{ ĊĊĠĠĠĠĠĠĠ Ġ// ĠArrange ĊĊĠĠĠĠĠĠĠ Ġcount Down Ġ{ Ġl atch Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġrule . run On Ui Thread Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontainer . setContent ( Re composer . current ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠFill Layout ( Modifier ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. consume Movement Gesture Filter ( consume Movement ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. on Position ed Ġ{ Ġl atch . count Down () Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġrule . run On Ui Thread Ġ{ ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġandroid Compose View Ġ= Ġcontainer . getChild At ( 0 ) Ġas ĠAndroid Compose View ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġ( x , Ġy ) Ġ= ĠInt Array ( 2 ). let Ġ{ Ġarray Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġandroid Compose View . getLocation In Window ( array ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġarray . map Ġ{ Ġitem Ġ-> Ġitem . toFloat () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdown Ġ= ĠMotion Event ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠMotion Event . ACTION _ DOWN , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 1 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠarrayOf ( Pointer Properties ( 0 )), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠarrayOf ( Pointer Coords ( x , Ġy )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmove Ġ= ĠMotion Event ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠMotion Event . ACTION _ MOVE , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 1 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠarrayOf ( Pointer Properties ( 0 )), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠarrayOf ( Pointer Coords ( x Ġ+ Ġ 1 , Ġy )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġandroid Compose View . dispatch Touch Event ( down ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠAct ĊĠĠĠĠĠĠĠĠĠĠĠ Ġandroid Compose View . dispatch Touch Event ( move ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠAssert ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( calls Request Dis allow Intercept Touch Event ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġverify ( container ). request Dis allow Intercept Touch Event ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġverify ( container , Ġnever ()). request Dis allow Intercept Touch Event ( any ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ @ Suppress (" Test FunctionName ") Ċ @ Composable Ċ fun ĠAndroid With Compose ( context : ĠContext , Ġandroid Padding : ĠInt , Ġchildren : Ġ@ Composable Ġ() Ġ-> ĠUnit ) Ġ{ ĊĠĠĠ Ġval Ġanother Layout Ġ= ĠFrame Layout ( context ). also Ġ{ Ġview Ġ-> ĊĠĠĠĠĠĠĠ Ġview . setContent ( Re composer . current ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġchildren () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġview . set Padding ( android Padding , Ġandroid Padding , Ġandroid Padding , Ġandroid Padding ) ĊĠĠĠ Ġ} ĊĠĠĠ ĠAndroid View ({ Ġanother Layout Ġ}) Ċ } Ċ Ċ fun ĠModifier . consume Movement Gesture Filter ( consume Movement : ĠBoolean Ġ= Ġfalse ): ĠModifier Ġ= Ġcomposed Ġ{ ĊĠĠĠ Ġval Ġfilter Ġ= Ġremember ( consume Movement ) Ġ{ ĠCons ume Movement Gesture Filter ( consume Movement ) Ġ} ĊĠĠĠ ĠPointer Input Modifier Impl ( filter ) Ċ } Ċ Ċ fun ĠModifier . consume Down Gesture Filter ( on Down : Ġ( Offset ) Ġ-> ĠUnit ): ĠModifier Ġ= Ġcomposed Ġ{ ĊĠĠĠ Ġval Ġfilter Ġ= Ġremember Ġ{ ĠCons ume Down Change Filter () Ġ} ĊĠĠĠ Ġfilter . on Down Ġ= Ġon Down ĊĠĠĠ Ġthis . then ( Pointer Input Modifier Impl ( filter )) Ċ } Ċ Ċ fun ĠModifier . log Events Gesture Filter ( log : ĠMutable List < List < Pointer Input Change >> ): ĠModifier Ġ= ĊĠĠĠ Ġcomposed Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġfilter Ġ= Ġremember Ġ{ ĠLog Events Gesture Filter ( log ) Ġ} ĊĠĠĠĠĠĠĠ Ġthis . then ( Pointer Input Modifier Impl ( filter )) ĊĠĠĠ Ġ} Ċ Ċ private Ġclass ĠPointer Input Modifier Impl ( override Ġval Ġpointer Input Filter : ĠPointer Input Filter ) Ġ: ĊĠĠĠ ĠPointer Input Modifier Ċ Ċ private Ġclass ĠCons ume Movement Gesture Filter ( val Ġconsume Movement : ĠBoolean ) Ġ: ĠPointer Input Filter () Ġ{ ĊĠĠĠ Ġoverride Ġfun Ġon Pointer Input ( ĊĠĠĠĠĠĠĠ Ġchanges : ĠList < Pointer Input Change >, ĊĠĠĠĠĠĠĠ Ġpass : ĠPointer Event Pass , ĊĠĠĠĠĠĠĠ Ġbounds : ĠInt Size ĊĠĠĠ Ġ) Ġ= ĊĠĠĠĠĠĠĠ Ġif Ġ( consume Movement ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġchanges . map Ġ{ Ġit . consume Position Change ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . position Change (). x , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . position Change (). y ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġchanges ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Cancel () Ġ{} Ċ } Ċ Ċ private Ġclass ĠCons ume Down Change Filter Ġ: ĠPointer Input Filter () Ġ{ ĊĠĠĠ Ġvar Ġon Down Ġby Ġmutable State Of <( Offset ) Ġ-> ĠUnit > ({}) ĊĠĠĠ Ġoverride Ġfun Ġon Pointer Input ( ĊĠĠĠĠĠĠĠ Ġchanges : ĠList < Pointer Input Change >, ĊĠĠĠĠĠĠĠ Ġpass : ĠPointer Event Pass , ĊĠĠĠĠĠĠĠ Ġbounds : ĠInt Size ĊĠĠĠ Ġ) Ġ= Ġchanges . map Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( it . changed To Down ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon Down ( it . current . position !! ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġit . consume Down Change () ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġit ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Cancel () Ġ{} Ċ } Ċ Ċ private Ġclass ĠLog Events Gesture Filter ( val Ġlog : ĠMutable List < List < Pointer Input Change >>) Ġ: ĊĠĠĠ ĠPointer Input Filter () Ġ{ ĊĊĠĠĠ Ġoverride Ġfun Ġon Pointer Input ( ĊĠĠĠĠĠĠĠ Ġchanges : ĠList < Pointer Input Change >, ĊĠĠĠĠĠĠĠ Ġpass : ĠPointer Event Pass , ĊĠĠĠĠĠĠĠ Ġbounds : ĠInt Size ĊĠĠĠ Ġ): ĠList < Pointer Input Change > Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( pass Ġ== ĠPointer Event Pass . Initial Down ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlog . add ( changes . map Ġ{ Ġit . copy () Ġ}) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġchanges ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Cancel () Ġ{} Ċ } Ċ Ċ @ Suppress (" Test FunctionName ") Ċ @ Composable Ċ private Ġfun ĠFill Layout ( modifier : ĠModifier Ġ= ĠModifier ) Ġ{ ĊĠĠĠ ĠLayout ( empty Content (), Ġmodifier ) Ġ{ Ġ_, Ġconstraints Ġ-> ĊĠĠĠĠĠĠĠ Ġlayout ( constraints . maxWidth , Ġconstraints . max Height ) Ġ{} ĊĠĠĠ Ġ} Ċ } Ċ Ċ private Ġfun Ġcount Down ( block : Ġ( Count DownLatch ) Ġ-> ĠUnit ) Ġ{ ĊĠĠĠ Ġval Ġcount DownLatch Ġ= ĠCount DownLatch ( 1 ) ĊĠĠĠ Ġblock ( count DownLatch ) ĊĠĠĠ ĠassertThat ( count DownLatch . await ( 1 , ĠTimeUnit . SECONDS )). isTrue () Ċ } Ċ Ċ class ĠAndroid Pointer Input Test Activity Ġ: ĠComponent Activity () Ċ Ċ @ Suppress (" Same Parameter Value ", Ġ" Test FunctionName ") Ċ private Ġfun ĠMotion Event ( ĊĠĠĠ Ġevent Time : ĠInt , ĊĠĠĠ Ġaction : ĠInt , ĊĠĠĠ Ġnum Pointers : ĠInt , ĊĠĠĠ Ġaction Index : ĠInt , ĊĠĠĠ Ġpointer Properties : ĠArray < Motion Event . Pointer Properties >, ĊĠĠĠ Ġpointer Coords : ĠArray < Motion Event . Pointer Coords > Ċ ) Ġ= ĠMotion Event . obtain ( ĊĠĠĠĠ 0 , ĊĠĠĠ Ġevent Time . to Long (), ĊĠĠĠ Ġaction Ġ+ Ġ( action Index Ġshl ĠMotion Event . ACTION _ POINTER _ INDEX _ SHIFT ), ĊĠĠĠ Ġnum Pointers , ĊĠĠĠ Ġpointer Properties , ĊĠĠĠ Ġpointer Coords , ĊĠĠĠĠ 0 , ĊĠĠĠĠ 0 , ĊĠĠĠĠ 0 f , ĊĠĠĠĠ 0 f , ĊĠĠĠĠ 0 , ĊĠĠĠĠ 0 , ĊĠĠĠĠ 0 , ĊĠĠĠĠ 0 Ċ )