// ĠCopyright Ġ 2 0 2 1 ĠGoogle ĠLLC Ċ // Ċ // Ġ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 Ġcom . google . android . libraries . car . trust agent . ble message stream Ċ Ċ import Ġandroid . annotation . Suppress Lint Ċ import Ġandroid . bluetooth . Bluetooth Device Ċ import Ġandroid . bluetooth . Bluetooth Socket Ċ import Ġandroid . content . Context Ċ import Ġandroidx . annotation . Visible ForTesting Ċ import Ġandroidx . core . content . Context Compat Ċ import Ġcom . google . android . libraries . car . trust agent . util . lo ge Ċ import Ġcom . google . android . libraries . car . trust agent . util . log i Ċ import Ġjava . io . ByteArray OutputStream Ċ import Ġjava . io . IOException Ċ import Ġjava . nio . ByteBuffer Ċ import Ġjava . nio . Byte Order Ċ import Ġjava . util . UUID Ċ import Ġjava . util . concurrent . Executor Ċ import Ġjava . util . concurrent . Executors Ċ Ċ /** Ċ Ġ* ĠHandles Ġreading Ġand Ġreceiving Ġdata Ġfrom Ġan ĠS pp Ġconnection . ĠWill Ġstart Ġnew Ġthread Ġto Ġhandle Ċ Ġ* Ġ[ Connect Task ] Ġand Ġ[ Read Message Task ]. Ċ Ġ* Ċ Ġ* Ġ@ property Ġservice Uuid ĠService Ġrecord ĠUUID Ġof Ġthe ĠRF COMM Ġsocket . Ċ Ġ*/ Ċ class ĠS pp Manager ( ĊĠ Ġcontext : ĠContext , ĊĠ Ġoverride Ġval Ġbluetooth Device : ĠBluetooth Device , ĊĠ Ġprivate Ġval Ġservice Uuid : ĠUUID Ċ ) Ġ: ĠBluetooth ConnectionManager () Ġ{ ĊĠ Ġinternal Ġvar Ġconnect Task : ĠConnect Task ? Ġ= Ġnull ĊĠ Ġ@ Visible ForTesting Ġinternal Ġvar Ġwrite Executor : ĠExecutor Ġ= ĠExec utors . new Single Thread Executor () ĊĠ Ġ@ Visible ForTesting Ġinternal Ġvar Ġread Message Task : ĠRead Message Task ? Ġ= Ġnull ĊĊĠ Ġprivate Ġval Ġconnection Executor Ġ= ĠExec utors . new Single Thread Executor () ĊĠ Ġprivate Ġval Ġtask Callback Executor Ġ= ĠContext Compat . get Main Executor ( context ) ĊĠ Ġprivate Ġvar Ġconnected Socket : ĠBluetooth Socket ? Ġ= Ġnull ĊĊĠ Ġ@ Suppress Lint (" Missing Permission ") ĊĠ Ġoverride Ġvar Ġdevice Name Ġ= Ġbluetooth Device . name ĊĠĠĠ Ġprivate Ġset ĊĊĠ Ġ@ Visible ForTesting ĊĠ Ġinternal Ġval Ġconnect Task Callback Ġ= ĊĠĠĠ Ġobject Ġ: ĠConnect Task . Callback Ġ{ ĊĠĠĠĠĠ Ġoverride Ġfun Ġon Connection Success ( socket : ĠBluetooth Socket ) Ġ{ ĊĠĠĠĠĠĠĠ Ġlog i ( TAG , Ġ" Connected , Ġremote Ġdevice Ġis Ġ${ bluetooth Device . address }") ĊĠĠĠĠĠĠĠ Ġconnected Socket Ġ= Ġsocket ĊĊĠĠĠĠĠĠĠ Ġread Message Task ?. cancel () ĊĠĠĠĠĠĠĠ Ġ// ĠStart Ġthe Ġtask Ġto Ġmanage Ġthe Ġconnection Ġand Ġperform Ġtrans missions ĊĠĠĠĠĠĠĠ Ġread Message Task Ġ= ĊĠĠĠĠĠĠĠĠĠ ĠRead Message Task ( socket . inputStream , Ġread Message Task Callback , Ġtask Callback Executor ) ĊĠĠĠĠĠĠĠ Ġconnection Executor . execute ( read Message Task ) ĊĠĠĠĠĠĠĠ Ġconnection Callbacks . forEach Ġ{ Ġit . on Connected () Ġ} ĊĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠ Ġoverride Ġfun Ġon Connection Attempt Failed () Ġ{ ĊĠĠĠĠĠĠĠ Ġconnection Callbacks . forEach Ġ{ Ġit . on Connection Failed () Ġ} ĊĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠ Ġ@ Visible ForTesting ĊĠ Ġinternal Ġval Ġread Message Task Callback Ġ= ĊĠĠĠ Ġobject Ġ: ĠRead Message Task . Callback Ġ{ ĊĠĠĠĠĠ Ġoverride Ġfun Ġon Message Received ( message : ĠByteArray ) Ġ{ ĊĠĠĠĠĠĠĠ Ġmessage Callbacks . forEach Ġ{ Ġit . on Message Received ( message ) Ġ} ĊĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠ Ġoverride Ġfun Ġon Message Read Error () Ġ{ ĊĠĠĠĠĠĠĠ Ġdisconnect () ĊĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠ Ġoverride Ġval Ġmax Write Size : ĠInt Ġ= ĠMAX _ WRITE _ SIZE ĊĊĠ Ġ/** ĠStart Ġthe Ġ[ Connect Task ] Ġto Ġinitiate Ġa Ġconnection Ġto Ġa Ġremote Ġdevice . Ġ*/ ĊĠ Ġoverride Ġfun Ġconnect () Ġ{ ĊĠĠĠ Ġ// ĠTODO ( b / 1 6 2 5 3 7 0 4 0 ): Ġadd Ġretry Ġlogic Ġfor ĠS PP ĊĠĠĠ Ġlog i ( TAG , Ġ" Attempt Ġconnect Ġto Ġremote Ġdevice .") ĊĠĠĠ Ġ// ĠCancel Ġany Ġthread Ġattempting Ġto Ġmake Ġa Ġconnection ĊĠĠĠ Ġconnect Task ?. cancel () ĊĊĠĠĠ Ġ// ĠStart Ġthe Ġtask Ġto Ġconnect Ġwith Ġthe Ġgiven Ġdevice ĊĠĠĠ Ġconnect Task Ġ= ĊĠĠĠĠĠ ĠConnect Task ( bluetooth Device , Ġtrue , Ġservice Uuid , Ġconnect Task Callback , Ġtask Callback Executor ) ĊĠĠĠ Ġconnection Executor . execute ( connect Task ) ĊĠ Ġ} ĊĊĠ Ġoverride Ġfun Ġdisconnect () Ġ{ ĊĠĠĠ Ġ// ĠCancel Ġthe Ġtask Ġthat Ġattempts Ġto Ġestablish Ġthe Ġconnection ĊĠĠĠ Ġconnect Task ?. cancel () ĊĠĠĠ Ġconnect Task Ġ= Ġnull ĊĊĠĠĠ Ġ// ĠCancel Ġany Ġtask Ġcurrently Ġrunning Ġa Ġconnection ĊĠĠĠ Ġread Message Task ?. cancel () ĊĠĠĠ Ġread Message Task Ġ= Ġnull ĊĊĠĠĠ Ġconnected Socket ?. close () ĊĠĠĠ Ġconnection Callbacks . forEach Ġ{ Ġit . on Disconnected () Ġ} ĊĠ Ġ} ĊĊĠ Ġ/** ĊĠĠ Ġ* ĠSends Ġ[ message ] Ġto Ġa Ġconnected Ġdevice . ĊĠĠ Ġ* ĊĠĠ Ġ* ĠThe Ġdelivery Ġof Ġdata Ġis Ġnotified Ġthrough Ġ[ Message Callback . on Message Sent ]. ĠThis Ġmethod Ġshould ĊĠĠ Ġ* Ġnot Ġbe Ġinvoked Ġagain Ġbefore Ġthe Ġcallback ; Ġotherwise Ġthe Ġbehavior Ġis Ġundefined . ĊĠĠ Ġ* ĊĠĠ Ġ* Ġ@ return Ġ` true ` Ġif Ġthe Ġrequest Ġto Ġsend Ġdata Ġwas Ġinitiated Ġsuccessfully ; Ġ` false ` Ġotherwise . ĊĠĠ Ġ*/ ĊĠ Ġoverride Ġfun ĠsendMessage ( message : ĠByteArray ): ĠBoolean Ġ{ ĊĠĠĠ Ġval Ġdata Ready ToSend Ġ= Ġwrap With Array Length ( message ) ĊĠĠĠ Ġif Ġ( connected Socket Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠ Ġlo ge ( TAG , Ġ" At tempted Ġto Ġsend Ġdata Ġwhen Ġdevice Ġis Ġdisconnected . ĠIgn oring .") ĊĠĠĠĠĠ Ġreturn Ġfalse ĊĠĠĠ Ġ} ĊĠĠĠ Ġwrite Executor . execute Ġ{ ĊĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠ Ġconnected Socket ?. output Stream ?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠ Ġit . write ( data Ready ToSend ) ĊĠĠĠĠĠĠĠĠĠ Ġlog i ( TAG , Ġ" Sent Ġmessage Ġto Ġremote Ġdevice Ġwith Ġlength : Ġ" Ġ+ Ġdata Ready ToSend . size ) ĊĠĠĠĠĠĠĠĠĠ Ġmessage Callbacks . forEach Ġ{ Ġit . on Message Sent ( message ) Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠ Ġlo ge ( TAG , Ġ" Exception Ġduring Ġwrite ", Ġe ) ĊĠĠĠĠĠĠĠ Ġdisconnect () ĊĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĠĠĠ Ġreturn Ġtrue ĊĠ Ġ} ĊĊĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠ Ġconst Ġval ĠLEN GTH _ BYTES _ SIZE Ġ= Ġ 4 ĊĊĠĠĠ Ġprivate Ġconst Ġval ĠTAG Ġ= Ġ" S pp Manager " ĊĠĠĠ Ġ// ĠTODO ( b / 1 6 6 5 3 8 3 7 3 ): ĠCurrently Ġits Ġan Ġarbitrary Ġnumber , Ġshould Ġupdate Ġafter Ġgetting Ġmore ĊĠĠĠ Ġ// Ġ Ġtesting Ġdata . ĊĠĠĠ Ġprivate Ġconst Ġval ĠMAX _ WRITE _ SIZE Ġ= Ġ 7 0 0 ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠWrap Ġthe Ġraw Ġbyte Ġarray Ġwith Ġarray Ġlength . ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* ĠShould Ġbe Ġcalled Ġevery Ġtime Ġwhen Ġserver Ġwants Ġto Ġsend Ġa Ġmessage Ġto Ġclient . ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* Ġ@ param Ġraw Data ĠOriginal Ġdata ĊĠĠĠĠ Ġ* Ġ@ return ĠThe Ġwrapped Ġdata ĊĠĠĠĠ Ġ* Ġ@ throws ĠIOException ĠIf Ġthere Ġare Ġsome Ġerrors Ġwriting Ġdata ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġ@ Visible ForTesting ĊĠĠĠ Ġinternal Ġfun Ġwrap With Array Length ( raw Data : ĠByteArray ): ĠByteArray Ġ{ ĊĠĠĠĠĠ Ġval Ġlength Ġ= Ġraw Data . size ĊĠĠĠĠĠ Ġval Ġlength Bytes Ġ= ĊĠĠĠĠĠĠĠ ĠByteBuffer . allocate ( LENGTH _ BYTES _ SIZE ). order ( Byte Order . LIT TLE _ ENDIAN ). put Int ( length ). array () ĊĠĠĠĠĠ Ġval ĠoutputStream Ġ= ĠByteArrayOutputStream () ĊĠĠĠĠĠ ĠoutputStream . write ( length Bytes Ġ+ Ġraw Data ) ĊĠĠĠĠĠ Ġreturn ĠoutputStream . toByteArray () ĊĠĠĠ Ġ} ĊĠ Ġ} Ċ } Ċ