diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1bc233e75ea7e67ecacfafd76a0d260a89cd5e47..907d1f2e632ea1a1068209dec5eef5b2a624b4fd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -57,8 +57,6 @@ android { setProperty("archivesBaseName", "Quasseldroid-$versionName") - multiDexEnabled = false - // Disable test runner analytics testInstrumentationRunnerArguments = mapOf( "disableAnalytics" to "true" @@ -72,6 +70,8 @@ android { isShrinkResources = true isUseProguard = false + multiDexEnabled = false + proguardFiles( getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" @@ -81,15 +81,7 @@ android { getByName("debug") { applicationIdSuffix = ".debug" - isZipAlignEnabled = true - isMinifyEnabled = true - isShrinkResources = true - isUseProguard = false - - proguardFiles( - getDefaultProguardFile("proguard-android.txt"), - "proguard-rules.pro" - ) + multiDexEnabled = true } } @@ -134,6 +126,8 @@ dependencies { implementation("androidx.paging", "paging-runtime", "2.0.0-rc01") + implementation("androidx.multidex", "multidex", "2.0.0") + // Utility implementation("io.reactivex.rxjava2", "rxandroid", "2.0.2") implementation("io.reactivex.rxjava2", "rxjava", "2.1.9") diff --git a/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt b/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt index 505d431ca2e0e708ff36a9784d4912363db33ba9..747366f5b8a5d4292bea57f4dced26d17aea8e71 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt @@ -20,224 +20,27 @@ package de.kuschku.quasseldroid import android.content.Context -import android.os.Build -import android.os.StrictMode -import com.squareup.leakcanary.LeakCanary -import dagger.android.AndroidInjector import dagger.android.support.DaggerApplication -import de.kuschku.malheur.CrashHandler +import de.kuschku.quasseldroid.app.AppDelegate +import de.kuschku.quasseldroid.app.QuasseldroidReleaseDelegate import de.kuschku.quasseldroid.dagger.DaggerAppComponent -import de.kuschku.quasseldroid.persistence.db.AccountDatabase -import de.kuschku.quasseldroid.persistence.db.LegacyAccountDatabase -import de.kuschku.quasseldroid.persistence.models.Account -import de.kuschku.quasseldroid.settings.AppearanceSettings -import de.kuschku.quasseldroid.settings.SettingsMigration -import de.kuschku.quasseldroid.settings.SettingsMigrationManager -import de.kuschku.quasseldroid.util.backport.AndroidThreeTenBackport -import de.kuschku.quasseldroid.util.compatibility.AndroidCompatibilityUtils -import de.kuschku.quasseldroid.util.compatibility.AndroidLoggingHandler -import de.kuschku.quasseldroid.util.compatibility.AndroidStreamChannelFactory import de.kuschku.quasseldroid.util.ui.LocaleHelper open class Quasseldroid : DaggerApplication() { - override fun applicationInjector(): AndroidInjector<Quasseldroid> = - DaggerAppComponent.builder().create(this) - - protected open fun init() { - if (LeakCanary.isInAnalyzerProcess(this)) { - // This process is dedicated to LeakCanary for heap analysis. - // You should not init your app in this process. - return - } - LeakCanary.install(this) - // Normal app init code... - - CrashHandler.init( - application = this, - buildConfig = BuildConfig::class.java - ) - - // Init compatibility utils - AndroidCompatibilityUtils.inject() - AndroidLoggingHandler.inject() - AndroidStreamChannelFactory.inject() - - AndroidThreeTenBackport.init(this) - - applicationInjector().inject(this) - - // Migrate preferences - SettingsMigrationManager( - listOf( - SettingsMigration.migrationOf(0, 1) { prefs, edit -> - // Migrating database - val database = LegacyAccountDatabase.Creator.init(this) - val accounts = database.accounts().all() - database.close() - - val accountDatabase = AccountDatabase.Creator.init(this) - accountDatabase.accounts().create(*accounts.map { - Account( - id = it.id, - host = it.host, - port = it.port, - user = it.user, - requireSsl = false, - pass = it.pass, - name = it.name, - lastUsed = 0, - acceptedMissingFeatures = false, - defaultFiltered = 0 - ) - }.toTypedArray()) - Thread(Runnable { - deleteDatabase("data") - }).start() - - // Migrating actual settings - if (prefs.contains("selectedtheme")) { - prefs.getString("selectedtheme", "").let { theme -> - when (theme) { - "light" -> AppearanceSettings.Theme.MATERIAL_LIGHT - "dark" -> AppearanceSettings.Theme.MATERIAL_DARK - else -> null - }?.let { - edit.putString(getString(R.string.preference_theme_key), it.name) - } - } - edit.remove("selectedtheme") - } - - if (prefs.contains("timestamp")) { - prefs.getString("timestamp", "").let { - val timestamp = it ?: "" - edit.putBoolean(getString(R.string.preference_show_seconds_key), - timestamp.contains("ss")) - edit.putBoolean(getString(R.string.preference_show_seconds_key), - !timestamp.contains("hh") && !timestamp.contains("a")) - } - edit.remove("timestamp") - } - - if (prefs.contains("fontsizeChannelList")) { - prefs.getString("fontsizeChannelList", "")?.toIntOrNull()?.let { fontSize -> - edit.putInt(getString(R.string.preference_textsize_key), fontSize) - } - edit.remove("fontsizeChannelList") - } - - if (prefs.contains("allowcoloredtext")) { - prefs.getBoolean("allowcoloredtext", false).let { - edit.putBoolean(getString(R.string.preference_colorize_mirc_key), it) - } - edit.remove("allowcoloredtext") - } - - if (prefs.contains("monospace")) { - prefs.getBoolean("monospace", false).let { - edit.putBoolean(getString(R.string.preference_monospace_key), it) - } - edit.remove("monospace") - } - - if (prefs.contains("detailed_actions")) { - prefs.getBoolean("detailed_actions", false).let { - edit.putBoolean(getString(R.string.preference_hostmask_actions_key), it) - } - edit.remove("detailed_actions") - } - - if (prefs.contains("showlag")) { - prefs.getBoolean("showlag", false).let { - edit.putBoolean(getString(R.string.preference_show_lag_key), it) - } - edit.remove("showlag") - } - } - ) - ).migrate(this) - - // Initialize preferences unless already set - - /* - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - systemService<ShortcutManager>().dynamicShortcuts = listOf( - ShortcutInfo.Builder(this, "id1") - .setShortLabel("#quassel") - .setIcon(Icon.createWithResource(this, R.drawable.ic_shortcut_channel)) - .setIntent(packageManager.getLaunchIntentForPackage(BuildConfig.APPLICATION_ID)) - .build(), - ShortcutInfo.Builder(this, "id2") - .setShortLabel("#quasseldroid") - .setIcon(Icon.createWithResource(this, R.drawable.ic_shortcut_channel)) - .setIntent(packageManager.getLaunchIntentForPackage(BuildConfig.APPLICATION_ID)) - .build(), - ShortcutInfo.Builder(this, "id3") - .setShortLabel("#quassel.de") - .setIcon(Icon.createWithResource(this, R.drawable.ic_shortcut_channel)) - .setIntent(packageManager.getLaunchIntentForPackage(BuildConfig.APPLICATION_ID)) - .build(), - ShortcutInfo.Builder(this, "id4") - .setShortLabel("justJanne") - .setIcon(Icon.createWithResource(this, R.drawable.ic_shortcut_query)) - .setIntent(packageManager.getLaunchIntentForPackage(BuildConfig.APPLICATION_ID)) - .build() - ) - } - */ - - if (BuildConfig.DEBUG) { - StrictMode.setThreadPolicy( - StrictMode.ThreadPolicy.Builder() - .detectNetwork() - .detectCustomSlowCalls() - .let { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - it.detectResourceMismatches() - } else { - it - } - }.let { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - it.detectUnbufferedIo() - } else { - it - } - } - .penaltyLog() - .build() - ) - StrictMode.setVmPolicy( - StrictMode.VmPolicy.Builder() - .detectLeakedSqlLiteObjects() - .detectActivityLeaks() - .detectLeakedClosableObjects() - .detectLeakedRegistrationObjects() - .let { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - it.detectFileUriExposure() - } else { - it - } - }.let { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - it.detectContentUriWithoutPermission() - } else { - it - } - } - .penaltyLog() - .build() - ) - } - } + override fun applicationInjector() = DaggerAppComponent.builder().create(this) + open val delegate: AppDelegate = QuasseldroidReleaseDelegate(this) override fun onCreate() { super.onCreate() - init() + if (delegate.shouldInit()) { + delegate.onInit() + applicationInjector().inject(this) + delegate.onPostInit() + } } override fun attachBaseContext(base: Context) { super.attachBaseContext(LocaleHelper.setLocale(base)) + delegate.onInstallMultidex() } } diff --git a/app/src/main/java/de/kuschku/quasseldroid/app/AppDelegate.kt b/app/src/main/java/de/kuschku/quasseldroid/app/AppDelegate.kt new file mode 100644 index 0000000000000000000000000000000000000000..482bb355077ca4ad20e4d305fe1db2aff1073669 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/app/AppDelegate.kt @@ -0,0 +1,27 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid.app + +interface AppDelegate { + fun shouldInit(): Boolean + fun onInstallMultidex() + fun onInit() + fun onPostInit() +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidReleaseDelegate.kt b/app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidReleaseDelegate.kt new file mode 100644 index 0000000000000000000000000000000000000000..87724c0402b7dc8066aa00d8a0e36ed3f4a386c2 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidReleaseDelegate.kt @@ -0,0 +1,214 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid.app + +import android.os.Build +import android.os.StrictMode +import androidx.multidex.MultiDex +import com.squareup.leakcanary.LeakCanary +import de.kuschku.malheur.CrashHandler +import de.kuschku.quasseldroid.BuildConfig +import de.kuschku.quasseldroid.Quasseldroid +import de.kuschku.quasseldroid.R +import de.kuschku.quasseldroid.persistence.db.AccountDatabase +import de.kuschku.quasseldroid.persistence.db.LegacyAccountDatabase +import de.kuschku.quasseldroid.persistence.models.Account +import de.kuschku.quasseldroid.settings.AppearanceSettings +import de.kuschku.quasseldroid.settings.SettingsMigration +import de.kuschku.quasseldroid.settings.SettingsMigrationManager +import de.kuschku.quasseldroid.util.backport.AndroidThreeTenBackport +import de.kuschku.quasseldroid.util.compatibility.AndroidCompatibilityUtils +import de.kuschku.quasseldroid.util.compatibility.AndroidLoggingHandler +import de.kuschku.quasseldroid.util.compatibility.AndroidStreamChannelFactory + +class QuasseldroidReleaseDelegate(private val app: Quasseldroid) : + AppDelegate { + override fun shouldInit() = !LeakCanary.isInAnalyzerProcess(app) + + override fun onInit() { + LeakCanary.install(app) + // Normal app init code... + + CrashHandler.init( + application = app, + buildConfig = BuildConfig::class.java + ) + + // Init compatibility utils + AndroidCompatibilityUtils.inject() + AndroidLoggingHandler.inject() + AndroidStreamChannelFactory.inject() + + AndroidThreeTenBackport.init(app) + } + + override fun onPostInit() { + // Migrate preferences + SettingsMigrationManager( + listOf( + SettingsMigration.migrationOf(0, + 1) { prefs, edit -> + // Migrating database + val database = LegacyAccountDatabase.Creator.init( + app) + val accounts = database.accounts().all() + database.close() + + val accountDatabase = AccountDatabase.Creator.init( + app) + accountDatabase.accounts().create(*accounts.map { + Account( + id = it.id, + host = it.host, + port = it.port, + user = it.user, + requireSsl = false, + pass = it.pass, + name = it.name, + lastUsed = 0, + acceptedMissingFeatures = false, + defaultFiltered = 0 + ) + }.toTypedArray()) + Thread(Runnable { + app.deleteDatabase("data") + }).start() + + // Migrating actual settings + if (prefs.contains("selectedtheme")) { + prefs.getString("selectedtheme", "").let { theme -> + when (theme) { + "light" -> AppearanceSettings.Theme.MATERIAL_LIGHT + "dark" -> AppearanceSettings.Theme.MATERIAL_DARK + else -> null + }?.let { + edit.putString(app.getString(R.string.preference_theme_key), + it.name) + } + } + edit.remove("selectedtheme") + } + + if (prefs.contains("timestamp")) { + prefs.getString("timestamp", "").let { + val timestamp = it ?: "" + edit.putBoolean(app.getString(R.string.preference_show_seconds_key), + timestamp.contains("ss")) + edit.putBoolean(app.getString(R.string.preference_show_seconds_key), + !timestamp.contains("hh") && !timestamp.contains("a")) + } + edit.remove("timestamp") + } + + if (prefs.contains("fontsizeChannelList")) { + prefs.getString("fontsizeChannelList", "")?.toIntOrNull()?.let { fontSize -> + edit.putInt(app.getString(R.string.preference_textsize_key), + fontSize) + } + edit.remove("fontsizeChannelList") + } + + if (prefs.contains("allowcoloredtext")) { + prefs.getBoolean("allowcoloredtext", false).let { + edit.putBoolean(app.getString(R.string.preference_colorize_mirc_key), + it) + } + edit.remove("allowcoloredtext") + } + + if (prefs.contains("monospace")) { + prefs.getBoolean("monospace", false).let { + edit.putBoolean(app.getString(R.string.preference_monospace_key), + it) + } + edit.remove("monospace") + } + + if (prefs.contains("detailed_actions")) { + prefs.getBoolean("detailed_actions", false).let { + edit.putBoolean(app.getString(R.string.preference_hostmask_actions_key), + it) + } + edit.remove("detailed_actions") + } + + if (prefs.contains("showlag")) { + prefs.getBoolean("showlag", false).let { + edit.putBoolean(app.getString(R.string.preference_show_lag_key), + it) + } + edit.remove("showlag") + } + } + ) + ).migrate(app) + + if (BuildConfig.DEBUG) { + StrictMode.setThreadPolicy( + StrictMode.ThreadPolicy.Builder() + .detectNetwork() + .detectCustomSlowCalls() + .let { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + it.detectResourceMismatches() + } else { + it + } + }.let { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + it.detectUnbufferedIo() + } else { + it + } + } + .penaltyLog() + .build() + ) + StrictMode.setVmPolicy( + StrictMode.VmPolicy.Builder() + .detectLeakedSqlLiteObjects() + .detectActivityLeaks() + .detectLeakedClosableObjects() + .detectLeakedRegistrationObjects() + .let { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + it.detectFileUriExposure() + } else { + it + } + }.let { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + it.detectContentUriWithoutPermission() + } else { + it + } + } + .penaltyLog() + .build() + ) + } + } + + override fun onInstallMultidex() { + if (BuildConfig.DEBUG) { + MultiDex.install(app) + } + } +} diff --git a/app/src/test/java/de/kuschku/quasseldroid/QuasseldroidTest.kt b/app/src/test/java/de/kuschku/quasseldroid/QuasseldroidTest.kt index 5f0b57dc69da0df35c280e5de7a147931f5362b7..2ecdd1764ff30becbc7eb888faf27c5966575b62 100644 --- a/app/src/test/java/de/kuschku/quasseldroid/QuasseldroidTest.kt +++ b/app/src/test/java/de/kuschku/quasseldroid/QuasseldroidTest.kt @@ -19,8 +19,8 @@ package de.kuschku.quasseldroid +import de.kuschku.quasseldroid.app.QuasseldroidTestDelegate + class QuasseldroidTest : Quasseldroid() { - override fun init() { - applicationInjector().inject(this) - } + override val delegate = QuasseldroidTestDelegate() } diff --git a/app/src/test/java/de/kuschku/quasseldroid/app/QuasseldroidTestDelegate.kt b/app/src/test/java/de/kuschku/quasseldroid/app/QuasseldroidTestDelegate.kt new file mode 100644 index 0000000000000000000000000000000000000000..2341e01b85135288d9b8a9880a86d54131326869 --- /dev/null +++ b/app/src/test/java/de/kuschku/quasseldroid/app/QuasseldroidTestDelegate.kt @@ -0,0 +1,27 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid.app + +class QuasseldroidTestDelegate : AppDelegate { + override fun shouldInit() = true + override fun onInstallMultidex() = Unit + override fun onInit() = Unit + override fun onPostInit() = Unit +}