package Ġcom . inf om ani ak . lib . login Ċ Ċ import Ġandroid . app . Activity Ċ import Ġandroid . content . Component Name Ċ import Ġandroid . content . Context Ċ import Ġandroid . content . Context . MODE _ PRIVATE Ċ import Ġandroid . content . Intent Ċ import Ġandroid . content . SharedPreferences Ċ import Ġandroid . content . pm . Resolve Info Ċ import Ġandroid . net . Uri Ċ import Ġandroid . util . Base 6 4 Ċ import Ġandroid . util . Log Ċ import Ġandroid . webkit . URL Util Ċ import Ġandroidx . browser . custom tabs . Custom Tabs Client Ċ import Ġandroidx . browser . custom tabs . Custom Tabs Intent Ċ import Ġandroidx . browser . custom tabs . Custom Tabs Service Connection Ċ import Ġandroidx . fragment . app . Fragment Ċ import Ġcom . google . gson . Gson Ċ import Ġcom . google . gson . Json Parser Ċ import Ġkotlinx . coroutines . Dispatch ers Ċ import Ġkotlinx . coroutines . with Context Ċ import Ġokhttp 3 . Multipart Body Ċ import Ġokhttp 3 . Ok HttpClient Ċ import Ġokhttp 3 . Request Ċ import Ġokhttp 3 . RequestBody Ċ import Ġjava . security . Message Digest Ċ import Ġjava . security . Secure Random Ċ Ċ /** Ċ Ġ* ĠClass Ġwhich Ġconsists Ġto Ġcreate Ġand Ġmanage Ġan Ġoauth Ġ 2 . 0 Ġconnection Ġthrough ĠInf om ani ak ĠProcess Ċ Ġ* ĠSupports ĠPK CE Ġchallenge Ġand Ġlegacy Ġbrowser Ċ Ġ*/ Ċ class ĠInf om ani ak Login ( ĊĠĠĠ Ġprivate Ġval Ġcontext : ĠContext , ĊĠĠĠ Ġprivate Ġvar Ġlogin Url : ĠString Ġ= ĠDEFAULT _ LOGIN _ URL , ĊĠĠĠ Ġprivate Ġval Ġclient ID : ĠString , ĊĠĠĠ Ġprivate Ġval Ġapp UID : ĠString Ċ ) Ġ{ ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠCH ROME _ ST ABLE _ PACKAGE Ġ= Ġ" com . android . chrome " ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠSERVICE _ ACTION Ġ= Ġ" android . support . custom tabs . action . Custom Tabs Service " ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠDEFAULT _ ACCESS _ TYPE Ġ= Ġ" offline " ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠDEFAULT _ HASH _ MODE Ġ= Ġ" SHA - 2 5 6 " ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠDEFAULT _ HASH _ MODE _ SHORT Ġ= Ġ" S 2 5 6 " ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠDEFAULT _ LOGIN _ URL Ġ= Ġ" https :// login . inf om ani ak . com /" ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠDEFAULT _ RE DIRECT _ URI Ġ= Ġ" :// oauth 2 redirect " ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠDEFAULT _ RESPONSE _ TYPE Ġ= Ġ" code " ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval Ġpreference Name Ġ= Ġ" pk ce _ step _ codes " ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval Ġverifier Key Ġ= Ġ" code _ verifier " ĊĊĠĠĠĠĠĠĠ Ġconst Ġval ĠLOGIN _ URL _ TAG Ġ= Ġ" login _ url " ĊĠĠĠĠĠĠĠ Ġconst Ġval ĠCODE _ TAG Ġ= Ġ" code " ĊĠĠĠĠĠĠĠ Ġconst Ġval ĠERROR _ TRANSL ATED _ TAG Ġ= Ġ" translated _ error " ĊĠĠĠĠĠĠĠ Ġconst Ġval ĠERROR _ CODE _ TAG Ġ= Ġ" error _ code " ĊĊĠĠĠĠĠĠĠ Ġconst Ġval ĠWEB VIEW _ ERROR _ CODE _ INTER NET _ DIS CONNECTED Ġ= Ġ" net :: ERR _ INTER NET _ DIS CONNECTED " ĊĠĠĠĠĠĠĠ Ġconst Ġval ĠWEB VIEW _ ERROR _ CODE _ CONNECTION _ REF USED Ġ= Ġ" net :: ERR _ CONNECTION _ REF USED " ĊĊĠĠĠĠĠĠĠ Ġconst Ġval ĠERROR _ ACCESS _ DEN IED Ġ= Ġ" access _ den ied " ĊĊĠĠĠĠĠĠĠ Ġconst Ġval ĠSSL _ ERROR _ CODE Ġ= Ġ" ssl _ error _ code " ĊĠĠĠĠĠĠĠ Ġconst Ġval ĠHTTP _ ERROR _ CODE Ġ= Ġ" http _ error _ code " ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġvar Ġtab Client : ĠCustom Tabs Client ? Ġ= Ġnull ĊĠĠĠ Ġprivate Ġvar Ġtab Connection : ĠCustom Tabs Service Connection ? Ġ= Ġnull ĊĠĠĠ Ġprivate Ġval Ġtab Intent : ĠCustom Tabs Intent Ġby Ġlazy Ġ{ ĊĠĠĠĠĠĠĠ ĠCustom Tabs Intent . Builder () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. run Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbuild () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ}. also Ġ{ Ġcustom Tab Intent Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcustom Tab Intent . intent . add Flags ( Intent . FLAG _ ACTIVITY _ SINGLE _ TOP ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠOffic ially Ġstart Ġthe ĠChrome ĠTab ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġstart (): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġcode Challenge Ġ= Ġgenerate Pk ce Codes () ĊĠĠĠĠĠĠĠ Ġval Ġurl Ġ= Ġgenerate Url ( code Challenge ) ĊĠĠĠĠĠĠĠ Ġvar Ġsuccess Ġ= Ġfalse ĊĠĠĠĠĠĠĠ Ġif Ġ( URL Util . isValid Url ( url )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis Chrome Custom Tabs Supported ( context ) Ġ-> Ġbind Custom Tabs Service ( url ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsuccess Ġ= Ġshow On Default Browser (( url )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġsuccess ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠStart ĠWebView Ġlogin ĊĠĠĠĠ Ġ* Ġ@ param Ġrequest Code Ġ: Ġactivity Ġfor Ġresult Ġrequest Ġcode ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġstart WebView Login ( request Code : ĠInt , Ġfragment : ĠFragment ? Ġ= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġcode Challenge Ġ= Ġgenerate Pk ce Codes () ĊĠĠĠĠĠĠĠ Ġval Ġurl Ġ= Ġgenerate Url ( code Challenge ) ĊĠĠĠĠĠĠĠ Ġval Ġintent Ġ= ĠIntent ( context , ĠWebView Login Activity :: class . java ). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġput Extra ( LOGIN _ URL _ TAG , Ġurl ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġput Extra ( WebView Login Activity . APPLICATION _ ID _ TAG , Ġapp UID ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ( fragment Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ( context Ġas ĠActivity ). startActivity For Result ( intent , Ġrequest Code ) ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfragment . startActivity For Result ( intent , Ġrequest Code ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġget Code Verifier (): ĠString Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġprefs : ĠSharedPreferences Ġ= Ġcontext . get SharedPreferences ( preference Name , ĠMODE _ PRIVATE ) ĊĠĠĠĠĠĠĠ Ġreturn Ġprefs . getString ( verifier Key , Ġ""). toString () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġget Redirect URI () Ġ= Ġ"$ app UID $ DEFAULT _ RE DIRECT _ URI " ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠU nb ind Ġthe Ġcustom Ġtab Ġ( close Ġthe Ġconnection ) ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġun bind () Ġ{ ĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . unbind Service ( tab Connection !! ) ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( ignore : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠLog . e (" k Login Ġerror ", Ġ" The Ġlogin Ġservice Ġcannot Ġbe Ġun bin ded ") ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠInstead Ġof ĠChrome ĠCustom ĠTab , Ġcreate Ġa Ġtab Ġin Ġthe Ġdefault Ġbrowser ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġshow On Default Browser ( url : ĠString ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġintent Ġ= ĠIntent ( Intent . ACTION _ VIEW ). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdata Ġ= ĠUri . parse ( url ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġadd Flags ( Intent . FLAG _ ACTIVITY _ SINGLE _ TOP ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġreturn Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . startActivity ( intent ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtrue ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠLog . e (" k Login Ġerror ", Ġ" Unable Ġto Ġstart ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfalse ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠBind Ġthe Ġcustom Ġtab Ġto Ġthe Ġcurrent Ġcontext Ġ( modern Ġmethod ) ĊĠĠĠĠ Ġ* Ġ@ url ĠString Ġ: ĠURL Ġof Ġthe Ġlogin Ġpage ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġbind Custom Tabs Service ( url : ĠString ) Ġ{ ĊĠĠĠĠĠĠĠ Ġtab Connection Ġ= Ġobject Ġ: ĠCustom Tabs Service Connection () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġon Custom Tabs Service Connected ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcomponent Name : ĠComponent Name , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġclient : ĠCustom Tabs Client ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtab Client Ġ= Ġclient ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlaunch Custom Tab ( url ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġon Service Disconnected ( name : ĠComponent Name ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtab Client Ġ= Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġun bind () ĊĠĠĠĠĠĠĠ ĠCustom Tabs Client . bind Custom Tabs Service ( context , ĠCH ROME _ ST ABLE _ PACKAGE , Ġtab Connection !! ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠLaunch Ġthe Ġcustom Ġtab Ġbased Ġon Ġan ĠURL Ġ( legacy Ġmethod ) ĊĠĠĠĠ Ġ* Ġ@ url ĠString Ġ: ĠURL Ġof Ġthe Ġlogin Ġpage ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġlaunch Custom Tab ( url : ĠString ) Ġ{ ĊĠĠĠĠĠĠĠ Ġtab Client ?. warm up ( 0 L ) ĊĠĠĠĠĠĠĠ Ġtab Intent . launch Url ( context , ĠUri . parse ( url )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠDetermine Ġif ĠCustom ĠChrome Ġtabs Ġare Ġsupported Ġon Ġthe Ġdevice ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġis Chrome Custom Tabs Supported ( context : ĠContext ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġservice Intent Ġ= ĠIntent ( SERVICE _ ACTION ). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġset Package ( CH ROME _ ST ABLE _ PACKAGE ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġval Ġresolve Infos : ĠMutable List < Resolve Info >? Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . package Manager . query Intent Services ( service Intent , Ġ 0 ) ĊĠĠĠĠĠĠĠ Ġreturn Ġ! resolve Infos . isNull OrEmpty () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠWill Ġgenerate Ġthe ĠPK CE Ġchallenge Ġcodes Ġfor Ġthis Ġobject ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġgenerate Pk ce Codes (): ĠString Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġcode Verifier Ġ= Ġgenerate Code Verifier () ĊĠĠĠĠĠĠĠ Ġval Ġcode Challenge Ġ= Ġgenerate Code Challenge ( code Verifier ) ĊĠĠĠĠĠĠĠ Ġval Ġeditor Ġ= Ġcontext . get SharedPreferences ( preference Name , ĠMODE _ PRIVATE ). edit () ĊĠĠĠĠĠĠĠ Ġeditor . putString ( verifier Key , Ġcode Verifier ) ĊĠĠĠĠĠĠĠ Ġeditor . apply () ĊĊĠĠĠĠĠĠĠ Ġreturn Ġcode Challenge ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠGenerate Ġthe Ġcomplete Ġlogin ĠURL Ġbased Ġon Ġparameters Ġand Ġbase ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġgenerate Url ( code Challenge : ĠString ): ĠString Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġlogin Url Ġ+ Ġ" authorize /" Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ"? response _ type =$ DEFAULT _ RESPONSE _ TYPE " Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ"& access _ type =$ DEFAULT _ ACCESS _ TYPE " Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ"& client _ id =$ client ID " Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ"& redirect _ uri =${ get Redirect URI () }" Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ"& code _ challenge _ method =$ DEFAULT _ HASH _ MODE _ SHORT " Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ"& code _ challenge =$ code Challenge " ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠGenerate Ġa Ġverifier Ġcode Ġfor ĠPK CE Ġchallenge Ġ( rfc 7 6 3 6 Ġ 4 . 1 .) ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġgenerate Code Verifier (): ĠString Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġsr Ġ= ĠSecure Random () ĊĠĠĠĠĠĠĠ Ġval Ġcode Ġ= ĠByteArray ( 3 3 ) ĊĠĠĠĠĠĠĠ Ġsr . next Bytes ( code ) ĊĠĠĠĠĠĠĠ Ġreturn ĠBase 6 4 . encode ToString ( code , ĠBase 6 4 . URL _ SAFE Ġor ĠBase 6 4 . NO _ WRAP Ġor ĠBase 6 4 . NO _ P ADDING ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠGenerate Ġa Ġchallenge Ġcode Ġfor ĠPK CE Ġchallenge Ġ( rfc 7 6 3 6 Ġ 4 . 2 .) ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġgenerate Code Challenge ( code Verifier : ĠString ): ĠString Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġbytes Ġ= Ġcode Verifier . toByteArray ( Charsets . US _ ASCII ) ĊĠĠĠĠĠĠĠ Ġval Ġmd Ġ= ĠMessage Digest . getInstance ( DEFAULT _ HASH _ MODE ) ĊĠĠĠĠĠĠĠ Ġmd . update ( bytes , Ġ 0 , Ġbytes . size ) ĊĠĠĠĠĠĠĠ Ġval Ġdigest Ġ= Ġmd . digest () ĊĠĠĠĠĠĠĠ Ġreturn ĠBase 6 4 . encode ToString ( digest , ĠBase 6 4 . URL _ SAFE Ġor ĠBase 6 4 . NO _ WRAP Ġor ĠBase 6 4 . NO _ P ADDING ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġcheck Response ( ĊĠĠĠĠĠĠĠ Ġintent : ĠIntent , ĊĠĠĠĠĠĠĠ ĠonSuccess : Ġ( code : ĠString ) Ġ-> ĠUnit , ĊĠĠĠĠĠĠĠ ĠonError : Ġ( error : ĠString ) Ġ-> ĠUnit ĊĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġdata Ġ= Ġintent . data ĊĠĠĠĠĠĠĠ Ġif Ġ( data Ġ!= Ġnull Ġ&& Ġapp UID Ġ== Ġdata . scheme ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġintent . data Ġ= Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcode Ġ= Ġdata . getQuery Parameter (" code ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġerror Ġ= Ġdata . getQuery Parameter (" error ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! code . isNull Or Blank ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠonSuccess ( code ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! error . isNull Or Blank ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġerror Title Ġ= Ġif Ġ( error Ġ== Ġ" access _ den ied ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . getString ( R . string . access _ den ied ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontext . getString ( R . string . an _ error _ has _ occ urred ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠonError ( error Title ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġenum Ġclass ĠError Status Ġ{ ĊĠĠĠĠĠĠĠ ĠSERVER , ĊĠĠĠĠĠĠĠ ĠAUTH , ĊĠĠĠĠĠĠĠ ĠCONNECTION , ĊĠĠĠĠĠĠĠ ĠUNKNOWN ; ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun ĠgetToken ( ĊĠĠĠĠĠĠĠ Ġok HttpClient : ĠOk HttpClient , ĊĠĠĠĠĠĠĠ Ġcode : ĠString , ĊĠĠĠĠĠĠĠ ĠonSuccess : Ġ( api Token : ĠApi Token ) Ġ-> ĠUnit , ĊĠĠĠĠĠĠĠ ĠonError : Ġ( error : ĠError Status ) Ġ-> ĠUnit ĊĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġform Builder : ĠMultip art Body . Builder Ġ= ĠMultip art Body . Builder () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setType ( Multipart Body . FORM ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. add FormData Part (" grant _ type ", Ġ" authorization _ code ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. add FormData Part (" client _ id ", Ġclient ID ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. add FormData Part (" code ", Ġcode ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. add FormData Part (" code _ verifier ", Ġget Code Verifier ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. add FormData Part (" redirect _ uri ", Ġget Redirect URI ()) ĊĊĠĠĠĠĠĠĠ ĠgetToken ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġok HttpClient Ġ= Ġok HttpClient , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġbody Ġ= Ġform Builder . build (), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠonSuccess Ġ= ĠonSuccess , ĊĠĠĠĠĠĠĠĠĠĠĠ ĠonError Ġ= ĠonError ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun ĠgetToken ( ĊĠĠĠĠĠĠĠ Ġok HttpClient : ĠOk HttpClient , ĊĠĠĠĠĠĠĠ Ġusername : ĠString , ĊĠĠĠĠĠĠĠ Ġpassword : ĠString , ĊĠĠĠĠĠĠĠ ĠonSuccess : Ġ( api Token : ĠApi Token ) Ġ-> ĠUnit , ĊĠĠĠĠĠĠĠ ĠonError : Ġ( error : ĠError Status ) Ġ-> ĠUnit ĊĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġform Builder : ĠMultip art Body . Builder Ġ= ĠMultip art Body . Builder () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. setType ( Multipart Body . FORM ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. add FormData Part (" grant _ type ", Ġ" password ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. add FormData Part (" access _ type ", ĠDEFAULT _ ACCESS _ TYPE ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. add FormData Part (" client _ id ", Ġclient ID ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. add FormData Part (" username ", Ġusername ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. add FormData Part (" password ", Ġpassword ) ĊĊĠĠĠĠĠĠĠ ĠgetToken ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġok HttpClient Ġ= Ġok HttpClient , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġbody Ġ= Ġform Builder . build (), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠonSuccess Ġ= ĠonSuccess , ĊĠĠĠĠĠĠĠĠĠĠĠ ĠonError Ġ= ĠonError ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġsuspend Ġfun ĠgetToken ( ĊĠĠĠĠĠĠĠ Ġok HttpClient : ĠOk HttpClient , ĊĠĠĠĠĠĠĠ Ġbody : ĠRequest Body , ĊĠĠĠĠĠĠĠ ĠonSuccess : Ġ( api Token : ĠApi Token ) Ġ-> ĠUnit , ĊĠĠĠĠĠĠĠ ĠonError : Ġ( error : ĠError Status ) Ġ-> ĠUnit ĊĠĠĠ Ġ) Ġ= Ġwith Context ( Dispatch ers . IO ) Ġ{ ĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġrequest Ġ= ĠRequest . Builder () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. url ("${ login Url } token ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. post ( body ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. build () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġresponse Ġ= Ġok HttpClient . new Call ( request ). execute () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġbody Response Ġ= Ġresponse . body ?. string () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġresponse . code Ġ>= Ġ 5 0 0 Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwith Context ( Dispatch ers . Main ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠonError ( Error Status . SERVER ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġresponse . code Ġ>= Ġ 4 0 0 Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwith Context ( Dispatch ers . Main ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠonError ( Error Status . AUTH ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbody Response . isNull Or Blank () Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwith Context ( Dispatch ers . Main ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠonError ( Error Status . CONNECTION ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwith Context ( Dispatch ers . Default ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġgson Ġ= ĠGson () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġjson Result Ġ= ĠJson Parser . parse String ( body Response ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġapi Token Ġ= Ġgson . fromJson ( json Result , ĠApi Token :: class . java ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠSet Ġthe Ġtoken Ġexpiration Ġdate Ġ( with Ġmargin - delay ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġapi Token . expires At Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠSystem . currentTimeMillis () Ġ+ Ġ(( api Token . expires In Ġ- Ġ 6 0 ) Ġ* Ġ 1 0 0 0 ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwith Context ( Dispatch ers . Main ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠonSuccess ( api Token ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( exception : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexception . printStackTrace () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdescription Error Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( exception . java Class . name . contains (" java . net .", Ġignore Case Ġ= Ġtrue ) Ġ|| ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexception . java Class . name . contains (" javax . net .", Ġignore Case Ġ= Ġtrue ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠError Status . CONNECTION ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠError Status . UNKNOWN ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwith Context ( Dispatch ers . Main ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠonError ( description Error ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ