package Ġcom . mo yi . li u . audio feedback . domain Ċ Ċ import Ġandroidx . annotation . Visible ForTesting Ċ import Ġcom . mo yi . li u . audio feedback . adapter . audio . Audio Manager Ċ import Ġcom . mo yi . li u . audio feedback . adapter . transformer . Sensor Data Transformer Ċ import Ġcom . mo yi . li u . audio feedback . domain . model . Boundary Ċ import Ġcom . mo yi . li u . audio feedback . domain . model . Direction Ċ import Ġcom . mo yi . li u . audio feedback . domain . model . Power Accumulator Config Ċ import Ġcom . mo yi . li u . audio feedback . domain . power . AF Power Accumulator Ċ import Ġcom . mo yi . li u . audio feedback . domain . power . AF Power Store Ċ import Ġcom . mo yi . li u . audio feedback . domain . power . Power Accumulator Ċ import Ġcom . mo yi . li u . audio feedback . domain . power . Power Store Ċ import Ġcom . mo yi . li u . audio feedback . domain . sensor . Gravity Sensor Ċ import Ġcom . mo yi . li u . audio feedback . domain . use case . Calibration UseCase Ċ import Ġcom . mo yi . li u . audio feedback . utils . safe Dispose Ċ import Ġio . reactivex . rx java 3 . android . schedul ers . Android Schedulers Ċ import Ġio . reactivex . rx java 3 . core . Comp letable Ċ import Ġio . reactivex . rx java 3 . dis pos ables . Disposable Ċ import Ġio . reactivex . rx java 3 . schedul ers . Schedulers Ċ import Ġio . reactivex . rx java 3 . subjects . Publish Subject Ċ Ċ class ĠAudio Feedback Handler ( ĊĠĠĠ Ġprivate Ġval Ġsensor : ĠGr avity Sensor , ĊĠĠĠ Ġprivate Ġval Ġaudio Manager : ĠAudio Manager , ĊĠĠĠ Ġprivate Ġval Ġcalibration UseCase : ĠCal ibration UseCase Ċ ) Ġ{ ĊĊĠĠĠ Ġ@ Visible ForTesting ( otherwise Ġ= ĠVis ible ForTesting . PRIVATE ) ĊĠĠĠ Ġinternal Ġvar Ġdata Stream Disposable : ĠDis posable ? Ġ= Ġnull ĊĊĠĠĠ Ġ@ Visible ForTesting ( otherwise Ġ= ĠVis ible ForTesting . PRIVATE ) ĊĠĠĠ Ġinternal Ġvar Ġpower InputStream Disposable : ĠDis posable ? Ġ= Ġnull ĊĊĠĠĠ Ġ@ Visible ForTesting ( otherwise Ġ= ĠVis ible ForTesting . PRIVATE ) ĊĠĠĠ Ġinternal Ġvar Ġleft Char ged Indicator Stream Disposable : ĠDis posable ? Ġ= Ġnull ĊĊĠĠĠ Ġ@ Visible ForTesting ( otherwise Ġ= ĠVis ible ForTesting . PRIVATE ) ĊĠĠĠ Ġinternal Ġvar Ġright Char ged Indicator Stream Disposable : ĠDis posable ? Ġ= Ġnull ĊĊĠĠĠ Ġval Ġis Power Store Initial ised : ĠBoolean Ġget () Ġ= Ġthis ::_ power Store . isInitialized ĊĠĠĠ Ġval Ġis Data Transformer Initial ised : ĠBoolean Ġget () Ġ= Ġthis ::_ data Transformer . isInitialized ĊĊĠĠĠ Ġvar Ġpower Store : ĠPower Store ĊĠĠĠĠĠĠĠ Ġget () Ġ= Ġ_ power Store ĊĠĠĠĠĠĠĠ Ġset ( value ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( this ::_ power Store . isInitialized ) Ġthrow ĠIllegalStateException (" Power Store Ġis Ġinitial ised .") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ_ power Store Ġ= Ġvalue ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠ Ġvar Ġdata Transformer : ĠSensor Data Transformer ĊĠĠĠĠĠĠĠ Ġget () Ġ= Ġ_ data Transformer ĊĠĠĠĠĠĠĠ Ġset ( value ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( this ::_ data Transformer . isInitialized ) Ġthrow ĠIllegalStateException (" Power Store Ġis Ġinitial ised .") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ_ data Transformer Ġ= Ġvalue ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġ_ power Store : ĠPower Store ĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġ_ data Transformer : ĠSensor Data Transformer ĊĊĊĠĠĠ Ġprivate Ġval Ġpower InputStream Ġ= ĠPublish Subject . create < Pair < Direction , ĠFloat >>() ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠLoad Ġsound Ġfiles Ġinto Ġmemory Ġ( Sound Pool ) Ġand Ġinitialise Ġthe Ġsensor ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġsetup (): ĠComp letable Ġ= ĊĠĠĠĠĠĠĠ Ġaudio Manager . load Sound Tracks () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. merge With ( sensor . initial ise Sensor ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. subscribe On ( Android Schedulers . main Thread ()) ĊĊĠĠĠ Ġfun Ġcal ibrate (): ĠComp letable Ġ= ĊĠĠĠĠĠĠĠ Ġcalibration UseCase . start Calibration () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. do On Success Ġ{ Ġ( origin , ĠnumOf Data Points ) Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġpower Accumulator Config Ġ= ĠPower Accumulator Config ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġint ake PerSecond Ġ= ĠnumOf Data Points Ġ/ Ġcalibration UseCase . calibration Config . calibration Duration InSeconds , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ_ power Store Ġ= ĠAF Power Store ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġleft Power Accumulator Ġ= ĠAF Power Accumulator ( power Accumulator Config ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġright Power Accumulator Ġ= ĠAF Power Accumulator ( power Accumulator Config ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ_ data Transformer Ġ= ĠSensor Data Transformer ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfront Back Axis Origin Value Ġ= Ġorigin . x , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġleft Right Axis Origin Value Ġ= Ġorigin . z , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// TODO Ġcheck Ġangles ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfront Back Bound aries Ġ= ĠBound ary ( 1 4 f , Ġ 2 4 f ) Ġto ĠBound ary ( 1 0 f , Ġ 2 0 f ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġleft Right Bound aries Ġ= ĠBound ary ( 1 0 f , Ġ 3 0 f ) Ġto ĠBound ary ( 1 0 f , Ġ 3 0 f ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġaccumulator Config Ġ= Ġpower Accumulator Config ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. subscribe On ( Schedulers . io ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. ignore Element () ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠPrep Ġwork ĊĠĠĠĠ Ġ* Ġ- ĠRegister Ġthe Ġsensor Ġfor Ġreceiving Ġdata ĊĠĠĠĠ Ġ* Ġ- ĠSetup Ġpower Ġstream Ġto Ġallow Ġsending Ġpower Ġvalues Ġto Ġ[ Power Accumulator ] s ĊĠĠĠĠ Ġ* Ġ- ĠSetup Ġchar ged Ġindicator Ġstream Ġto Ġreceive Ġthe Ġpower Ġfully - char ged Ġsignal Ġfrom Ġ[ Power Accumulator ] s ĊĠĠĠĠ Ġ* Ġ- ĠStart Ġlooping Ġsome Ġtracks Ġsilently ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġstart (): ĠComp letable Ġ= Ġsensor . register () ĊĠĠĠĠĠĠĠ Ġ. do On Subscribe Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsubscribe Power Stream () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsubscribe Char ged Indicators () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġaudio Manager . start Loop ing Track sWith No Volume () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ. do On Complete (:: subscribe DataStream ) ĊĠĠĠĠĠĠĠ Ġ. do OnError Ġ{ Ġterminate () Ġ} ĊĠĠĠĠĠĠĠ Ġ. subscribe On ( Android Schedulers . main Thread ()) ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠCleanup Ġcached Ġresources Ġand Ġclose Ġstreams ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġterminate () Ġ{ ĊĠĠĠĠĠĠĠ Ġdata Stream Disposable . safe Dispose () ĊĠĠĠĠĠĠĠ Ġpower InputStream Disposable . safe Dispose () ĊĠĠĠĠĠĠĠ Ġleft Char ged Indicator Stream Disposable . safe Dispose () ĊĠĠĠĠĠĠĠ Ġright Char ged Indicator Stream Disposable . safe Dispose () ĊĠĠĠĠĠĠĠ Ġ_ power Store . shutdown () ĊĠĠĠĠĠĠĠ Ġaudio Manager . release All Tracks () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠSetup Ġsensor Ġdata Ġstream Ġto Ġreact Ġon Ġit Ġby Ġtransform ing Ġto Ġdomain Ġmodels ĊĠĠĠĠ Ġ* Ġand Ġindicate Ġ[ Power Store ] Ġand Ġupdate Ġ[ Audio Manager ] ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġsubscribe DataStream () Ġ{ ĊĠĠĠĠĠĠĠ Ġdata Stream Disposable . safe Dispose () ĊĠĠĠĠĠĠĠ Ġdata Stream Disposable Ġ= Ġsensor . sensor DataStream ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. observe On ( Schedulers . io ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġ( x , Ġ_, Ġz ) Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ_ data Transformer . run Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtransform For Front Back Tracks ( z ) Ġto Ġtransform For Left Right Tracks ( x ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. subscribe On ( Android Schedulers . main Thread ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. subscribe ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ{ Ġ( audio Contexts , Ġpower Context ) Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġaudio Manager . update Front Back Tracks ( audio Contexts ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġpower InputStream . onNext ( power Context ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}, Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ignore ĠError ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠSetup Ġpower Ġstream Ġand Ġprocess Ġthe Ġdata Ġon : ĊĠĠĠĠ Ġ* Ġ- ĠDirection Ġchange Ġ- Ġempty Ġopposite Ġdirection Ġ[ Power Accumulator ] ĊĠĠĠĠ Ġ* Ġ- ĠCharge Ġthe Ġ[ Power Accumulator ] Ġof Ġthe Ġreceived Ġdirection ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġsubscribe Power Stream () Ġ{ ĊĠĠĠĠĠĠĠ Ġpower InputStream Disposable . safe Dispose () ĊĠĠĠĠĠĠĠ Ġpower InputStream Disposable Ġ= Ġpower InputStream ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. observe On ( Schedulers . io ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. scan ( Pair ( Direction . LEFT , Ġ 0 f )) Ġ{ Ġpre , Ġnew Power Context Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġ( pre Direction , Ġ_) Ġ= Ġpre ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġ( new Direction , Ġ_) Ġ= Ġnew Power Context ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( pre Direction Ġ!= Ġnew Direction ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( new Direction ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠDirection . LEFT Ġ-> Ġ_ power Store . empty With ( Direction . RIGHT ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠDirection . RIGHT Ġ-> Ġ_ power Store . empty With ( Direction . LEFT ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnew Power Context ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. do On Subscribe Ġ{ Ġ_ power Store . activate () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. subscribe ({ Ġ( direction , Ġpower ) Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ_ power Store . charge With ( direction , Ġpower ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ}, Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ_ power Store . shutdown () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠSetup Ġchar ged Ġindicator Ġstreams Ġwhich Ġmake Ġ[ Audio Manager ] Ġto Ġplay Ġa Ġsignal Ġnote Ġonce Ġon Ġone Ġsignal Ġreceive ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġsubscribe Char ged Indicators () Ġ{ ĊĠĠĠĠĠĠĠ Ġleft Char ged Indicator Stream Disposable . safe Dispose () ĊĠĠĠĠĠĠĠ Ġright Char ged Indicator Stream Disposable . safe Dispose () ĊĠĠĠĠĠĠĠ Ġleft Char ged Indicator Stream Disposable Ġ= Ġ_ power Store . char ged Indicators [ 0 ] ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. observe On ( Android Schedulers . main Thread ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. subscribe ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġaudio Manager . update Left Right Tracks ( Direction . LEFT ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}, Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ignore Ġerror ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}) ĊĊĠĠĠĠĠĠĠ Ġright Char ged Indicator Stream Disposable Ġ= Ġ_ power Store . char ged Indicators [ 1 ] ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. observe On ( Android Schedulers . main Thread ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. subscribe ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ{ Ġaudio Manager . update Left Right Tracks ( Direction . RIGHT ) Ġ}, Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ignore Ġerror ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠ Ġ} Ċ }