Unverified Commit 72fb3e02 authored by Lucio Maciel's avatar Lucio Maciel Committed by GitHub

Merge pull request #1351 from RocketChat/release/2.3.0-hotfix2

[RELEASE] 2.3.2 - HOTFIX
parents 73eb4e89 fc47bcfe
...@@ -13,8 +13,8 @@ android { ...@@ -13,8 +13,8 @@ android {
applicationId "chat.rocket.android" applicationId "chat.rocket.android"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion versions.targetSdk targetSdkVersion versions.targetSdk
versionCode 2025 versionCode 2026
versionName "2.3.1" versionName "2.3.2"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true multiDexEnabled true
} }
......
...@@ -16,13 +16,22 @@ import chat.rocket.android.app.migration.model.RealmBasedServerInfo ...@@ -16,13 +16,22 @@ import chat.rocket.android.app.migration.model.RealmBasedServerInfo
import chat.rocket.android.app.migration.model.RealmPublicSetting import chat.rocket.android.app.migration.model.RealmPublicSetting
import chat.rocket.android.app.migration.model.RealmSession import chat.rocket.android.app.migration.model.RealmSession
import chat.rocket.android.app.migration.model.RealmUser import chat.rocket.android.app.migration.model.RealmUser
import chat.rocket.android.authentication.domain.model.toToken
import chat.rocket.android.dagger.DaggerAppComponent import chat.rocket.android.dagger.DaggerAppComponent
import chat.rocket.android.dagger.qualifier.ForMessages import chat.rocket.android.dagger.qualifier.ForMessages
import chat.rocket.android.helper.CrashlyticsTree import chat.rocket.android.helper.CrashlyticsTree
import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.* import chat.rocket.android.infrastructure.installCrashlyticsWrapper
import chat.rocket.android.server.domain.AccountsRepository
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SITE_URL
import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.serverLogoUrl import chat.rocket.android.util.extensions.serverLogoUrl
import chat.rocket.android.widget.emoji.EmojiRepository import chat.rocket.android.widget.emoji.EmojiRepository
...@@ -34,13 +43,16 @@ import com.facebook.drawee.backends.pipeline.DraweeConfig ...@@ -34,13 +43,16 @@ import com.facebook.drawee.backends.pipeline.DraweeConfig
import com.facebook.drawee.backends.pipeline.Fresco import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imagepipeline.core.ImagePipelineConfig import com.facebook.imagepipeline.core.ImagePipelineConfig
import com.jakewharton.threetenabp.AndroidThreeTen import com.jakewharton.threetenabp.AndroidThreeTen
import dagger.android.* import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasActivityInjector
import dagger.android.HasBroadcastReceiverInjector
import dagger.android.HasServiceInjector
import io.fabric.sdk.android.Fabric import io.fabric.sdk.android.Fabric
import io.realm.Realm import io.realm.Realm
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.launch import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.runBlocking
import timber.log.Timber import timber.log.Timber
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import javax.inject.Inject import javax.inject.Inject
...@@ -69,7 +81,7 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje ...@@ -69,7 +81,7 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
@Inject @Inject
lateinit var getCurrentServerInteractor: GetCurrentServerInteractor lateinit var getCurrentServerInteractor: GetCurrentServerInteractor
@Inject @Inject
lateinit var multiServerRepository: MultiServerTokenRepository lateinit var settingsInteractor: GetSettingsInteractor
@Inject @Inject
lateinit var settingsRepository: SettingsRepository lateinit var settingsRepository: SettingsRepository
@Inject @Inject
...@@ -81,8 +93,6 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje ...@@ -81,8 +93,6 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
@Inject @Inject
lateinit var prefs: SharedPreferences lateinit var prefs: SharedPreferences
@Inject @Inject
lateinit var getAccountsInteractor: GetAccountsInteractor
@Inject
lateinit var localRepository: LocalRepository lateinit var localRepository: LocalRepository
@Inject @Inject
...@@ -101,8 +111,6 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje ...@@ -101,8 +111,6 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
.lifecycle .lifecycle
.addObserver(appLifecycleObserver) .addObserver(appLifecycleObserver)
// TODO - remove this on the future, temporary migration stuff for pre-release versions.
migrateInternalTokens()
context = WeakReference(applicationContext) context = WeakReference(applicationContext)
AndroidThreeTen.init(this) AndroidThreeTen.init(this)
...@@ -127,6 +135,29 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje ...@@ -127,6 +135,29 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
} catch (ex: Exception) { } catch (ex: Exception) {
Timber.d(ex, "Error migrating old accounts") Timber.d(ex, "Error migrating old accounts")
} }
// TODO - remove this
checkCurrentServer()
}
private fun checkCurrentServer() {
val currentServer = getCurrentServerInteractor.get() ?: "<unknown>"
if (currentServer == "<unknown>") {
val message = "null currentServer"
Timber.d(IllegalStateException(message), message)
}
val settings = settingsInteractor.get(currentServer)
if (settings.isEmpty()) {
val message = "Empty settings for: $currentServer"
Timber.d(IllegalStateException(message), message)
}
val baseUrl = settings[SITE_URL]
if (baseUrl == null) {
val message = "Server $currentServer SITE_URL"
Timber.d(IllegalStateException(message), message)
}
} }
private fun migrateFromLegacy() { private fun migrateFromLegacy() {
...@@ -233,32 +264,13 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje ...@@ -233,32 +264,13 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
} }
} }
private fun migrateInternalTokens() {
if (!prefs.getBoolean(INTERNAL_TOKEN_MIGRATION_NEEDED, true)) {
Timber.d("Tokens already migrated")
return
}
getCurrentServerInteractor.get()?.let { serverUrl ->
multiServerRepository.get(serverUrl)?.let { token ->
tokenRepository.save(serverUrl, Token(token.userId, token.authToken))
}
}
runBlocking {
getAccountsInteractor.get().forEach { account ->
multiServerRepository.get(account.serverUrl)?.let { token ->
tokenRepository.save(account.serverUrl, token.toToken())
}
}
}
prefs.edit { putBoolean(INTERNAL_TOKEN_MIGRATION_NEEDED, false) }
}
private fun setupCrashlytics() { private fun setupCrashlytics() {
val core = CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build() val core = CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()
Fabric.with(this, Crashlytics.Builder().core(core).build()) Fabric.with(this, Crashlytics.Builder().core(core).build())
installCrashlyticsWrapper(this@RocketChatApplication,
getCurrentServerInteractor, settingsInteractor,
accountRepository, localRepository)
} }
private fun setupFresco() { private fun setupFresco() {
...@@ -301,6 +313,4 @@ private fun LocalRepository.hasMigrated() = getBoolean(LocalRepository.MIGRATION ...@@ -301,6 +313,4 @@ private fun LocalRepository.hasMigrated() = getBoolean(LocalRepository.MIGRATION
private fun LocalRepository.needOldMessagesCleanUp() = getBoolean(CLEANUP_OLD_MESSAGES_NEEDED, true) private fun LocalRepository.needOldMessagesCleanUp() = getBoolean(CLEANUP_OLD_MESSAGES_NEEDED, true)
private fun LocalRepository.setOldMessagesCleanedUp() = save(CLEANUP_OLD_MESSAGES_NEEDED, false) private fun LocalRepository.setOldMessagesCleanedUp() = save(CLEANUP_OLD_MESSAGES_NEEDED, false)
private const val INTERNAL_TOKEN_MIGRATION_NEEDED = "INTERNAL_TOKEN_MIGRATION_NEEDED"
private const val CLEANUP_OLD_MESSAGES_NEEDED = "CLEANUP_OLD_MESSAGES_NEEDED" private const val CLEANUP_OLD_MESSAGES_NEEDED = "CLEANUP_OLD_MESSAGES_NEEDED"
\ No newline at end of file
...@@ -812,7 +812,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -812,7 +812,7 @@ class ChatRoomPresenter @Inject constructor(
} }
} }
if (typingStatusList.isNotEmpty()) { if (typingStatusList.isNotEmpty()) {
view.showTypingStatus(typingStatusList) view.showTypingStatus(typingStatusList.toList()) // copy typingStatusList
} else { } else {
view.hideTypingStatusView() view.hideTypingStatusView()
} }
......
...@@ -31,7 +31,7 @@ interface ChatRoomView : LoadingView, MessageView { ...@@ -31,7 +31,7 @@ interface ChatRoomView : LoadingView, MessageView {
* *
* @param usernameList The list of username to show. * @param usernameList The list of username to show.
*/ */
fun showTypingStatus(usernameList: ArrayList<String>) fun showTypingStatus(usernameList: List<String>)
/** /**
* Hides the typing status view. * Hides the typing status view.
......
...@@ -367,7 +367,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -367,7 +367,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
} }
override fun showTypingStatus(usernameList: ArrayList<String>) { override fun showTypingStatus(usernameList: List<String>) {
ui { ui {
when (usernameList.size) { when (usernameList.size) {
1 -> { 1 -> {
......
...@@ -61,8 +61,8 @@ class ViewModelMapper @Inject constructor( ...@@ -61,8 +61,8 @@ class ViewModelMapper @Inject constructor(
) { ) {
private val currentServer = serverInteractor.get()!! private val currentServer = serverInteractor.get()!!
private val settings: Map<String, Value<Any>> = getSettingsInteractor.get(currentServer) private val settings = getSettingsInteractor.get(currentServer)
private val baseUrl = settings.baseUrl() private val baseUrl = currentServer
private val token = tokenRepository.get(currentServer) private val token = tokenRepository.get(currentServer)
private val currentUsername: String? = localRepository.get(LocalRepository.CURRENT_USERNAME_KEY) private val currentUsername: String? = localRepository.get(LocalRepository.CURRENT_USERNAME_KEY)
private val secondaryTextColor = ContextCompat.getColor(context, R.color.colorSecondaryText) private val secondaryTextColor = ContextCompat.getColor(context, R.color.colorSecondaryText)
......
...@@ -3,6 +3,7 @@ package chat.rocket.android.chatrooms.ui ...@@ -3,6 +3,7 @@ package chat.rocket.android.chatrooms.ui
import android.app.AlertDialog import android.app.AlertDialog
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.renderscript.RSInvalidStateException
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.support.v7.util.DiffUtil import android.support.v7.util.DiffUtil
...@@ -37,11 +38,13 @@ import chat.rocket.android.widget.DividerItemDecoration ...@@ -37,11 +38,13 @@ import chat.rocket.android.widget.DividerItemDecoration
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
import chat.rocket.core.internal.realtime.socket.model.State import chat.rocket.core.internal.realtime.socket.model.State
import chat.rocket.core.model.ChatRoom import chat.rocket.core.model.ChatRoom
import com.crashlytics.android.Crashlytics
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_chat_rooms.* import kotlinx.android.synthetic.main.fragment_chat_rooms.*
import kotlinx.coroutines.experimental.Job import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.NonCancellable.isActive import kotlinx.coroutines.experimental.NonCancellable.isActive
import timber.log.Timber import timber.log.Timber
import java.security.InvalidParameterException
import javax.inject.Inject import javax.inject.Inject
private const val BUNDLE_CHAT_ROOM_ID = "BUNDLE_CHAT_ROOM_ID" private const val BUNDLE_CHAT_ROOM_ID = "BUNDLE_CHAT_ROOM_ID"
......
package chat.rocket.android.infrastructure
import android.app.Application
import chat.rocket.android.BuildConfig
import chat.rocket.android.server.domain.AccountsRepository
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.SITE_URL
import com.crashlytics.android.Crashlytics
import kotlinx.coroutines.experimental.runBlocking
fun installCrashlyticsWrapper(context: Application,
currentServerInteractor: GetCurrentServerInteractor,
settingsInteractor: GetSettingsInteractor,
accountRepository: AccountsRepository,
localRepository: LocalRepository) {
if (isCrashlyticsEnabled()) {
Thread.setDefaultUncaughtExceptionHandler(RocketChatUncaughtExceptionHandler(currentServerInteractor,
settingsInteractor, accountRepository, localRepository))
}
}
private fun isCrashlyticsEnabled(): Boolean {
return !BuildConfig.DEBUG
}
private class RocketChatUncaughtExceptionHandler(
val currentServerInteractor: GetCurrentServerInteractor,
val settingsInteractor: GetSettingsInteractor,
val accountRepository: AccountsRepository,
val localRepository: LocalRepository)
: Thread.UncaughtExceptionHandler {
val crashlyticsHandler: Thread.UncaughtExceptionHandler? = Thread.getDefaultUncaughtExceptionHandler()
override fun uncaughtException(t: Thread, e: Throwable) {
val currentServer = currentServerInteractor.get() ?: "<unknown>"
Crashlytics.setString(KEY_CURRENT_SERVER, currentServer)
runBlocking {
val accounts = accountRepository.load()
Crashlytics.setString(KEY_ACCOUNTS, accounts.toString())
}
val settings = settingsInteractor.get(currentServer)
Crashlytics.setInt(KEY_SETTINGS_SIZE, settings.size)
val baseUrl = settings[SITE_URL]?.toString()
Crashlytics.setString(KEY_SETTINGS_BASE_URL, baseUrl)
val user = localRepository.getCurrentUser(currentServer)
Crashlytics.setString(KEY_CURRENT_USER, user?.toString())
Crashlytics.setString(KEY_CURRENT_USERNAME, localRepository.username())
if (crashlyticsHandler != null) {
crashlyticsHandler.uncaughtException(t, e)
} else {
throw RuntimeException("Missing default exception handler")
}
}
}
private const val KEY_CURRENT_SERVER = "CURRENT_SERVER"
private const val KEY_CURRENT_USER = "CURRENT_USER"
private const val KEY_CURRENT_USERNAME = "CURRENT_USERNAME"
private const val KEY_ACCOUNTS = "ACCOUNTS"
private const val KEY_SETTINGS_SIZE = "SETTINGS_SIZE"
private const val KEY_SETTINGS_BASE_URL = "SETTINGS_BASE_URL"
\ No newline at end of file
...@@ -5,11 +5,6 @@ import chat.rocket.core.model.Value ...@@ -5,11 +5,6 @@ import chat.rocket.core.model.Value
typealias PublicSettings = Map<String, Value<Any>> typealias PublicSettings = Map<String, Value<Any>>
interface SettingsRepository {
fun save(url: String, settings: PublicSettings)
fun get(url: String): PublicSettings
}
// Authentication methods. // Authentication methods.
const val LDAP_ENABLE = "LDAP_Enable" const val LDAP_ENABLE = "LDAP_Enable"
const val CAS_ENABLE = "CAS_enabled" const val CAS_ENABLE = "CAS_enabled"
...@@ -105,3 +100,8 @@ fun PublicSettings.uploadMaxFileSize(): Int { ...@@ -105,3 +100,8 @@ fun PublicSettings.uploadMaxFileSize(): Int {
fun PublicSettings.baseUrl(): String = this[SITE_URL]?.value as String fun PublicSettings.baseUrl(): String = this[SITE_URL]?.value as String
fun PublicSettings.siteName(): String? = this[SITE_NAME]?.value as String? fun PublicSettings.siteName(): String? = this[SITE_NAME]?.value as String?
interface SettingsRepository {
fun save(url: String, settings: PublicSettings)
fun get(url: String): PublicSettings
}
\ No newline at end of file
...@@ -5,6 +5,7 @@ import chat.rocket.android.infrastructure.LocalRepository.Companion.SETTINGS_KEY ...@@ -5,6 +5,7 @@ import chat.rocket.android.infrastructure.LocalRepository.Companion.SETTINGS_KEY
import chat.rocket.android.server.domain.PublicSettings import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SettingsRepository import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.core.internal.SettingsAdapter import chat.rocket.core.internal.SettingsAdapter
import timber.log.Timber
class SharedPreferencesSettingsRepository( class SharedPreferencesSettingsRepository(
private val localRepository: LocalRepository private val localRepository: LocalRepository
...@@ -13,11 +14,27 @@ class SharedPreferencesSettingsRepository( ...@@ -13,11 +14,27 @@ class SharedPreferencesSettingsRepository(
private val adapter = SettingsAdapter().lenient() private val adapter = SettingsAdapter().lenient()
override fun save(url: String, settings: PublicSettings) { override fun save(url: String, settings: PublicSettings) {
if (settings.isEmpty()) {
val message = "Saving empty settings for $SETTINGS_KEY$url"
Timber.d(IllegalStateException(message), message)
}
localRepository.save("$SETTINGS_KEY$url", adapter.toJson(settings)) localRepository.save("$SETTINGS_KEY$url", adapter.toJson(settings))
} }
override fun get(url: String): PublicSettings { override fun get(url: String): PublicSettings {
val settings = localRepository.get("$SETTINGS_KEY$url") val settingsStr = localRepository.get("$SETTINGS_KEY$url")
return if (settings == null) hashMapOf() else adapter.fromJson(settings) ?: hashMapOf() return if (settingsStr == null) {
val message = "NULL Settings for: $SETTINGS_KEY$url"
Timber.d(IllegalStateException(message), message)
hashMapOf()
} else {
val settings = adapter.fromJson(settingsStr)
if (settings == null) {
val message = "NULL Settings for: $SETTINGS_KEY$url with saved settings: $settingsStr"
Timber.d(IllegalStateException(message), message)
}
settings ?: hashMapOf()
}
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment