Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Logout Functionality to the Application #458

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ publish_plugin_version=2.0.0
versions_plugin_version=0.51.0

radar_commons_version=0.15.0
radar_schemas_commons_version=0.8.10-SNAPSHOT
radar_schemas_commons_version=0.8.10

radar_faros_sdk_version=0.1.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ class ApplicationStatusManager(
cacheReceiver?.unregister()
serverRecordsReceiver?.unregister()
serverStatusReceiver?.unregister()
tzProcessor?.close()
}

private fun processTimeZone() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ class OAuth2LoginManager(

override fun loginFailed(manager: LoginManager?, ex: Exception?) = this.service.loginFailed(this, ex)

override fun loggedOut(manager: LoginManager?, authState: AppAuthState) = Unit

companion object {
private const val OAUTH2_SOURCE_TYPE = "org.radarcns.android.auth.oauth2.OAuth2LoginManager"
private val OAUTH2_SOURCE_TYPES = listOf(OAUTH2_SOURCE_TYPE)
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,17 @@ import org.radarbase.android.RadarConfiguration.Companion.USER_ID_KEY
import org.radarbase.android.RadarService.Companion.ACTION_CHECK_PERMISSIONS
import org.radarbase.android.RadarService.Companion.ACTION_PROVIDERS_UPDATED
import org.radarbase.android.RadarService.Companion.EXTRA_PERMISSIONS
import org.radarbase.android.auth.AuthService
import org.radarbase.android.config.CombinedRadarConfig
import org.radarbase.android.auth.AppAuthState
import org.radarbase.android.auth.AuthServiceConnection
import org.radarbase.android.auth.LoginListener
import org.radarbase.android.auth.LoginManager
import org.radarbase.android.util.*
import org.slf4j.LoggerFactory
import java.io.File

/** Base MainActivity class. It manages the services to collect the data and starts up a view. To
* create an application, extend this class and override the abstract methods. */
abstract class MainActivity : AppCompatActivity() {
abstract class MainActivity : AppCompatActivity(), LoginListener {

/** Time between refreshes. */
private var uiRefreshRate: Long = 0
Expand All @@ -56,13 +59,14 @@ abstract class MainActivity : AppCompatActivity() {

private var configurationBroadcastReceiver: BroadcastRegistration? = null
private lateinit var permissionHandler: PermissionHandler
protected lateinit var authConnection: ManagedServiceConnection<AuthService.AuthServiceBinder>
protected lateinit var authConnection: AuthServiceConnection
protected lateinit var radarConnection: ManagedServiceConnection<IRadarBinder>

private lateinit var bluetoothEnforcer: BluetoothEnforcer

protected lateinit var configuration: RadarConfiguration
private var connectionsUpdatedReceiver: BroadcastRegistration? = null
private lateinit var broadcaster: LocalBroadcastManager

protected open val requestPermissionTimeoutMs: Long
get() = REQUEST_PERMISSION_TIMEOUT_MS
Expand Down Expand Up @@ -98,8 +102,9 @@ abstract class MainActivity : AppCompatActivity() {
onUnboundListeners += IRadarBinder::stopScanning
}

broadcaster = LocalBroadcastManager.getInstance(this)
bluetoothEnforcer = BluetoothEnforcer(this, radarConnection)
authConnection = ManagedServiceConnection(this, radarApp.authService)
authConnection = AuthServiceConnection(this, this)
create()
}

Expand Down Expand Up @@ -148,6 +153,14 @@ abstract class MainActivity : AppCompatActivity() {
}
}

override fun loginSucceeded(manager: LoginManager?, authState: AppAuthState) = Unit

override fun loginFailed(manager: LoginManager?, ex: Exception?) = Unit

override fun loggedOut(manager: LoginManager?, authState: AppAuthState) {

}

override fun onPause() {
super.onPause()
uiUpdater?.let {
Expand Down Expand Up @@ -226,11 +239,54 @@ abstract class MainActivity : AppCompatActivity() {
* still valid.
*/
protected fun logout(disableRefresh: Boolean) {
radarConnection.unbind()
authConnection.applyBinder { invalidate(null, disableRefresh) }
radarConfig.reset()
clearConfigSharedPrefs()
clearAppData(this)
logger.debug("Disabling Firebase Analytics")
FirebaseAnalytics.getInstance(this).setAnalyticsCollectionEnabled(false)
radarConfig.resetStatus()
// Start Launcher Activity in overriding method
}

private fun clearConfigSharedPrefs() {
val sharedPreferences = getSharedPreferences("org.radarbase.android.config.LocalConfiguration", Context.MODE_PRIVATE)
sharedPreferences.all.forEach { (key, value) ->
}
sharedPreferences.edit().clear().apply()
}

private fun clearAppData(context: Context) {
clearCache(context)
clearFilesDir(context)
}

private fun clearFilesDir(context: Context) {
val filesDir = context.filesDir
deleteFilesInDirectory(filesDir)
}

private fun clearCache(context: Context) {
val cacheDir = context.cacheDir
deleteFilesInDirectory(cacheDir)
}

private fun deleteFilesInDirectory(directory: File) {
if (directory.isDirectory) {
val children = directory.listFiles()
if (children != null) {
for (child in children) {
if (child.absolutePath.toString().contains("firebase")) return
deleteFilesInDirectory(child)
}
}
}
directory.delete()
}



companion object {
private val logger = LoggerFactory.getLogger(MainActivity::class.java)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ interface RadarConfiguration {
*/
fun reset(vararg keys: String)

fun resetStatus()

/**
* Fetch the remote configuration from server if it is outdated.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import android.Manifest.permission.*
import android.app.Notification
import android.app.PendingIntent
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.PackageManager.PERMISSION_GRANTED
Expand Down Expand Up @@ -243,13 +242,16 @@ abstract class RadarService : LifecycleService(), ServerStatusListener, LoginLis
it.close()
sourceRegistrar = null
}
(dataHandler as? TableDataHandler)?.close()
dataHandler = null
}
authConnection.unbind()

mConnections.asSequence()
.filter(SourceProvider<*>::isBound)
.forEach(SourceProvider<*>::unbind)

logger.info("Destroying RADAR Service")
super.onDestroy()
}

Expand Down Expand Up @@ -528,6 +530,19 @@ abstract class RadarService : LifecycleService(), ServerStatusListener, LoginLis
}
}

override fun loggedOut(manager: LoginManager?, authState: AppAuthState) {
mHandler.execute {
updateProviders(authState, configuration.latestConfig)
val oldProviders = mConnections
removeProviders(mConnections.toSet())
oldProviders.forEach {
it.stopService()
}
stopForeground(STOP_FOREGROUND_REMOVE)
stopSelf()
}
}

private fun removeProviders(sourceProviders: Set<SourceProvider<*>>) {
if (sourceProviders.isEmpty()) {
return
Expand Down Expand Up @@ -680,6 +695,7 @@ abstract class RadarService : LifecycleService(), ServerStatusListener, LoginLis

const val ACTION_PERMISSIONS_GRANTED = "$RADAR_PACKAGE.ACTION_PERMISSIONS_GRANTED"
const val EXTRA_GRANT_RESULTS = "$RADAR_PACKAGE.EXTRA_GRANT_RESULTS"
const val ACTION_STOP_FOREGROUND_SERVICE = "$RADAR_PACKAGE.ACTION_STOP_FOREGROUND_SERVICE"

private const val BLUETOOTH_NOTIFICATION = 521290

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ class AppAuthState private constructor(builder: Builder) {
}.apply(changes).build()
}

fun clear(): AppAuthState = Builder().build()

class Builder {
val lastUpdate = SystemClock.elapsedRealtime()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ abstract class AuthService : Service(), LoginListener {
authSerialization.store(appAuth)
config.updateWithAuthState(this@AuthService, appAuth)
}

override fun loggedOut(manager: LoginManager?, authState: AppAuthState) {
// authSerialization.store(appAuth)
// config.updateWithAuthState(this@AuthService, appAuth)
}
})
}

Expand Down Expand Up @@ -183,6 +188,7 @@ abstract class AuthService : Service(), LoginListener {
listeners.filter { it.lastUpdate < sinceUpdate }
.forEach { listener ->
listener.lastUpdate = sinceUpdate
logger.info("Sending Login Succeed to listener: {}", listener.loginListener)
call(listener)
}
}
Expand All @@ -201,13 +207,22 @@ abstract class AuthService : Service(), LoginListener {
appAuth = authState

broadcaster.send(ACTION_LOGIN_SUCCESS)

callListeners(sinceUpdate = appAuth.lastUpdate) {
it.loginListener.loginSucceeded(manager, appAuth)
}
}
}

override fun loggedOut(manager: LoginManager?, authState: AppAuthState) {
handler.executeReentrant {
logger.info("Logout Succeed")
appAuth = authState
callListeners {
it.loginListener.loggedOut(manager, appAuth)
}
}
}

override fun onDestroy() {
networkConnectedListener.unregister()
configRegistration?.let { removeLoginListener(it) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ abstract class LoginActivity : AppCompatActivity(), LoginListener {
finish()
}

override fun loggedOut(manager: LoginManager?, authState: AppAuthState) = Unit

companion object {
private val logger = LoggerFactory.getLogger(LoginActivity::class.java)
const val ACTION_LOGIN = "org.radarcns.auth.LoginActivity.login"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,6 @@ interface LoginListener {
* It my also be `null`.
*/
fun loginFailed(manager: LoginManager?, ex: Exception?)

fun loggedOut(manager: LoginManager?, authState: AppAuthState)
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class ManagementPortalLoginManager(private val listener: AuthService, state: App
disableRefresh -> authState.alter {
attributes -= MP_REFRESH_TOKEN_PROPERTY
isPrivacyPolicyAccepted = false
}
}.also { listener.loggedOut(this@ManagementPortalLoginManager, authState.clear()) }
else -> authState
}
}
Expand Down Expand Up @@ -273,7 +273,6 @@ class ManagementPortalLoginManager(private val listener: AuthService, state: App
logger.error("Cannot construct ManagementPortalClient without client credentials")
null
}

if (newClientConfig == clientConfig) return

client = newClientConfig?.let {
Expand All @@ -284,6 +283,7 @@ class ManagementPortalLoginManager(private val listener: AuthService, state: App
client = restClient,
).also { restClient = it.client }
}

}

private fun addSource(authState: AppAuthState, source: SourceMetadata): AppAuthState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ class CombinedRadarConfig(
persistChanges()
}

override fun resetStatus() {
(remoteConfigs.find { it is FirebaseRemoteConfiguration } as FirebaseRemoteConfiguration).resetStatus()
status = INITIAL
}

override fun fetch() = remoteConfigs.forEach {
it.fetch(latestConfig.getLong(FETCH_TIMEOUT_MS_KEY, FETCH_TIMEOUT_MS_DEFAULT))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ class FirebaseRemoteConfiguration(private val context: Context, inDevelopmentMod
}
}

fun resetStatus() {
status = RadarConfiguration.RemoteConfigStatus.INITIAL
}

companion object {
private val logger = LoggerFactory.getLogger(FirebaseRemoteConfiguration::class.java)
private const val FIREBASE_FETCH_TIMEOUT_MS_DEFAULT = 12 * 60 * 60 * 1000L
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ abstract class SourceProvider<T : BaseSourceState>(protected val radarService: R
connection.onServiceDisconnected(null)
}

fun stopService() {
val intent = Intent(radarService, serviceClass)
radarService.stopService(intent)
}

/**
* Update the configuration of the service based on the given RadarConfiguration.
* @throws IllegalStateException if [.getConnection] has not been called
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class SourceProviderRegistrar(
}
}

override fun loggedOut(manager: LoginManager?, authState: AppAuthState) = Unit

private fun registerProvider(provider: SourceProvider<*>, authState: AppAuthState) {
if (isClosed) {
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ abstract class SourceService<T : BaseSourceState> : LifecycleService(), SourceSt
}
}

override fun loggedOut(manager: LoginManager?, authState: AppAuthState) = Unit

override fun loginFailed(manager: LoginManager?, ex: Exception?) {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ abstract class SplashActivity : AppCompatActivity() {
startActivity(radarApp.loginActivity)
}
}

override fun loggedOut(manager: LoginManager?, authState: AppAuthState) = Unit
}
}

Expand Down
Loading