From 176cb854b456c239e163556673dad3ef0195d038 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Wed, 15 Sep 2021 23:36:54 +0200 Subject: [PATCH 01/24] Update: Gradle wrapper --- gradle/wrapper/gradle-wrapper.properties | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 558870d..892ac8c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Wed Sep 15 23:07:46 CEST 2021 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME From ab12b80b702d20adeb09095e44ed1ee2cd9d6b9c Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Wed, 15 Sep 2021 23:40:01 +0200 Subject: [PATCH 02/24] Update: Dependencies --- build.gradle | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 4c8edca..205458d 100644 --- a/build.gradle +++ b/build.gradle @@ -116,13 +116,14 @@ repositories { } dependencies { - implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:' + versions.kotlin - implementation 'androidx.fragment:fragment:1.2.5' + implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:' + versions.kotlin + implementation 'androidx.fragment:fragment-ktx:1.3.6' implementation 'androidx.viewpager2:viewpager2:1.0.0' implementation 'androidx.vectordrawable:vectordrawable:1.1.0' - implementation 'com.squareup.okhttp3:okhttp:4.7.2' - implementation 'io.reactivex.rxjava3:rxjava:3.0.4' + implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.2' + implementation 'io.reactivex.rxjava3:rxjava:3.1.1' implementation 'io.reactivex.rxjava3:rxandroid:3.0.0' - implementation 'com.fasterxml.jackson.core:jackson-core:2.11.0' - implementation 'com.squareup.picasso:picasso:2.71828' + implementation 'io.reactivex.rxjava3:rxkotlin:3.0.1' + implementation 'com.fasterxml.jackson.core:jackson-core:2.12.5' + implementation 'com.squareup.picasso:picasso:2.8' } From b9ed252ed1bc228ecf0a5c1fae82af2cab2b2ed3 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Wed, 15 Sep 2021 23:41:18 +0200 Subject: [PATCH 03/24] Update: AGP --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 205458d..3609b28 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ buildscript { ext.versions = [ - android: '3.4.1', + android: '7.0.2', kotlin: '1.3.72' ] From 43d45871ecbfed1c3f2ea3cece62ef8880d41ba9 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Wed, 15 Sep 2021 23:41:44 +0200 Subject: [PATCH 04/24] Update: Tweak gradle build --- gradle.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gradle.properties b/gradle.properties index 5bac8ac..e5635fe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,4 @@ android.useAndroidX=true +android.enableJetifier=true +org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +org.gradle.parallel=true From 97286f76a32b2ef82df69977d4b522aa5a143012 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Wed, 15 Sep 2021 23:42:06 +0200 Subject: [PATCH 05/24] Update: Kotlin --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3609b28..d4278f4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ buildscript { ext.versions = [ android: '7.0.2', - kotlin: '1.3.72' + kotlin: '1.5.30' ] repositories { From 6ebf500540cb4036eb9eed0e470670c181d7f7fd Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Wed, 15 Sep 2021 23:43:11 +0200 Subject: [PATCH 06/24] Update: Migrate from Jcenter to MavenCentral --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index d4278f4..ae51893 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ buildscript { ] repositories { + mavenCentral() google() - jcenter() } dependencies { @@ -111,8 +111,8 @@ android { } repositories { + mavenCentral() google() - jcenter() } dependencies { From 6461c313a29cbb933b26b0bad90217fe477e41fd Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Wed, 15 Sep 2021 23:44:20 +0200 Subject: [PATCH 07/24] Update: Compile- and targetSDK to 31 --- build.gradle | 5 ++--- src/main/AndroidManifest.xml | 6 ++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index ae51893..d52033f 100644 --- a/build.gradle +++ b/build.gradle @@ -19,14 +19,13 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' android { - compileSdkVersion 29 - buildToolsVersion '29.0.3' + compileSdkVersion 31 defaultConfig { archivesBaseName = 'foxy-droid' applicationId 'nya.kitsunyan.foxydroid' minSdkVersion 21 - targetSdkVersion 29 + targetSdkVersion 31 versionCode 4 versionName '1.3' diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 11237ad..2dc6051 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -20,7 +20,8 @@ tools:ignore="GoogleAppIndexingWarning"> + android:name=".MainApplication$BootReceiver" + android:exported="false"> @@ -31,7 +32,8 @@ + android:windowSoftInputMode="adjustResize" + android:exported="true"> From a8438c974f642b1469af4eadf5036ce478661b16 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Wed, 15 Sep 2021 23:45:27 +0200 Subject: [PATCH 08/24] Fix: Removed/deprecated Kotlin functions --- src/main/kotlin/nya/kitsunyan/foxydroid/entity/Product.kt | 2 +- .../kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/entity/Product.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/entity/Product.kt index 133e9b5..4e8b0d7 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/entity/Product.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/entity/Product.kt @@ -129,7 +129,7 @@ data class Product(val repositoryId: Long, val packageName: String, val name: St companion object { fun findSuggested(products: List, installedItem: InstalledItem?, extract: (T) -> Product): T? { - return products.maxWith(compareBy({ extract(it).compatible && + return products.maxWithOrNull(compareBy({ extract(it).compatible && (installedItem == null || installedItem.signature in extract(it).signatures) }, { extract(it).versionCode })) } diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt index deb28c9..d223f86 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt @@ -338,8 +338,8 @@ class ProductFragment(): ScreenFragment(), ProductAdapter.Callbacks { val release = if (compatibleReleases.size >= 2) { compatibleReleases .filter { it.platforms.contains(Android.primaryPlatform) } - .minBy { it.platforms.size } - ?: compatibleReleases.minBy { it.platforms.size } + .minByOrNull { it.platforms.size } + ?: compatibleReleases.minByOrNull { it.platforms.size } ?: compatibleReleases.firstOrNull() } else { compatibleReleases.firstOrNull() From 94f5b6636873bf7660bbc8f5b80fa83c0ad32715 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Thu, 16 Sep 2021 00:56:01 +0200 Subject: [PATCH 09/24] Add: Root installation preference --- build.gradle | 2 ++ src/main/kotlin/nya/kitsunyan/foxydroid/content/Preferences.kt | 3 ++- .../nya/kitsunyan/foxydroid/screen/PreferencesFragment.kt | 3 +++ src/main/res/values/strings.xml | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d52033f..8427e50 100644 --- a/build.gradle +++ b/build.gradle @@ -112,6 +112,7 @@ android { repositories { mavenCentral() google() + maven { url 'https://jitpack.io' } } dependencies { @@ -125,4 +126,5 @@ dependencies { implementation 'io.reactivex.rxjava3:rxkotlin:3.0.1' implementation 'com.fasterxml.jackson.core:jackson-core:2.12.5' implementation 'com.squareup.picasso:picasso:2.8' + implementation 'com.github.topjohnwu.libsu:core:3.1.2' } diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/content/Preferences.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/content/Preferences.kt index 470fe68..26a786f 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/content/Preferences.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/content/Preferences.kt @@ -15,7 +15,7 @@ object Preferences { private val subject = PublishSubject.create>() - private val keys = sequenceOf(Key.AutoSync, Key.IncompatibleVersions, Key.ProxyHost, Key.ProxyPort, Key.ProxyType, + private val keys = sequenceOf(Key.AutoSync, Key.IncompatibleVersions, Key.RootInstalation, Key.ProxyHost, Key.ProxyPort, Key.ProxyType, Key.SortOrder, Key.Theme, Key.UpdateNotify, Key.UpdateUnstable).map { Pair(it.name, it) }.toMap() fun init(context: Context) { @@ -82,6 +82,7 @@ object Preferences { sealed class Key(val name: String, val default: Value) { object AutoSync: Key("auto_sync", Value.EnumerationValue(Preferences.AutoSync.Wifi)) object IncompatibleVersions: Key("incompatible_versions", Value.BooleanValue(false)) + object RootInstalation : Key("root_installation",Value.BooleanValue(false)) object ProxyHost: Key("proxy_host", Value.StringValue("localhost")) object ProxyPort: Key("proxy_port", Value.IntValue(9050)) object ProxyType: Key("proxy_type", Value.EnumerationValue(Preferences.ProxyType.Direct)) diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/PreferencesFragment.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/PreferencesFragment.kt index 383f753..6385018 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/PreferencesFragment.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/PreferencesFragment.kt @@ -19,6 +19,7 @@ import android.widget.TextView import android.widget.Toolbar import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment +import com.topjohnwu.superuser.Shell import io.reactivex.rxjava3.disposables.Disposable import nya.kitsunyan.foxydroid.R import nya.kitsunyan.foxydroid.content.Preferences @@ -82,6 +83,8 @@ class PreferencesFragment: ScreenFragment() { is Preferences.Theme.Dark -> getString(R.string.dark) } } + if (Shell.getShell().isRoot) addSwitch(Preferences.Key.RootInstalation, getString(R.string.root_installation), + getString(R.string.root_installation_summary)) addSwitch(Preferences.Key.IncompatibleVersions, getString(R.string.incompatible_versions), getString(R.string.incompatible_versions_summary)) } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 6dcf864..fb7988a 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -163,5 +163,7 @@ Versions Waiting to start download Website + Root installation + Install apps automatically using root permission From d1d3ebe11875368b6328eb2c7392a80149f6d097 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Thu, 16 Sep 2021 10:19:50 +0200 Subject: [PATCH 10/24] Add: Root installation --- .../foxydroid/screen/ScreenActivity.kt | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ScreenActivity.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ScreenActivity.kt index 2466e1c..6210a2c 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ScreenActivity.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ScreenActivity.kt @@ -12,6 +12,7 @@ import android.widget.FrameLayout import android.widget.Toolbar import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity +import com.topjohnwu.superuser.Shell import nya.kitsunyan.foxydroid.R import nya.kitsunyan.foxydroid.content.Cache import nya.kitsunyan.foxydroid.content.Preferences @@ -21,6 +22,7 @@ import nya.kitsunyan.foxydroid.utility.Utils import nya.kitsunyan.foxydroid.utility.extension.android.* import nya.kitsunyan.foxydroid.utility.extension.resources.* import nya.kitsunyan.foxydroid.utility.extension.text.* +import java.io.File abstract class ScreenActivity: FragmentActivity() { companion object { @@ -230,17 +232,36 @@ abstract class ScreenActivity: FragmentActivity() { } internal fun startPackageInstaller(cacheFileName: String) { - val (uri, flags) = if (Android.sdk(24)) { - Pair(Cache.getReleaseUri(this, cacheFileName), Intent.FLAG_GRANT_READ_URI_PERMISSION) + if (Preferences[Preferences.Key.RootInstalation] && Shell.getShell().isRoot) { + val commandBuilder = StringBuilder() + // disable verify apps over usb + commandBuilder.append("settings put global verifier_verify_adb_installs 0 ; ") + // Install main package + commandBuilder.append( + getPackageInstallCommand(Cache.getReleaseFile(this, cacheFileName)) + ) + // re-enable verify apps over usb after install + commandBuilder.append(" ; settings put global verifier_verify_adb_installs 1") + val result = Shell.su(commandBuilder.toString()).exec() } else { - Pair(Uri.fromFile(Cache.getReleaseFile(this, cacheFileName)), 0) + val (uri, flags) = if (Android.sdk(24)) { + Pair(Cache.getReleaseUri(this, cacheFileName), Intent.FLAG_GRANT_READ_URI_PERMISSION) + } else { + Pair(Uri.fromFile(Cache.getReleaseFile(this, cacheFileName)), 0) + } + // TODO Handle deprecation + @Suppress("DEPRECATION") + startActivity( + Intent(Intent.ACTION_INSTALL_PACKAGE) + .setDataAndType(uri, "application/vnd.android.package-archive").setFlags(flags) + ) } - // TODO Handle deprecation - @Suppress("DEPRECATION") - startActivity(Intent(Intent.ACTION_INSTALL_PACKAGE) - .setDataAndType(uri, "application/vnd.android.package-archive").setFlags(flags)) } + private fun getPackageInstallCommand(apkPath: File): String = + "cat \"${apkPath.absolutePath}\" | pm install -t -r -S ${apkPath.length()}" + + internal fun navigateProduct(packageName: String) = pushFragment(ProductFragment(packageName)) internal fun navigateRepositories() = pushFragment(RepositoriesFragment()) internal fun navigatePreferences() = pushFragment(PreferencesFragment()) From acdfdd8e11d299338381bc349874f997380772bc Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Thu, 16 Sep 2021 10:20:25 +0200 Subject: [PATCH 11/24] Update: True/amoled black dark mode --- src/main/res/values/colors.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/res/values/colors.xml b/src/main/res/values/colors.xml index 1839bce..d1c4aaf 100644 --- a/src/main/res/values/colors.xml +++ b/src/main/res/values/colors.xml @@ -6,7 +6,7 @@ #ff21242b #ff1976d2 #ffff1d18 - #ff111111 + #ff000000 #ff262c38 #ff21242b #ff47a2fc From c7aaa3a70f76db56e89ee014d38f1db2e310e2de Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Thu, 16 Sep 2021 10:20:42 +0200 Subject: [PATCH 12/24] Add: Query all apps permission (needed for SDK30+) --- src/main/AndroidManifest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 2dc6051..cdf1c4d 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -9,6 +9,9 @@ + Date: Fri, 17 Sep 2021 00:27:39 +0200 Subject: [PATCH 13/24] Fix: Root installation key name --- .../kotlin/nya/kitsunyan/foxydroid/content/Preferences.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/content/Preferences.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/content/Preferences.kt index 26a786f..dc5b1ce 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/content/Preferences.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/content/Preferences.kt @@ -15,7 +15,7 @@ object Preferences { private val subject = PublishSubject.create>() - private val keys = sequenceOf(Key.AutoSync, Key.IncompatibleVersions, Key.RootInstalation, Key.ProxyHost, Key.ProxyPort, Key.ProxyType, + private val keys = sequenceOf(Key.AutoSync, Key.IncompatibleVersions, Key.RootInstallation, Key.ProxyHost, Key.ProxyPort, Key.ProxyType, Key.SortOrder, Key.Theme, Key.UpdateNotify, Key.UpdateUnstable).map { Pair(it.name, it) }.toMap() fun init(context: Context) { @@ -82,7 +82,7 @@ object Preferences { sealed class Key(val name: String, val default: Value) { object AutoSync: Key("auto_sync", Value.EnumerationValue(Preferences.AutoSync.Wifi)) object IncompatibleVersions: Key("incompatible_versions", Value.BooleanValue(false)) - object RootInstalation : Key("root_installation",Value.BooleanValue(false)) + object RootInstallation : Key("root_installation",Value.BooleanValue(false)) object ProxyHost: Key("proxy_host", Value.StringValue("localhost")) object ProxyPort: Key("proxy_port", Value.IntValue(9050)) object ProxyType: Key("proxy_type", Value.EnumerationValue(Preferences.ProxyType.Direct)) From 9b1c567915253f0724673171523f1a6869916504 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Fri, 17 Sep 2021 00:28:09 +0200 Subject: [PATCH 14/24] Update: Grey out root installation option when not available --- .../nya/kitsunyan/foxydroid/screen/PreferencesFragment.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/PreferencesFragment.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/PreferencesFragment.kt index 6385018..7f06571 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/PreferencesFragment.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/PreferencesFragment.kt @@ -83,7 +83,7 @@ class PreferencesFragment: ScreenFragment() { is Preferences.Theme.Dark -> getString(R.string.dark) } } - if (Shell.getShell().isRoot) addSwitch(Preferences.Key.RootInstalation, getString(R.string.root_installation), + addSwitch(Preferences.Key.RootInstallation, getString(R.string.root_installation), getString(R.string.root_installation_summary)) addSwitch(Preferences.Key.IncompatibleVersions, getString(R.string.incompatible_versions), getString(R.string.incompatible_versions_summary)) @@ -113,6 +113,7 @@ class PreferencesFragment: ScreenFragment() { preferences[Preferences.Key.ProxyHost]?.setEnabled(enabled) preferences[Preferences.Key.ProxyPort]?.setEnabled(enabled) } + preferences[Preferences.Key.RootInstallation]?.setEnabled(Shell.getShell().isRoot) if (key == Preferences.Key.Theme) { requireActivity().recreate() } From 15242ead9d4189cc6d2efbbbd0915d65e8e452b3 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Fri, 17 Sep 2021 00:29:14 +0200 Subject: [PATCH 15/24] Update: Allow root installation in background even when in other Activities as ScreenActivity --- .../kitsunyan/foxydroid/service/DownloadService.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/service/DownloadService.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/service/DownloadService.kt index 7c4c4e2..c37b56c 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/service/DownloadService.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/service/DownloadService.kt @@ -9,6 +9,7 @@ import android.content.Intent import android.net.Uri import android.view.ContextThemeWrapper import androidx.core.app.NotificationCompat +import com.topjohnwu.superuser.Shell import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.disposables.Disposable @@ -18,6 +19,7 @@ import nya.kitsunyan.foxydroid.Common import nya.kitsunyan.foxydroid.MainActivity import nya.kitsunyan.foxydroid.R import nya.kitsunyan.foxydroid.content.Cache +import nya.kitsunyan.foxydroid.content.Preferences import nya.kitsunyan.foxydroid.entity.Release import nya.kitsunyan.foxydroid.entity.Repository import nya.kitsunyan.foxydroid.network.Downloader @@ -234,9 +236,12 @@ class DownloadService: ConnectionService() { private fun publishSuccess(task: Task) { var consumed = false stateSubject.onNext(State.Success(task.packageName, task.name, task.release) { consumed = true }) - if (!consumed) { - showNotificationInstall(task) - } + if (consumed || (Preferences[Preferences.Key.RootInstallation] && Shell.getShell().isRoot)) + PendingIntent.getBroadcast(this, 0, Intent(this, Receiver::class.java) + .setAction("$ACTION_INSTALL.${task.packageName}") + .putExtra(EXTRA_CACHE_FILE_NAME, task.release.cacheFileName), PendingIntent.FLAG_UPDATE_CURRENT) + .send() + else showNotificationInstall(task) } private fun validatePackage(task: Task, file: File): ValidationError? { From 6057637df2a8906f6f27393fbca72cad1ddd519b Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Fri, 17 Sep 2021 00:30:52 +0200 Subject: [PATCH 16/24] Update: Make startPackageInstaller an extension of Activity. Add: Clean up cached apk after install --- .../foxydroid/screen/ProductFragment.kt | 1 + .../foxydroid/screen/ScreenActivity.kt | 39 +----------- .../nya/kitsunyan/foxydroid/utility/Utils.kt | 59 +++++++++++++++++++ 3 files changed, 62 insertions(+), 37 deletions(-) diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt index d223f86..e4db0af 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt @@ -34,6 +34,7 @@ import nya.kitsunyan.foxydroid.service.Connection import nya.kitsunyan.foxydroid.service.DownloadService import nya.kitsunyan.foxydroid.utility.RxUtils import nya.kitsunyan.foxydroid.utility.Utils +import nya.kitsunyan.foxydroid.utility.Utils.startPackageInstaller import nya.kitsunyan.foxydroid.utility.extension.android.* import nya.kitsunyan.foxydroid.widget.DividerItemDecoration diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ScreenActivity.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ScreenActivity.kt index 6210a2c..f5c264d 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ScreenActivity.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ScreenActivity.kt @@ -2,7 +2,6 @@ package nya.kitsunyan.foxydroid.screen import android.content.Context import android.content.Intent -import android.net.Uri import android.os.Bundle import android.os.Parcel import android.view.View @@ -12,17 +11,14 @@ import android.widget.FrameLayout import android.widget.Toolbar import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity -import com.topjohnwu.superuser.Shell import nya.kitsunyan.foxydroid.R -import nya.kitsunyan.foxydroid.content.Cache import nya.kitsunyan.foxydroid.content.Preferences import nya.kitsunyan.foxydroid.database.CursorOwner import nya.kitsunyan.foxydroid.utility.KParcelable import nya.kitsunyan.foxydroid.utility.Utils -import nya.kitsunyan.foxydroid.utility.extension.android.* +import nya.kitsunyan.foxydroid.utility.Utils.startPackageInstaller import nya.kitsunyan.foxydroid.utility.extension.resources.* import nya.kitsunyan.foxydroid.utility.extension.text.* -import java.io.File abstract class ScreenActivity: FragmentActivity() { companion object { @@ -210,7 +206,7 @@ abstract class ScreenActivity: FragmentActivity() { if (fragment !is ProductFragment || fragment.packageName != packageName) { pushFragment(ProductFragment(packageName)) } - specialIntent.cacheFileName?.let(::startPackageInstaller) + specialIntent.cacheFileName?.let { startPackageInstaller(it) } } Unit } @@ -231,37 +227,6 @@ abstract class ScreenActivity: FragmentActivity() { } } - internal fun startPackageInstaller(cacheFileName: String) { - if (Preferences[Preferences.Key.RootInstalation] && Shell.getShell().isRoot) { - val commandBuilder = StringBuilder() - // disable verify apps over usb - commandBuilder.append("settings put global verifier_verify_adb_installs 0 ; ") - // Install main package - commandBuilder.append( - getPackageInstallCommand(Cache.getReleaseFile(this, cacheFileName)) - ) - // re-enable verify apps over usb after install - commandBuilder.append(" ; settings put global verifier_verify_adb_installs 1") - val result = Shell.su(commandBuilder.toString()).exec() - } else { - val (uri, flags) = if (Android.sdk(24)) { - Pair(Cache.getReleaseUri(this, cacheFileName), Intent.FLAG_GRANT_READ_URI_PERMISSION) - } else { - Pair(Uri.fromFile(Cache.getReleaseFile(this, cacheFileName)), 0) - } - // TODO Handle deprecation - @Suppress("DEPRECATION") - startActivity( - Intent(Intent.ACTION_INSTALL_PACKAGE) - .setDataAndType(uri, "application/vnd.android.package-archive").setFlags(flags) - ) - } - } - - private fun getPackageInstallCommand(apkPath: File): String = - "cat \"${apkPath.absolutePath}\" | pm install -t -r -S ${apkPath.length()}" - - internal fun navigateProduct(packageName: String) = pushFragment(ProductFragment(packageName)) internal fun navigateRepositories() = pushFragment(RepositoriesFragment()) internal fun navigatePreferences() = pushFragment(PreferencesFragment()) diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/utility/Utils.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/utility/Utils.kt index e6d72d6..f76892f 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/utility/Utils.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/utility/Utils.kt @@ -1,17 +1,25 @@ package nya.kitsunyan.foxydroid.utility import android.animation.ValueAnimator +import android.app.Activity import android.content.Context +import android.content.Intent import android.content.pm.Signature import android.content.res.Configuration import android.graphics.drawable.Drawable +import android.net.Uri import android.os.LocaleList import android.provider.Settings +import android.util.Log +import com.topjohnwu.superuser.Shell import nya.kitsunyan.foxydroid.BuildConfig import nya.kitsunyan.foxydroid.R +import nya.kitsunyan.foxydroid.content.Cache +import nya.kitsunyan.foxydroid.content.Preferences import nya.kitsunyan.foxydroid.utility.extension.android.* import nya.kitsunyan.foxydroid.utility.extension.resources.* import nya.kitsunyan.foxydroid.utility.extension.text.* +import java.io.File import java.security.MessageDigest import java.security.cert.Certificate import java.security.cert.CertificateEncodingException @@ -97,4 +105,55 @@ object Utils { Settings.Global.getFloat(context.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1f) != 0f } } + + fun quote(string: String) = "\"${string.replace(Regex("""[\\$"`]""")) { c -> "\\${c.value}" }}\"" + + internal fun Activity.startPackageInstaller(cacheFileName: String) { + if (Preferences[Preferences.Key.RootInstallation] && Shell.getShell().isRoot) { + val releaseFile = Cache.getReleaseFile(this, cacheFileName) + val commandBuilder = StringBuilder() + // disable verify apps over usb + commandBuilder.append("settings put global verifier_verify_adb_installs 0 ; ") + // Install main package + commandBuilder.append(getPackageInstallCommand(releaseFile)) + // re-enable verify apps over usb after install + commandBuilder.append(" ; settings put global verifier_verify_adb_installs 1") + val result = Shell.su(commandBuilder.toString()).exec() + if (result.isSuccess) Shell.su("${getUtilBoxPath()} rm ${quote(releaseFile.absolutePath)}") + } else { + val (uri, flags) = if (Android.sdk(24)) { + Pair(Cache.getReleaseUri(this, cacheFileName), Intent.FLAG_GRANT_READ_URI_PERMISSION) + } else { + Pair(Uri.fromFile(Cache.getReleaseFile(this, cacheFileName)), 0) + } + // TODO Handle deprecation + @Suppress("DEPRECATION") + startActivity( + Intent(Intent.ACTION_INSTALL_PACKAGE) + .setDataAndType(uri, "application/vnd.android.package-archive").setFlags(flags) + ) + } + } + + private fun getPackageInstallCommand(apkPath: File): String = + "cat \"${apkPath.absolutePath}\" | pm install -t -r -S ${apkPath.length()}" + + private fun getUtilBoxPath(): String { + listOf("toybox", "busybox").forEach { + var shellResult = Shell.su("which $it").exec() + if (shellResult.out.isNotEmpty()) { + val utilBoxPath = shellResult.out.joinToString("") + if (utilBoxPath.isNotEmpty()) { + val utilBoxQuoted = quote(utilBoxPath) + shellResult = Shell.su("$utilBoxQuoted --version").exec() + if (shellResult.out.isNotEmpty()) { + val utilBoxVersion = shellResult.out.joinToString("") + Log.i(this.javaClass.canonicalName,"Using Utilbox $it : $utilBoxQuoted $utilBoxVersion") + } + return utilBoxQuoted + } + } + } + return "" + } } From 032e9999c109a3e2f64fc65069ae63ad17f06899 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Fri, 17 Sep 2021 01:33:42 +0200 Subject: [PATCH 17/24] Add: 23 repositories to default --- .../kitsunyan/foxydroid/entity/Repository.kt | 94 ++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/entity/Repository.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/entity/Repository.kt index 6debcf0..0a5feb1 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/entity/Repository.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/entity/Repository.kt @@ -107,12 +107,104 @@ data class Repository(val id: Long, val address: String, val mirrors: List Date: Fri, 17 Sep 2021 01:34:07 +0200 Subject: [PATCH 18/24] Update: Sort default repositories by name --- src/main/kotlin/nya/kitsunyan/foxydroid/database/Database.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/database/Database.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/database/Database.kt index 7b7a24d..29a233e 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/database/Database.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/database/Database.kt @@ -22,7 +22,7 @@ object Database { val helper = Helper(context) db = helper.writableDatabase if (helper.created) { - for (repository in Repository.defaultRepositories) { + for (repository in Repository.defaultRepositories.sortedBy { it.name }) { RepositoryAdapter.put(repository) } } From c5f3f18d4ef8f3b57aab5b3c558acc397dcc8db4 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Tue, 28 Sep 2021 01:17:17 +0200 Subject: [PATCH 19/24] Update: Don't open app's page after installing/updating --- .../kotlin/nya/kitsunyan/foxydroid/screen/ScreenActivity.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ScreenActivity.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ScreenActivity.kt index f5c264d..b75d00e 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ScreenActivity.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ScreenActivity.kt @@ -202,10 +202,6 @@ abstract class ScreenActivity: FragmentActivity() { is SpecialIntent.Install -> { val packageName = specialIntent.packageName if (!packageName.isNullOrEmpty()) { - val fragment = currentFragment - if (fragment !is ProductFragment || fragment.packageName != packageName) { - pushFragment(ProductFragment(packageName)) - } specialIntent.cacheFileName?.let { startPackageInstaller(it) } } Unit From 4253c5d0f56b5d0324a5b7edc9b60c7aab025a74 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Tue, 28 Sep 2021 01:19:16 +0200 Subject: [PATCH 20/24] Update: Move toInstalledItem and abstract install/update action to Utils --- .../kitsunyan/foxydroid/MainApplication.kt | 8 +---- .../foxydroid/screen/ProductFragment.kt | 18 +---------- .../nya/kitsunyan/foxydroid/utility/Utils.kt | 30 +++++++++++++++++++ 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/MainApplication.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/MainApplication.kt index 4a2de84..ef71399 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/MainApplication.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/MainApplication.kt @@ -9,31 +9,25 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.IntentFilter -import android.content.pm.PackageInfo import com.squareup.picasso.OkHttp3Downloader import com.squareup.picasso.Picasso import nya.kitsunyan.foxydroid.content.Cache import nya.kitsunyan.foxydroid.content.Preferences import nya.kitsunyan.foxydroid.content.ProductPreferences import nya.kitsunyan.foxydroid.database.Database -import nya.kitsunyan.foxydroid.entity.InstalledItem import nya.kitsunyan.foxydroid.index.RepositoryUpdater import nya.kitsunyan.foxydroid.network.Downloader import nya.kitsunyan.foxydroid.network.PicassoDownloader import nya.kitsunyan.foxydroid.service.Connection import nya.kitsunyan.foxydroid.service.SyncService import nya.kitsunyan.foxydroid.utility.Utils +import nya.kitsunyan.foxydroid.utility.Utils.toInstalledItem import nya.kitsunyan.foxydroid.utility.extension.android.* import java.net.InetSocketAddress import java.net.Proxy @Suppress("unused") class MainApplication: Application() { - private fun PackageInfo.toInstalledItem(): InstalledItem { - val signatureString = singleSignature?.let(Utils::calculateHash).orEmpty() - return InstalledItem(packageName, versionName.orEmpty(), versionCodeCompat, signatureString) - } - override fun attachBaseContext(base: Context) { super.attachBaseContext(Utils.configureLocale(base)) } diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt index e4db0af..085f2dc 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt @@ -333,23 +333,7 @@ class ProductFragment(): ScreenFragment(), ProductAdapter.Callbacks { ProductAdapter.Action.INSTALL, ProductAdapter.Action.UPDATE -> { val installedItem = installed?.installedItem - val productRepository = Product.findSuggested(products, installedItem) { it.first } - val compatibleReleases = productRepository?.first?.selectedReleases.orEmpty() - .filter { installedItem == null || installedItem.signature == it.signature } - val release = if (compatibleReleases.size >= 2) { - compatibleReleases - .filter { it.platforms.contains(Android.primaryPlatform) } - .minByOrNull { it.platforms.size } - ?: compatibleReleases.minByOrNull { it.platforms.size } - ?: compatibleReleases.firstOrNull() - } else { - compatibleReleases.firstOrNull() - } - val binder = downloadConnection.binder - if (productRepository != null && release != null && binder != null) { - binder.enqueue(packageName, productRepository.first.name, productRepository.second, release) - } - Unit + Utils.startInstallUpdateAction(installedItem, products, downloadConnection) } ProductAdapter.Action.LAUNCH -> { val launcherActivities = installed?.launcherActivities.orEmpty() diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/utility/Utils.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/utility/Utils.kt index f76892f..4579919 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/utility/Utils.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/utility/Utils.kt @@ -4,6 +4,7 @@ import android.animation.ValueAnimator import android.app.Activity import android.content.Context import android.content.Intent +import android.content.pm.PackageInfo import android.content.pm.Signature import android.content.res.Configuration import android.graphics.drawable.Drawable @@ -16,6 +17,11 @@ import nya.kitsunyan.foxydroid.BuildConfig import nya.kitsunyan.foxydroid.R import nya.kitsunyan.foxydroid.content.Cache import nya.kitsunyan.foxydroid.content.Preferences +import nya.kitsunyan.foxydroid.entity.InstalledItem +import nya.kitsunyan.foxydroid.entity.Product +import nya.kitsunyan.foxydroid.entity.Repository +import nya.kitsunyan.foxydroid.service.Connection +import nya.kitsunyan.foxydroid.service.DownloadService import nya.kitsunyan.foxydroid.utility.extension.android.* import nya.kitsunyan.foxydroid.utility.extension.resources.* import nya.kitsunyan.foxydroid.utility.extension.text.* @@ -156,4 +162,28 @@ object Utils { } return "" } + + fun PackageInfo.toInstalledItem(): InstalledItem { + val signatureString = singleSignature?.let(Utils::calculateHash).orEmpty() + return InstalledItem(packageName, versionName.orEmpty(), versionCodeCompat, signatureString) + } + + fun startInstallUpdateAction(installedItem: InstalledItem?, products: List>, downloadConnection: Connection) { + val pairProductRepository = Product.findSuggested(products, installedItem) { it.first } + val compatibleReleases = pairProductRepository?.first?.selectedReleases.orEmpty() + .filter { installedItem == null || installedItem.signature == it.signature } + val release = if (compatibleReleases.size >= 2) { + compatibleReleases + .filter { it.platforms.contains(Android.primaryPlatform) } + .minByOrNull { it.platforms.size } + ?: compatibleReleases.minByOrNull { it.platforms.size } + ?: compatibleReleases.firstOrNull() + } else { + compatibleReleases.firstOrNull() + } + val binder = downloadConnection.binder + if (pairProductRepository != null && release != null && binder != null) { + binder.enqueue(installedItem?.packageName ?: "", pairProductRepository.first.name, pairProductRepository.second, release) + } + } } From 6bfb4376469c93e6bc0f447c020431c781106da7 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Tue, 28 Sep 2021 01:21:43 +0200 Subject: [PATCH 21/24] Update: Update icon --- .../nya/kitsunyan/foxydroid/screen/ProductFragment.kt | 2 +- src/main/res/drawable/ic_update.xml | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 src/main/res/drawable/ic_update.xml diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt index 085f2dc..27feef4 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductFragment.kt @@ -56,7 +56,7 @@ class ProductFragment(): ScreenFragment(), ProductAdapter.Callbacks { private enum class Action(val id: Int, val adapterAction: ProductAdapter.Action, val iconResId: Int) { INSTALL(1, ProductAdapter.Action.INSTALL, R.drawable.ic_archive), - UPDATE(2, ProductAdapter.Action.UPDATE, R.drawable.ic_archive), + UPDATE(2, ProductAdapter.Action.UPDATE, R.drawable.ic_update), LAUNCH(3, ProductAdapter.Action.LAUNCH, R.drawable.ic_launch), DETAILS(4, ProductAdapter.Action.DETAILS, R.drawable.ic_tune), UNINSTALL(5, ProductAdapter.Action.UNINSTALL, R.drawable.ic_delete) diff --git a/src/main/res/drawable/ic_update.xml b/src/main/res/drawable/ic_update.xml new file mode 100644 index 0000000..81af728 --- /dev/null +++ b/src/main/res/drawable/ic_update.xml @@ -0,0 +1,9 @@ + + + From 8b680320807ae1dcfbe5fa68cc5414d02579fcc5 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Tue, 28 Sep 2021 01:24:12 +0200 Subject: [PATCH 22/24] Add: Update all (skeleton) The codebase has some structural design problems and so needs some huge refactoring. --- .../kitsunyan/foxydroid/database/Database.kt | 1 + .../foxydroid/screen/ProductsFragment.kt | 8 +-- .../foxydroid/screen/TabsFragment.kt | 55 ++++++++++++++----- src/main/res/layout/fragment.xml | 10 ++++ src/main/res/values/strings.xml | 1 + 5 files changed, 58 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/database/Database.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/database/Database.kt index 29a233e..ab61b31 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/database/Database.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/database/Database.kt @@ -17,6 +17,7 @@ import nya.kitsunyan.foxydroid.utility.extension.android.* import nya.kitsunyan.foxydroid.utility.extension.json.* import java.io.ByteArrayOutputStream +// TODO migrate to Room object Database { fun init(context: Context): Boolean { val helper = Helper(context) diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductsFragment.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductsFragment.kt index 7af8a19..1cca4ac 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductsFragment.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/ProductsFragment.kt @@ -30,10 +30,10 @@ class ProductsFragment(): ScreenFragment(), CursorOwner.Callback { private const val STATE_LAYOUT_MANAGER = "layoutManager" } - enum class Source(val titleResId: Int, val sections: Boolean, val order: Boolean) { - AVAILABLE(R.string.available, true, true), - INSTALLED(R.string.installed, false, false), - UPDATES(R.string.updates, false, false) + enum class Source(val titleResId: Int, val sections: Boolean, val order: Boolean, val updates: Boolean) { + AVAILABLE(R.string.available, true, true, false), + INSTALLED(R.string.installed, false, false, false), + UPDATES(R.string.updates, false, false, true) } constructor(source: Source): this() { diff --git a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/TabsFragment.kt b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/TabsFragment.kt index 61a2b6a..f973d77 100644 --- a/src/main/kotlin/nya/kitsunyan/foxydroid/screen/TabsFragment.kt +++ b/src/main/kotlin/nya/kitsunyan/foxydroid/screen/TabsFragment.kt @@ -1,7 +1,9 @@ package nya.kitsunyan.foxydroid.screen import android.animation.ValueAnimator +import android.app.AlertDialog import android.content.Context +import android.content.DialogInterface import android.content.res.ColorStateList import android.graphics.Canvas import android.graphics.ColorFilter @@ -16,13 +18,9 @@ import android.view.View import android.view.ViewGroup import android.view.animation.AccelerateInterpolator import android.view.animation.DecelerateInterpolator -import android.widget.FrameLayout -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.SearchView -import android.widget.TextView -import android.widget.Toolbar +import android.widget.* import androidx.fragment.app.Fragment +import androidx.fragment.app.findFragment import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.adapter.FragmentStateAdapter @@ -33,6 +31,7 @@ import io.reactivex.rxjava3.disposables.Disposable import io.reactivex.rxjava3.schedulers.Schedulers import nya.kitsunyan.foxydroid.R import nya.kitsunyan.foxydroid.content.Preferences +import nya.kitsunyan.foxydroid.database.CursorOwner import nya.kitsunyan.foxydroid.database.Database import nya.kitsunyan.foxydroid.entity.ProductItem import nya.kitsunyan.foxydroid.service.Connection @@ -61,6 +60,7 @@ class TabsFragment: ScreenFragment() { val sectionChange = view.findViewById(R.id.section_change)!! val sectionName = view.findViewById(R.id.section_name)!! val sectionIcon = view.findViewById(R.id.section_icon)!! + val updateAll = view.findViewById