/* Ċ Ġ* ĠCopyright Ġ 2 0 1 6 - 2 0 1 9 ĠJul ian e ĠLe hm ann Ġ< jl @ lamb das oup . com > Ċ Ġ* Ċ Ġ* Ġ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 . lamb das oup . quick fit . persist Ċ Ċ import Ġandroid . content . Content Resolver Ċ import Ġandroid . content . Content Values Ċ import Ġandroid . content . Context Ċ import Ġandroid . database . Cursor Ċ import Ġandroidx . concurrent . futures . Callback To Future Adapter Ċ import Ġandroidx . work . List enable Worker Ċ import Ġandroidx . work . Worker Parameters Ċ import Ġcom . google . android . gms . auth . api . signin . Google SignIn Ċ import Ġcom . google . android . gms . auth . api . signin . Google SignIn Account Ċ import Ġcom . google . android . gms . fitness . Fitness Ċ import Ġcom . google . android . gms . fitness . Fitness Options Ċ import Ġcom . google . android . gms . fitness . Sessions Client Ċ import Ġcom . google . android . gms . fitness . data .* Ċ import Ġcom . google . android . gms . fitness . request . Session Insert Request Ċ import Ġcom . google . android . gms . tasks . Success Continuation Ċ import Ġcom . google . android . gms . tasks . Task Ċ import Ġcom . google . android . gms . tasks . Tasks Ċ import Ġcom . google . common . util . concurrent . List enable Future Ċ import Ġcom . lamb das oup . quick fit . Constants . FITNESS _ API _ OPTIONS Ċ import Ġtim ber . log . Tim ber Ċ import Ġjava . util . concurrent . Executors Ċ import Ġjava . util . concurrent . TimeUnit Ċ Ċ private Ġval ĠSY NC _ EXECUT OR Ġ= ĠExec utors . new Single Thread Executor Ġ{ Ġr Ġ-> ĠThread ( r , Ġ" sync Ġworker Ġthread ") Ġ} Ċ private Ġval ĠSTATUS _ TRAN SM IT TED Ġ= ĠContent Values (). apply Ġ{ ĊĠĠĠ Ġput ( Quick Fit Contract . Session Entry . STATUS , ĠQuick Fit Contract . Session Entry . Session Status . SYNC ED . name ) Ċ } Ċ Ċ class ĠSync Worker ( private Ġval Ġapp Context : ĠContext , Ġworker Params : ĠWorker Parameters ) Ġ: ĠList enable Worker ( app Context , Ġworker Params ) Ġ{ ĊĊĠĠĠ Ġprivate Ġval Ġcontent Resolver : ĠContent Resolver Ġby Ġlazy Ġ{ Ġapp Context . content Resolver Ġ} ĊĊĠĠĠ Ġ// ĠExact ly Ġone Ġworker Ġgets Ġinstantiated Ġper Ġunit Ġof Ġwork , Ġso Ġwe Ġuse Ġthe Ġinstance Ġto Ġkeep Ġour Ġstate Ġaround . ĊĠĠĠ Ġ// ĠDoes Ġnot Ġapply Ġto Ġcursor , Ġbecause Ġthat Ġis Ġnullable ... ĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġsessions Client : ĠS essions Client ĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġcursor : ĠCursor ĊĠĠĠ Ġprivate Ġvar Ġhas Failed Insert ions Ġ= Ġfalse ĊĊĠĠĠ Ġoverride Ġfun Ġstart Work (): ĠList enable Future < Result > Ġ= ĠCallback To Future Adapter . get Future Ġ{ Ġcomp leter Ġ-> ĊĠĠĠĠĠĠĠ ĠTasks . call ( SYNC _ EXECUT OR , Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsessions Cursor Ġ= Ġcontent Resolver . query ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠQuick Fit Content Provider . get Uri Sessions List (), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠQuick Fit Contract . Session Entry . COLUMNS , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠQuick Fit Contract . Session Entry . STATUS Ġ+ Ġ"= ?", ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠarrayOf ( Quick Fit Contract . Session Entry . Session Status . NEW . name ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . d (" Found Ġ% s Ġsessions Ġto Ġsync ", Ġsessions Cursor ?. count Ġ?: Ġ" no ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsessions Cursor ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. on Success Task Ġ( SYNC _ EXECUT OR , Ġ{ Ġsessions Cursor Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( sessions Cursor Ġ== Ġnull Ġ|| Ġsessions Cursor . is After Last ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsessions Cursor ?. close () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠTasks . for Result ( null ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġaccount Ġ= ĠGoogle SignIn . get Account For Extension ( app Context , ĠFITNESS _ API _ OPTIONS ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! Google SignIn . has Permissions ( account , ĠFITNESS _ API _ OPTIONS )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . d (" Sign - in Ġrequired ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠFit Api Failure Resolution . request Fit Permissions ( app Context , Ġaccount ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġwill Ġbe Ġretried Ġafter Ġsign Ġin Ġresolution ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcomp leter . set ( Result . failure ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ on Success Task ĠTasks . for Canceled () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsessions Client Ġ= ĠF itness . getS essions Client ( app Context , Ġaccount ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcursor Ġ= Ġsessions Cursor ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinsert Next Session () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. add On Canceled Listener Ġ{ ĠTim ber . d (" work Ġgot Ġcancelled ") Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. add On Complete Listener ( SYNC _ EXECUT OR , Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcomp leter . set ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . exception . let Ġ{ Ġt Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( t Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġtask Ġis Ġsuccessful . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . d (" Sync Ġcomplete ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( has Failed Insert ions ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠResult . retry () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠResult . success () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcomp leter . set Exception ( t ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠResult . failure () Ġ// ĠTODO : Ġor Ġretry ? Ġdepend Ġon Ġexception ? Ġmight Ġneed Ġto Ġdo Ġthe Ġsign In Ġthing ? ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġinsert Next Session (): ĠTask < Void > Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! cursor . moveTo Next ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġdone Ġwith Ġsessions ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . d (" Done .") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcursor . close () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġsync Ġfinished ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠTasks . for Result ( null ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval ĠstartTime Ġ= Ġcursor . getLong ( cursor . getColumnIndex ( Quick Fit Contract . Session Entry . START _ TIME )) ĊĠĠĠĠĠĠĠ Ġval ĠendTime Ġ= Ġcursor . getLong ( cursor . getColumnIndex ( Quick Fit Contract . Session Entry . END _ TIME )) ĊĠĠĠĠĠĠĠ Ġval Ġsession Name Ġ= Ġcursor . getString ( cursor . getColumnIndex ( Quick Fit Contract . Session Entry . NAME )) ĊĠĠĠĠĠĠĠ Ġval Ġsession Builder Ġ= ĠSession . Builder () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Activity ( cursor . getString ( cursor . getColumnIndex ( Quick Fit Contract . Session Entry . ACTIVITY _ TYPE ))) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set StartTime ( startTime , ĠTimeUnit . MILLISECONDS ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set EndTime ( endTime , ĠTimeUnit . MILLISECONDS ) ĊĠĠĠĠĠĠĠ Ġif Ġ( session Name Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsession Builder . setName ( session Name ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġinsert Request Ġ= ĠSession Insert Request . Builder () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Session ( session Builder . build ()) ĊĊĠĠĠĠĠĠĠ Ġif Ġ( cursor . getType ( cursor . getColumnIndex ( Quick Fit Contract . Session Entry . CAL ORIES )) Ġ!= ĠCursor . FIELD _ TYPE _ NULL ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdatasource Ġ= ĠDataSource . Builder () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set App PackageName ( app Context ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set DataType ( DataType . AGG REG ATE _ CAL ORIES _ EXP ENDED ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. setType ( DataSource . TYPE _ RAW ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Device ( Device . getLocal Device ( app Context )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. build () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġinsert Request . add Aggregate DataPoint ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠData Point . builder ( datasource ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. setField ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠField . FIELD _ CAL ORIES , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcursor . getInt ( cursor . getColumnIndex ( Quick Fit Contract . Session Entry . CAL ORIES )). toFloat () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġremove Ġ 1 Ġms Ġfrom Ġend Ġtime , Ġso Ġthe Ġfit Ġapi Ġwill Ġaccept Ġthis Ġdata Ġpoint Ġas Ġnested Ġinside Ġthe Ġsession ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. setTime Interval ( startTime , ĠendTime Ġ- Ġ 1 , ĠTimeUnit . MILLISECONDS ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. build () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġreturn Ġsessions Client . insert Session ( insert Request . build ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. add On Success Listener ( SYNC _ EXECUT OR , Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontent Resolver . update ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠQuick Fit Content Provider . get Uri Sessions Id ( cursor . getLong ( cursor . getColumnIndex ( Quick Fit Contract . Session Entry ._ ID ))), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠSTATUS _ TRAN SM IT TED , Ġnull , Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . d (" insertion Ġsuccessful ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. add On Failure Listener ( SYNC _ EXECUT OR , Ġ{ Ġe Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . w ( e , Ġ" insertion Ġfailed ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhas Failed Insert ions Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. continue With Task ( SYNC _ EXECUT OR , Ġ{ Ġinsert Next Session () Ġ}) ĊĠĠĠ Ġ} Ċ } Ċ