package Ġcom . work day . tor que Ċ Ċ import Ġcom . go j uno . command er . os . Notification Ċ import Ġcom . work day . tor que . pool ing . Module Info Ċ import Ġcom . work day . tor que . pool ing . Test Chunk Ċ import Ġcom . work day . tor que . pool ing . Test Module Info Ċ import Ġio . reactivex . Comp letable Ċ import Ġio . reactivex . Observable Ċ import Ġkotlinx . coroutines . rx 2 . await Ċ import Ġjava . util . concurrent . TimeUnit Ċ Ċ class ĠInstall er ( private Ġval Ġa db Device : ĠA db Device , Ġprivate Ġval Ġprocess Runner : ĠProcess Runner Ġ= ĠProcess Runner ()) Ġ{ ĊĊĠĠĠ Ġsuspend Ġfun Ġensure Test Package Installed ( args : ĠArgs , Ġtest Chunk : ĠTest Chunk ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( is Chunk A pk Installed ( test Chunk )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġa db Device . log (" Package Ġinstalled , Ġpackage : Ġ${ test Chunk . test Module Info . module Info . apk Package . value }") ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinstall Module A pk s ( test Chunk . test Module Info , Ġargs ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġis Chunk A pk Installed ( test Chunk : ĠTest Chunk ) Ġ: ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġtest Package Ġ= Ġtest Chunk . test Module Info . module Info . apk Package . value ĊĠĠĠĠĠĠĠ Ġreturn Ġa db Device . installed Packages . contains ( test Package ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġsuspend Ġfun Ġinstall Module A pk s ( test Module Info : ĠTest Module Info , Ġargs : ĠArgs ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( args . uninstall A pk After Test ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġa db Device . installed Packages . forEach Ġ{ Ġmodule Package Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġuninstall Package ( module Package , Ġargs ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġinstall Package ( test Module Info . module Info , Ġargs ) ĊĠĠĠĠĠĠĠ Ġval Ġtarget Module Info Ġ= Ġtest Module Info . app Module Info ĊĠĠĠĠĠĠĠ Ġif Ġ( target Module Info Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinstall Package ( target Module Info , Ġargs ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġsuspend Ġfun Ġuninstall Package ( module Package : ĠString , Ġargs : ĠArgs ) Ġ{ ĊĠĠĠĠĠĠĠ Ġuninstall A pk ( module Package , Ġargs ). await () ĊĠĠĠĠĠĠĠ Ġa db Device . installed Packages . remove ( module Package ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġuninstall A pk ( module Package : ĠString , Ġargs : ĠArgs ): ĠComp letable Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġinstall Timeout Ġ= ĠTimeout ( args . install Timeout Seconds , ĠTimeUnit . SECONDS ) ĊĠĠĠĠĠĠĠ Ġvar Ġretry Count Ġ= Ġ 0 ĊĊĠĠĠĠĠĠĠ Ġreturn ĠObservable ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. from Callable Ġ{ ĠSystem . currentTimeMillis () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. flatMap Ġ{ ĠstartTime Millis Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġa db Un install A pk ( module Package , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstall Timeout ). map Ġ{ Ġit Ġto ĠstartTime Millis Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġ( exit Notification , ĠstartTime Millis ) Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsuccess Ġ= Ġexit Notification ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. preprocess Output () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Ġ{ Ġit . isNotEmpty () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. first OrNull Ġ{ Ġit . equals (" Success ", Ġignore Case Ġ= Ġtrue ) Ġ} Ġ!= Ġnull ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġduration Ġ= ĠSystem . currentTimeMillis () Ġ- ĠstartTime Millis ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( success ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtrue Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġa db Device . log (" Successfully Ġun installed Ġpackage Ġin Ġ${ duration . millis To Hours Minutes Seconds ()}, Ġmodule Package Ġ= Ġ$ module Package ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfalse Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIllegalStateException (" Package Ġuninstall Ġfailed ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. ignore Elements () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. do On Subscribe Ġ{ Ġa db Device . log (" Un installing Ġpackage ... Ġmodule Package Ġ= Ġ$ module Package ") Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. do OnError Ġ{ Ġa db Device . log (" Error Ġduring Ġuninstall ing Ġpackage : Ġ$ it , Ġmodule Package Ġ= Ġ$ module Package , Ġretry Ġcount : Ġ${ retry Count ++ }/${ args . retries Install Per A pk }") Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. retry ( args . retries Install Per A pk ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġa db Un install A pk ( module Package : ĠString , Ġinstall Timeout : ĠTimeout ): ĠObservable < Notification . Exit > Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġprocess Runner . run A db ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcommand And Args Ġ= ĠlistOf ("- s ", Ġa db Device . id , Ġ" uninstall ", Ġmodule Package ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtimeout Ġ= Ġinstall Timeout , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġun buffered Output Ġ= Ġtrue ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. of Type ( Notification . Exit :: class . java ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġsuspend Ġfun Ġinstall Package ( module Info : ĠModule Info , Ġargs : ĠArgs ) Ġ{ ĊĠĠĠĠĠĠĠ Ġinstall A pk ( module Info . path To A pk , Ġargs ). await () ĊĠĠĠĠĠĠĠ Ġa db Device . installed Packages . add ( module Info . apk Package . value ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġinstall A pk ( path To A pk : ĠString , Ġargs : ĠArgs ): ĠComp letable Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġinstall Timeout Ġ= ĠTimeout ( args . install Timeout Seconds , ĠTimeUnit . SECONDS ) ĊĠĠĠĠĠĠĠ Ġvar Ġretry Count Ġ= Ġ 0 ĊĠĠĠĠĠĠĠ Ġreturn ĠObservable ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. from Callable Ġ{ ĠSystem . currentTimeMillis () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. flatMap Ġ{ ĠstartTime Millis Ġ-> Ġa db Install A pk ( path To A pk , Ġinstall Timeout ). map Ġ{ Ġit Ġto ĠstartTime Millis Ġ} Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġ( exit Notification , ĠstartTime Millis ) Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsuccess Ġ= Ġexit Notification ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. preprocess Output () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Ġ{ Ġit . isNotEmpty () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. first OrNull Ġ{ Ġit . equals (" Success ", Ġignore Case Ġ= Ġtrue ) Ġ} Ġ!= Ġnull ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġduration Ġ= ĠSystem . currentTimeMillis () Ġ- ĠstartTime Millis ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( success ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtrue Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġa db Device . log (" Successfully Ġinstalled Ġapk Ġin Ġ${ duration . millis To Hours Minutes Seconds ()}, Ġpath To A pk Ġ= Ġ$ path To A pk ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfalse Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIllegalStateException (" A pk Ġinstall Ġfailed ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. ignore Elements () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. do On Subscribe Ġ{ Ġa db Device . log (" Installing Ġapk ... Ġpath To A pk Ġ= Ġ$ path To A pk ") Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. do OnError Ġ{ Ġa db Device . log (" Error Ġduring Ġinstalling Ġapk : Ġ$ it , Ġpath To A pk Ġ= Ġ$ path To A pk , Ġretry Ġcount : Ġ${ retry Count ++ }/${ args . retries Install Per A pk }") Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. retry ( args . retries Install Per A pk ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġa db Install A pk ( path To A pk : ĠString , Ġinstall Timeout : ĠTimeout ): ĠObservable < Notification . Exit > Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġprocess Runner . run A db ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcommand And Args Ġ= ĠlistOf ("- s ", Ġa db Device . id , Ġ" install ", Ġ"- r ", Ġ"- g ", Ġpath To A pk ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtimeout Ġ= Ġinstall Timeout , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġun buffered Output Ġ= Ġtrue ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. of Type ( Notification . Exit :: class . java ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠNotification . Exit . preprocess Output (): ĠList < String > Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġoutput ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. read Text () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. split ( System . line Separator ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġit . trim () Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ data Ġclass ĠTimeout ( val Ġnumber : ĠInt , Ġval Ġtime Unit : ĠTimeUnit ) Ġ{ ĊĠĠĠ Ġfun Ġto Pair () Ġ= Ġnumber Ġto Ġtime Unit Ċ } Ċ