@@ -30,24 +30,28 @@ import com.google.firebase.analytics.FirebaseAnalytics
3030import kotlinx.coroutines.CoroutineStart
3131import kotlinx.coroutines.Dispatchers
3232import kotlinx.coroutines.Job
33+ import kotlinx.coroutines.delay
3334import kotlinx.coroutines.flow.MutableSharedFlow
3435import kotlinx.coroutines.flow.SharedFlow
3536import kotlinx.coroutines.flow.StateFlow
3637import kotlinx.coroutines.launch
3738import kotlinx.coroutines.sync.Mutex
3839import kotlinx.coroutines.sync.withLock
40+ import kotlinx.coroutines.withContext
3941import org.radarbase.android.RadarApplication.Companion.radarApp
4042import org.radarbase.android.RadarApplication.Companion.radarConfig
4143import org.radarbase.android.RadarConfiguration.Companion.PROJECT_ID_KEY
4244import org.radarbase.android.RadarConfiguration.Companion.UI_REFRESH_RATE_KEY
4345import org.radarbase.android.RadarConfiguration.Companion.USER_ID_KEY
46+ import org.radarbase.android.RadarConfiguration.RemoteConfigStatus.INITIAL
4447import org.radarbase.android.RadarService.Companion.ACTION_CHECK_PERMISSIONS
4548import org.radarbase.android.RadarService.Companion.EXTRA_PERMISSIONS
4649import org.radarbase.android.auth.AppAuthState
4750import org.radarbase.android.auth.AuthService
4851import org.radarbase.android.auth.AuthServiceStateReactor
4952import org.radarbase.android.auth.LoginListener
5053import org.radarbase.android.auth.LoginManager
54+ import org.radarbase.android.config.SingleRadarConfiguration
5155import org.radarbase.android.util.BindState
5256import org.radarbase.android.util.BluetoothEnforcer
5357import org.radarbase.android.util.CoroutineTaskExecutor
@@ -57,10 +61,11 @@ import org.radarbase.android.util.PermissionBroadcast
5761import org.radarbase.android.util.PermissionHandler
5862import org.radarbase.kotlin.coroutines.launchJoin
5963import org.slf4j.LoggerFactory
64+ import java.io.File
6065import kotlin.time.Duration
6166import kotlin.time.Duration.Companion.milliseconds
6267
63- typealias RadarServiceStateReactor = (IRadarBinder ) -> Unit
68+ typealias RadarServiceStateReactor = suspend (IRadarBinder ) -> Unit
6469
6570/* * Base MainActivity class. It manages the services to collect the data and starts up a view. To
6671 * create an application, extend this class and override the abstract methods. */
@@ -109,6 +114,7 @@ abstract class MainActivity : AppCompatActivity(), LoginListener {
109114 get() = configuration.latestConfig.optString(PROJECT_ID_KEY )
110115
111116 private val mutexCreateView: Mutex = Mutex ()
117+ private var connectionBound: Boolean = false
112118
113119 private var radarConnectionJob: Job ? = null
114120 private var authConnectionJob: Job ? = null
@@ -191,6 +197,8 @@ abstract class MainActivity : AppCompatActivity(), LoginListener {
191197 logger.info(" RADAR configuration at create: {}" , configuration)
192198 onConfigChanged()
193199
200+ connectionBound = false
201+
194202 // Start the UI thread
195203 uiRefreshRate = configuration.latestConfig.getLong(UI_REFRESH_RATE_KEY , 250L )
196204
@@ -261,10 +269,14 @@ abstract class MainActivity : AppCompatActivity(), LoginListener {
261269
262270 with (lifecycleScope) {
263271 launch {
264- authConnection.bind()
265- }
266- launch {
267- radarConnection.bind()
272+ try {
273+ connectionBound = true
274+ authConnection.bind()
275+ radarConnection.bind()
276+ } catch (ex: Exception ) {
277+ connectionBound = false
278+ throw ex
279+ }
268280 }
269281 }
270282 permissionHandler.invalidateCache()
@@ -343,18 +355,20 @@ abstract class MainActivity : AppCompatActivity(), LoginListener {
343355
344356 @CallSuper
345357 public override fun onStop () {
346- super .onStop()
347-
348358 mainExecutor.stop { view = null }
349359
350- radarConnection.unbind()
351- authConnection.unbind()
360+ if (connectionBound) {
361+ connectionBound = false
362+ radarConnection.unbind()
363+ authConnection.unbind()
364+ }
352365 bluetoothEnforcer.stop()
353366
354367 radarConnectionJob?.cancel()
355368 authConnectionJob?.cancel()
356369 radarConnectionJob = null
357370 authConnectionJob = null
371+ super .onStop()
358372 }
359373
360374 override fun onRequestPermissionsResult (
@@ -373,22 +387,62 @@ abstract class MainActivity : AppCompatActivity(), LoginListener {
373387 * still valid.
374388 */
375389 protected suspend fun logout (disableRefresh : Boolean ) {
376- authConnection.applyBinder { invalidate(null , disableRefresh) }
390+ lifecycleScope.launch {
391+ authConnection.applyBinder { invalidate(null , disableRefresh) }
392+ }
377393 logger.debug(" Disabling Firebase Analytics" )
378394 FirebaseAnalytics .getInstance(this ).setAnalyticsCollectionEnabled(false )
379395 }
380396
381397 override fun loginSucceeded (manager : LoginManager ? , authState : AppAuthState ) = Unit
382398
383399 override suspend fun logoutSucceeded (manager : LoginManager ? , authState : AppAuthState ) {
400+ if (! connectionBound) {
401+ connectionBound = false
402+ radarConnection.unbind()
403+ authConnection.unbind()
404+ }
405+ clearAppData(this )
406+ delay(300 )
407+ logger.trace(" Configurations reset" )
384408 logger.info(" Starting SplashActivity" )
385- val intent = packageManager.getLaunchIntentForPackage(BuildConfig .LIBRARY_PACKAGE_NAME ) ? : return
409+ val applicationPackage = packageName
410+ val intent = packageManager.getLaunchIntentForPackage(applicationPackage) ? : return
411+ logger.debug(" Starting splash activity with intent {}" , intent)
386412 startActivity(intent.apply {
387413 flags = Intent .FLAG_ACTIVITY_NEW_TASK or Intent .FLAG_ACTIVITY_TASK_ON_HOME or Intent .FLAG_ACTIVITY_CLEAR_TOP or Intent .FLAG_ACTIVITY_SINGLE_TOP
388414 })
389415 finish()
390416 }
391417
418+ private fun clearAppData (context : Context ) {
419+ clearCache(context)
420+ clearFilesDir(context)
421+ }
422+
423+ private fun clearFilesDir (context : Context ) {
424+ val filesDir = context.filesDir
425+ deleteFilesInDirectory(filesDir)
426+ }
427+
428+ private fun clearCache (context : Context ) {
429+ val cacheDir = context.cacheDir
430+ deleteFilesInDirectory(cacheDir)
431+ }
432+
433+ private fun deleteFilesInDirectory (directory : File ) {
434+ if (directory.isDirectory) {
435+ val children = directory.listFiles()
436+ if (children != null ) {
437+ for (child in children) {
438+ if (child.absolutePath.toString().contains(" firebase" )) return
439+ deleteFilesInDirectory(child)
440+ }
441+ }
442+ }
443+ directory.delete()
444+ }
445+
392446 companion object {
393447 private val logger = LoggerFactory .getLogger(MainActivity ::class .java)
394448
0 commit comments