/* Ċ Ġ* Ġ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 . test . util Ċ Ċ import Ġandroidx . compose . ui . geometry . Offset Ċ import Ġandroidx . compose . ui . gesture . util . Velocity Tracker Ċ import Ġandroidx . compose . ui . input . pointer . Pointer Event Ċ import Ġandroidx . compose . ui . input . pointer . Pointer Event Pass Ċ import Ġandroidx . compose . ui . input . pointer . Pointer Id Ċ import Ġandroidx . compose . ui . input . pointer . Pointer Input Change Ċ import Ġandroidx . compose . ui . input . pointer . Pointer Input Filter Ċ import Ġandroidx . compose . ui . input . pointer . Pointer Input Modifier Ċ import Ġandroidx . compose . ui . unit . Int Size Ċ import Ġcom . google . common . truth . Truth . assertThat Ċ Ċ data Ġclass ĠData Point ( ĊĠĠĠ Ġval Ġid : ĠPointer Id , ĊĠĠĠ Ġval Ġtimestamp : ĠLong , ĊĠĠĠ Ġval Ġposition : ĠOffset , ĊĠĠĠ Ġval Ġdown : ĠBoolean Ċ ) Ġ{ ĊĠĠĠ Ġval Ġx Ġget () Ġ= Ġposition . x ĊĠĠĠ Ġval Ġy Ġget () Ġ= Ġposition . y Ċ } Ċ Ċ class ĠSingle Pointer Input Recorder Ġ: ĠPointer Input Modifier Ġ{ ĊĠĠĠ Ġprivate Ġval Ġ_ events Ġ= Ġmutable ListOf < DataPoint >() ĊĠĠĠ Ġval Ġevents Ġget () Ġ= Ġ_ events Ġas ĠList < DataPoint > ĊĊĠĠĠ Ġprivate Ġval Ġvelocity Tracker Ġ= ĠVe locity Tracker () ĊĠĠĠ Ġval Ġrecorded Velocity Ġget () Ġ= Ġvelocity Tracker . calculate Velocity () ĊĊĠĠĠ Ġoverride Ġval Ġpointer Input Filter Ġ= ĠRecord ing Filter Ġ{ Ġchanges Ġ-> ĊĠĠĠĠĠĠĠ Ġchanges . forEach Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ_ events . add ( DataPoint ( it . id , Ġit . uptime Millis , Ġit . position , Ġit . pressed )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvelocity Tracker . add Position ( it . uptime Millis , Ġit . position ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ class ĠMulti Pointer Input Recorder Ġ: ĠPointer Input Modifier Ġ{ ĊĠĠĠ Ġdata Ġclass ĠEvent ( val Ġpointers : ĠList < DataPoint >) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġpointer Count : ĠInt Ġget () Ġ= Ġpointers . size ĊĠĠĠĠĠĠĠ Ġfun Ġget Pointer ( index : ĠInt ) Ġ= Ġpointers [ index ] ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġval Ġ_ events Ġ= Ġmutable ListOf < Event >() ĊĠĠĠ Ġval Ġevents Ġget () Ġ= Ġ_ events Ġas ĠList < Event > ĊĊĠĠĠ Ġoverride Ġval Ġpointer Input Filter Ġ= ĠRecord ing Filter Ġ{ Ġchanges Ġ-> ĊĠĠĠĠĠĠĠ Ġ_ events . add ( ĊĠĠĠĠĠĠĠĠĠĠĠ ĠEvent ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġchanges . map Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠData Point ( it . id , Ġit . uptime Millis , Ġit . position , Ġit . pressed ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠ Ġ} Ċ } Ċ Ċ class ĠRecord ing Filter ( ĊĠĠĠ Ġprivate Ġval Ġrecord : Ġ( List < Pointer Input Change >) Ġ-> ĠUnit Ċ ) Ġ: ĠPointer Input Filter () Ġ{ ĊĠĠĠ Ġoverride Ġfun Ġon Pointer Event ( ĊĠĠĠĠĠĠĠ Ġpointer Event : ĠPointer Event , ĊĠĠĠĠĠĠĠ Ġpass : ĠPointer Event Pass , ĊĠĠĠĠĠĠĠ Ġbounds : ĠInt Size ĊĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( pass Ġ== ĠPointer Event Pass . Initial ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġrecord ( pointer Event . changes ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Cancel () Ġ{ ĊĠĠĠĠĠĠĠ Ġ// ĠDo Ġnothing ĊĠĠĠ Ġ} Ċ } Ċ Ċ val ĠSingle Pointer Input Recorder . down Events Ġget () Ġ= Ġevents . filter Ġ{ Ġit . down Ġ} Ċ Ċ val ĠSingle Pointer Input Recorder . re corded Duration Millis : ĠLong ĊĠĠĠ Ġget () Ġ{ ĊĠĠĠĠĠĠĠ Ġcheck ( events . isNotEmpty ()) Ġ{ Ġ" No Ġevents Ġrecorded " Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġevents . last (). timestamp Ġ- Ġevents . first (). timestamp ĊĠĠĠ Ġ} Ċ Ċ fun ĠSingle Pointer Input Recorder . assert Timestamp s Are In creasing () Ġ{ ĊĠĠĠ Ġcheck ( events . isNotEmpty ()) Ġ{ Ġ" No Ġevents Ġrecorded " Ġ} ĊĠĠĠ Ġevents . reduce Ġ{ Ġprev , Ġcurr Ġ-> ĊĠĠĠĠĠĠĠ ĠassertThat ( curr . timestamp ). is At Least ( prev . timestamp ) ĊĠĠĠĠĠĠĠ Ġcurr ĊĠĠĠ Ġ} Ċ } Ċ Ċ fun ĠMulti Pointer Input Recorder . assert Timestamp s Are In creasing () Ġ{ ĊĠĠĠ Ġcheck ( events . isNotEmpty ()) Ġ{ Ġ" No Ġevents Ġrecorded " Ġ} ĊĠĠĠ Ġ// ĠCheck Ġthat Ġeach Ġevent Ġhas Ġthe Ġsame Ġtimestamp ĊĠĠĠ Ġevents . forEach Ġ{ Ġevent Ġ-> ĊĠĠĠĠĠĠĠ ĠassertThat ( event . pointer Count ). is At Least ( 1 ) ĊĠĠĠĠĠĠĠ Ġval Ġcurr Time Ġ= Ġevent . pointers [ 0 ]. timestamp ĊĠĠĠĠĠĠĠ Ġfor Ġ( i Ġin Ġ 1 Ġuntil Ġevent . pointer Count ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertThat ( event . pointers [ i ]. timestamp ). isEqualTo ( curr Time ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĠĠĠ Ġ// ĠCheck Ġthat Ġthe Ġtimestamps Ġare Ġordered ĊĠĠĠ ĠassertThat ( events . map Ġ{ Ġit . pointers [ 0 ]. timestamp Ġ}). isIn Order () Ċ } Ċ Ċ fun ĠSingle Pointer Input Recorder . assert Only Last Event Is Up () Ġ{ ĊĠĠĠ Ġcheck ( events . isNotEmpty ()) Ġ{ Ġ" No Ġevents Ġrecorded " Ġ} ĊĠĠĠ ĠassertThat ( events . last (). down ). isFalse () ĊĠĠĠ ĠassertThat ( events . count Ġ{ Ġ! it . down Ġ}). isEqualTo ( 1 ) Ċ } Ċ Ċ fun ĠData Point . verify ( ĊĠĠĠ Ġexpected Timestamp : ĠLong ?, ĊĠĠĠ Ġexpected Id : ĠPointer Id ?, ĊĠĠĠ Ġexpected Down : ĠBoolean , ĊĠĠĠ Ġexpected Position : ĠOffset Ċ ) Ġ{ ĊĠĠĠ Ġif Ġ( expected Timestamp Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠ ĠassertThat ( timestamp ). isEqualTo ( expected Timestamp ) ĊĠĠĠ Ġ} ĊĠĠĠ Ġif Ġ( expected Id Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠ ĠassertThat ( id ). isEqualTo ( expected Id ) ĊĠĠĠ Ġ} ĊĠĠĠ ĠassertThat ( down ). isEqualTo ( expected Down ) ĊĠĠĠ ĠassertThat ( position ). isEqualTo ( expected Position ) Ċ } Ċ Ċ /** Ċ Ġ* ĠChecks Ġthat Ġthe Ġcoordinates Ġare Ġprogress ing Ġin Ġa Ġmon oton ous Ġdirection Ċ Ġ*/ Ċ fun ĠList < DataPoint >. is Mon otonic Between ( start : ĠOffset , Ġend : ĠOffset ) Ġ{ ĊĠĠĠ Ġmap Ġ{ Ġit . x Ġ}. is Mon otonic Between ( start . x , Ġend . x , Ġ 1 e - 3 f ) ĊĠĠĠ Ġmap Ġ{ Ġit . y Ġ}. is Mon otonic Between ( start . y , Ġend . y , Ġ 1 e - 3 f ) Ċ } Ċ