From 5577f9978e9a5f9c8faeaa54a1ff521f5c13627f Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Wed, 30 Oct 2024 13:00:50 +0500 Subject: [PATCH 01/20] migrate to vanniktech/gradle-maven-publish-plugin --- .github/workflows/ci.yml | 13 +- build-logic/build.gradle.kts | 4 +- .../publishing/AckpineLibraryPublishPlugin.kt | 113 ++++++++---------- .../publishing/AckpinePublishingPlugin.kt | 46 +------ gradle/libs.versions.toml | 2 +- 5 files changed, 58 insertions(+), 120 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 47c3bda78..d43a32b2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,14 +53,13 @@ jobs: - name: Publish run: | - ./gradlew publishReleasePublicationToSonatypeRepository --max-workers 1 closeAndReleaseSonatypeStagingRepository + ./gradlew publishAndReleaseToMavenCentral --no-configuration-cache --max-workers 1 env: - OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} - OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} - SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} - SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} - SIGNING_KEY: ${{ secrets.SIGNING_KEY }} - SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }} + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.OSSRH_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.OSSRH_PASSWORD }} + ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.SIGNING_KEY_ID }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_KEY }} publish-docs: name: Publish documentation diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index 4a8207481..dbf17b06c 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Ilya Fomichev + * Copyright (C) 2023-2024 Ilya Fomichev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ gradlePlugin { dependencies { implementation(libs.plugin.agp) implementation(libs.plugin.kotlin.android) - implementation(libs.plugin.nexus.publish) + implementation(libs.plugin.gradleMavenPublish) implementation(libs.plugin.dokka) implementation(libs.plugin.binaryCompatibilityValidator) } \ No newline at end of file diff --git a/build-logic/src/main/kotlin/ru/solrudev/ackpine/gradle/publishing/AckpineLibraryPublishPlugin.kt b/build-logic/src/main/kotlin/ru/solrudev/ackpine/gradle/publishing/AckpineLibraryPublishPlugin.kt index 365a7b94b..e95ee3bcc 100644 --- a/build-logic/src/main/kotlin/ru/solrudev/ackpine/gradle/publishing/AckpineLibraryPublishPlugin.kt +++ b/build-logic/src/main/kotlin/ru/solrudev/ackpine/gradle/publishing/AckpineLibraryPublishPlugin.kt @@ -16,47 +16,42 @@ package ru.solrudev.ackpine.gradle.publishing -import com.android.build.gradle.LibraryExtension +import com.vanniktech.maven.publish.AndroidSingleVariantLibrary +import com.vanniktech.maven.publish.MavenPublishBaseExtension +import com.vanniktech.maven.publish.MavenPublishPlugin +import com.vanniktech.maven.publish.SonatypeHost import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.publish.PublishingExtension -import org.gradle.api.publish.maven.MavenPublication -import org.gradle.api.publish.maven.plugins.MavenPublishPlugin import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.assign import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.create -import org.gradle.kotlin.dsl.extra import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.hasPlugin import org.gradle.kotlin.dsl.withType -import org.gradle.plugins.signing.SigningExtension -import org.gradle.plugins.signing.SigningPlugin import org.jetbrains.dokka.gradle.DokkaPlugin import org.jetbrains.dokka.gradle.DokkaTaskPartial import ru.solrudev.ackpine.gradle.AckpineArtifact import ru.solrudev.ackpine.gradle.AckpineExtension import ru.solrudev.ackpine.gradle.AckpineLibraryPlugin -import ru.solrudev.ackpine.gradle.Constants public class AckpineLibraryPublishPlugin : Plugin { override fun apply(target: Project): Unit = target.run { - if (rootProject.plugins.hasPlugin(AckpinePublishingPlugin::class)) { - pluginManager.run { - apply(MavenPublishPlugin::class) - apply(SigningPlugin::class) - apply(DokkaPlugin::class) - } - val ackpineExtension = extensions.getByType() - val artifact = ackpineExtension.extensions.create("artifact") - configureDokka(artifact) - configurePublishing(ackpineExtension, artifact) - configureSigning() + check(rootProject.plugins.hasPlugin(AckpinePublishingPlugin::class)) { + "Applying library-publish plugin requires the publishing plugin to be applied to the root project" + } + check(plugins.hasPlugin(AckpineLibraryPlugin::class)) { + "Applying library-publish plugin requires the library plugin to be applied" } - if (plugins.hasPlugin(AckpineLibraryPlugin::class)) { - configureSourcesJar() + pluginManager.run { + apply(MavenPublishPlugin::class) + apply(DokkaPlugin::class) } + val ackpineExtension = extensions.getByType() + val artifact = ackpineExtension.extensions.create("artifact") + configureDokka(artifact) + configurePublishing(ackpineExtension, artifact) } private fun Project.configureDokka(artifact: AckpineArtifact) = afterEvaluate { @@ -68,57 +63,45 @@ public class AckpineLibraryPublishPlugin : Plugin { private fun Project.configurePublishing( ackpineExtension: AckpineExtension, artifact: AckpineArtifact - ) = afterEvaluate { - extensions.configure { - publications { - create("release") { - groupId = this@afterEvaluate.group.toString() - artifactId = "ackpine-${ackpineExtension.id}" - version = this@afterEvaluate.version.toString() - from(components.getByName("release")) - - pom { - name = artifact.name - description = this@afterEvaluate.description - url = "https://ackpine.solrudev.ru" + ) = extensions.configure { + configure( + AndroidSingleVariantLibrary( + variant = "release", + sourcesJar = true, + publishJavadocJar = false + ) + ) + publishToMavenCentral(SonatypeHost.S01) + signAllPublications() - licenses { - license { - name = "The Apache Software License, Version 2.0" - url = "https://www.apache.org/licenses/LICENSE-2.0.txt" - } - } + afterEvaluate { + coordinates(group.toString(), artifactId = "ackpine-${ackpineExtension.id}", version.toString()) - developers { - developer { - id = "solrudev" - name = "Ilya Fomichev" - } - } + pom { + name = artifact.name + description = this@afterEvaluate.description + inceptionYear = "2023" + url = "https://ackpine.solrudev.ru" - scm { - connection = "scm:git:github.com/solrudev/Ackpine.git" - developerConnection = "scm:git:ssh://github.com/solrudev/Ackpine.git" - url = "https://github.com/solrudev/Ackpine/tree/master" - } + licenses { + license { + name = "The Apache Software License, Version 2.0" + url = "https://www.apache.org/licenses/LICENSE-2.0.txt" } } - } - } - } - private fun Project.configureSigning() = extensions.configure { - val keyId = rootProject.extra[Constants.signingKeyId] as String - val key = rootProject.extra[Constants.signingKey] as String - val password = rootProject.extra[Constants.signingPassword] as String - useInMemoryPgpKeys(keyId, key, password) - sign(extensions.getByType().publications) - } + developers { + developer { + id = "solrudev" + name = "Ilya Fomichev" + } + } - private fun Project.configureSourcesJar() = extensions.configure { - publishing { - singleVariant("release") { - withSourcesJar() + scm { + connection = "scm:git:github.com/solrudev/Ackpine.git" + developerConnection = "scm:git:ssh://github.com/solrudev/Ackpine.git" + url = "https://github.com/solrudev/Ackpine/tree/master" + } } } } diff --git a/build-logic/src/main/kotlin/ru/solrudev/ackpine/gradle/publishing/AckpinePublishingPlugin.kt b/build-logic/src/main/kotlin/ru/solrudev/ackpine/gradle/publishing/AckpinePublishingPlugin.kt index cf3bd16a0..f99035ee8 100644 --- a/build-logic/src/main/kotlin/ru/solrudev/ackpine/gradle/publishing/AckpinePublishingPlugin.kt +++ b/build-logic/src/main/kotlin/ru/solrudev/ackpine/gradle/publishing/AckpinePublishingPlugin.kt @@ -17,21 +17,17 @@ package ru.solrudev.ackpine.gradle.publishing import com.android.build.gradle.LibraryExtension -import io.github.gradlenexus.publishplugin.NexusPublishExtension -import io.github.gradlenexus.publishplugin.NexusPublishPlugin import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.assign import org.gradle.kotlin.dsl.configure -import org.gradle.kotlin.dsl.extra import org.gradle.kotlin.dsl.hasPlugin import org.gradle.kotlin.dsl.withType import org.jetbrains.dokka.gradle.DokkaMultiModuleTask import org.jetbrains.dokka.gradle.DokkaPlugin import ru.solrudev.ackpine.gradle.AckpineLibraryPlugin import ru.solrudev.ackpine.gradle.Constants -import ru.solrudev.ackpine.gradle.helpers.withProperties import ru.solrudev.ackpine.gradle.versioning.getVersionFromPropertiesFile public class AckpinePublishingPlugin : Plugin { @@ -40,15 +36,11 @@ public class AckpinePublishingPlugin : Plugin { require(this == rootProject) { "Plugin must be applied to the root project but was applied to $path" } group = Constants.PACKAGE_NAME version = getVersionFromPropertiesFile().toString() - pluginManager.run { - apply(NexusPublishPlugin::class) - apply(DokkaPlugin::class) - } + pluginManager.apply(DokkaPlugin::class) tasks.withType().configureEach { outputDirectory = layout.projectDirectory.dir("docs/api") } registerBuildAckpineTask() - configurePublishing() } private fun Project.registerBuildAckpineTask() = tasks.register("buildAckpine") { @@ -64,40 +56,4 @@ public class AckpinePublishingPlugin : Plugin { } } } - - private fun Project.configurePublishing() { - val publishingProperties = publishingFromPropertiesFile() - val ossrhUsername = System.getenv("OSSRH_USERNAME") - ?: publishingProperties["ossrhUsername"] - val ossrhPassword = System.getenv("OSSRH_PASSWORD") - ?: publishingProperties["ossrhPassword"] - val sonatypeStagingProfileId = System.getenv("SONATYPE_STAGING_PROFILE_ID") - ?: publishingProperties["sonatypeStagingProfileId"] - extra[Constants.signingKeyId] = System.getenv("SIGNING_KEY_ID") - ?: publishingProperties["signing.keyId"].orEmpty() - extra[Constants.signingKey] = System.getenv("SIGNING_KEY") - ?: publishingProperties["signing.key"].orEmpty() - extra[Constants.signingPassword] = System.getenv("SIGNING_PASSWORD") - ?: publishingProperties["signing.password"].orEmpty() - extensions.configure { - repositories { - sonatype { - stagingProfileId = sonatypeStagingProfileId - username = ossrhUsername - password = ossrhPassword - nexusUrl = uri("https://s01.oss.sonatype.org/service/local/") - snapshotRepositoryUrl = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/") - } - } - } - } - - private fun Project.publishingFromPropertiesFile() = buildMap map@{ - val secretPropertiesFile = file("local.properties") - if (secretPropertiesFile.exists()) { - secretPropertiesFile.withProperties { - forEach { name, value -> this@map.put(name as String, value as String) } - } - } - } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 921f1841f..804ceb0f3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ kotlin-ksp = "2.0.20-1.0.25" [libraries] materialcomponents = { module = "com.google.android.material:material", version = "1.12.0" } -plugin-nexus-publish = { module = "io.github.gradle-nexus:publish-plugin", version = "1.3.0" } +plugin-gradleMavenPublish = { module = "com.vanniktech:gradle-maven-publish-plugin", version = "0.30.0" } plugin-agp = { module = "com.android.tools.build:gradle", version.ref = "android-gradleplugin" } plugin-kotlin-android = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } plugin-dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version = "1.9.20" } From 3568e0a2bcd0df50553b3e9435a6c3dca0f478b4 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Wed, 30 Oct 2024 20:38:03 +0500 Subject: [PATCH 02/20] fix absence of install confirmation when returning from system install permission request for session-based installer fix "Session {id} is dead." failure when confirmation activity is dismissed by clicking outside of dialog this is fix for #84 --- .../impl/activity/SessionCommitActivity.kt | 16 +++--- .../activity/SessionBasedInstallActivity.kt | 55 ++++++++++++++++--- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/activity/SessionCommitActivity.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/activity/SessionCommitActivity.kt index 59663f363..49d76cf3a 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/activity/SessionCommitActivity.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/activity/SessionCommitActivity.kt @@ -127,6 +127,14 @@ internal abstract class SessionCommitActivity protected constructor } } + protected fun abortSession() = withCompletableSession { session -> + session?.complete( + Session.State.Failed( + abortedStateFailureFactory("$tag was finished by user") + ) + ) + } + private fun initializeState(savedInstanceState: Bundle?) { if (savedInstanceState != null) { requestCode = savedInstanceState.getInt(REQUEST_CODE_KEY) @@ -159,14 +167,6 @@ internal abstract class SessionCommitActivity protected constructor } } - private fun abortSession() = withCompletableSession { session -> - session?.complete( - Session.State.Failed( - abortedStateFailureFactory("$tag was finished by user") - ) - ) - } - private fun finishActivityOnTerminalSessionState() = ackpineSessionFuture.handleResult { session -> session?.addStateListener(subscriptions) { _, state -> if (state.isTerminal) { diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt index 270b248d7..0a059f33e 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt @@ -18,14 +18,17 @@ package ru.solrudev.ackpine.impl.installer.activity +import android.Manifest.permission.INSTALL_PACKAGES import android.content.Intent import android.content.pm.PackageInstaller +import android.content.pm.PackageManager.PERMISSION_GRANTED import android.os.Build import android.os.Bundle import android.os.Handler import android.os.Looper import androidx.annotation.RequiresApi import androidx.annotation.RestrictTo +import androidx.core.content.ContextCompat import ru.solrudev.ackpine.impl.installer.activity.helpers.getParcelableCompat import ru.solrudev.ackpine.impl.session.helpers.commitSession import ru.solrudev.ackpine.impl.session.helpers.getSessionBasedSessionCommitProgressValue @@ -34,6 +37,7 @@ import ru.solrudev.ackpine.session.Session private const val CONFIRMATION_TAG = "SessionBasedInstallConfirmationActivity" private const val LAUNCHER_TAG = "SessionBasedInstallCommitActivity" +private const val CAN_INSTALL_PACKAGES_KEY = "CAN_INSTALL_PACKAGES" @RestrictTo(RestrictTo.Scope.LIBRARY) internal class SessionBasedInstallCommitActivity : InstallActivity(LAUNCHER_TAG, startsActivity = false) { @@ -54,6 +58,7 @@ internal class SessionBasedInstallConfirmationActivity : InstallActivity(CONFIRM private val sessionId by lazy(LazyThreadSafetyMode.NONE) { getSessionId(CONFIRMATION_TAG) } private val handler = Handler(Looper.getMainLooper()) + private var canInstallPackages = false private val deadSessionCompletionRunnable = Runnable { withCompletableSession { session -> @@ -65,6 +70,7 @@ internal class SessionBasedInstallConfirmationActivity : InstallActivity(CONFIRM override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + canInstallPackages = savedInstanceState?.getBoolean(CAN_INSTALL_PACKAGES_KEY) ?: canInstallPackages() if (savedInstanceState == null) { launchInstallActivity() } @@ -77,30 +83,61 @@ internal class SessionBasedInstallConfirmationActivity : InstallActivity(CONFIRM } } + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + if (isChangingConfigurations) { + outState.putBoolean(CAN_INSTALL_PACKAGES_KEY, canInstallPackages) + } + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode != this.requestCode) { return } + val isActivityCancelled = resultCode == RESULT_CANCELED val sessionInfo = packageInstaller.getSessionInfo(sessionId) - // Hacky workaround: progress not going higher after commit means session is dead. This is needed to complete - // the Ackpine session with failure on reasons which are not handled in PackageInstallerStatusReceiver. - // For example, "There was a problem parsing the package" error falls under that. - val isSessionAlive = sessionInfo != null && sessionInfo.progress >= getSessionBasedSessionCommitProgressValue() - if (!isSessionAlive) { - setLoading(isLoading = true, delayMillis = 100) - handler.postDelayed(deadSessionCompletionRunnable, 1000) - } else { - finish() + val isSessionAlive = sessionInfo != null + val isSessionStuck = sessionInfo != null && sessionInfo.progress < getSessionBasedSessionCommitProgressValue() + val previousCanInstallPackagesValue = canInstallPackages + canInstallPackages = canInstallPackages() + val isInstallPermissionStatusChanged = previousCanInstallPackagesValue != canInstallPackages + // Order of checks is important. + when { + // User has cancelled install permission request or hasn't granted permission. + !canInstallPackages -> { + withCompletableSession { session -> + session?.complete(Session.State.Failed(InstallFailure.Generic("Install permission denied"))) + } + finish() + } + // User hasn't confirmed installation because confirmation activity didn't appear after permission request. + isSessionStuck && isInstallPermissionStatusChanged -> launchInstallActivity() + // Session proceeded normally. + isSessionAlive && !isSessionStuck -> finish() + // User has dismissed confirmation activity. + isSessionAlive && isActivityCancelled -> abortSession() + // There was some error while installing which is not handled in PackageInstallerStatusReceiver, + // or session may have completed too quickly. + else -> { + // Wait for possible result from PackageInstallerStatusReceiver before completing with failure. + setLoading(isLoading = true, delayMillis = 100) + handler.postDelayed(deadSessionCompletionRunnable, 1000) + } } } private fun launchInstallActivity() { + canInstallPackages = canInstallPackages() intent.extras ?.getParcelableCompat(Intent.EXTRA_INTENT) ?.let { confirmationIntent -> startActivityForResult(confirmationIntent, requestCode) } notifySessionCommitted() } + + private fun canInstallPackages() = Build.VERSION.SDK_INT < Build.VERSION_CODES.O + || packageManager.canRequestPackageInstalls() + || ContextCompat.checkSelfPermission(this, INSTALL_PACKAGES) == PERMISSION_GRANTED } private val InstallActivity.packageInstaller: PackageInstaller From 2733d663d8cc71cc2acc8ea0c98b44660fdc817a Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Wed, 30 Oct 2024 22:46:27 +0500 Subject: [PATCH 03/20] don't check isChangingConfigurations --- .../impl/installer/activity/SessionBasedInstallActivity.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt index 0a059f33e..df4c88796 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt @@ -85,9 +85,7 @@ internal class SessionBasedInstallConfirmationActivity : InstallActivity(CONFIRM override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) - if (isChangingConfigurations) { - outState.putBoolean(CAN_INSTALL_PACKAGES_KEY, canInstallPackages) - } + outState.putBoolean(CAN_INSTALL_PACKAGES_KEY, canInstallPackages) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { From b12861e9dc4a9b4f00597fed6e065350c02abd99 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 01:42:04 +0500 Subject: [PATCH 04/20] add comment about repeated confirmation behavior --- .../impl/installer/activity/SessionBasedInstallActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt index df4c88796..9ad173f54 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt @@ -110,6 +110,8 @@ internal class SessionBasedInstallConfirmationActivity : InstallActivity(CONFIRM finish() } // User hasn't confirmed installation because confirmation activity didn't appear after permission request. + // Unfortunately, on some OS versions session may stay stuck if confirmation was dismissed by clicking + // outside of confirmation dialog, so this may lead to repeated confirmation if permission status changes. isSessionStuck && isInstallPermissionStatusChanged -> launchInstallActivity() // Session proceeded normally. isSessionAlive && !isSessionStuck -> finish() From 656bb86a7b0ee79f7bfbddedcec1c828770a7193 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 03:00:25 +0500 Subject: [PATCH 05/20] add comment about stuck update session when requireUserAction is set to false --- .../impl/installer/activity/SessionBasedInstallActivity.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt index 9ad173f54..83a2d6dcd 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt @@ -114,6 +114,10 @@ internal class SessionBasedInstallConfirmationActivity : InstallActivity(CONFIRM // outside of confirmation dialog, so this may lead to repeated confirmation if permission status changes. isSessionStuck && isInstallPermissionStatusChanged -> launchInstallActivity() // Session proceeded normally. + // On API 31-32 in case of requireUserAction = false and if _update_ confirmation was dismissed by clicking + // outside of confirmation dialog, session will stay stuck, unfortunately, because for some reason progress + // gets updated almost like the installation was confirmed even though it wasn't and no result is received + // from PackageInstallerStatusReceiver. isSessionAlive && !isSessionStuck -> finish() // User has dismissed confirmation activity. isSessionAlive && isActivityCancelled -> abortSession() From 0ea77454955e198aaa4d083cef0c7b1003e888e8 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 11:10:16 +0500 Subject: [PATCH 06/20] remove unnecessary super call in onActivityResult() --- .../impl/installer/activity/IntentBasedInstallActivity.kt | 1 - .../impl/installer/activity/SessionBasedInstallActivity.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/IntentBasedInstallActivity.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/IntentBasedInstallActivity.kt index 181666730..b3a789e64 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/IntentBasedInstallActivity.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/IntentBasedInstallActivity.kt @@ -41,7 +41,6 @@ internal class IntentBasedInstallActivity : InstallActivity(TAG, startsActivity } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) if (requestCode != this.requestCode) { return } diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt index 83a2d6dcd..f1c36fed9 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt @@ -89,7 +89,6 @@ internal class SessionBasedInstallConfirmationActivity : InstallActivity(CONFIRM } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) if (requestCode != this.requestCode) { return } From 5fcc34b9586df0a2343a9566aae222de6f447f42 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 11:25:43 +0500 Subject: [PATCH 07/20] fix session not aborting if install confirmation appears immediately after granting install permission on top of install permission screen and when dismissing it via clicking outside of dialog --- .../activity/SessionBasedInstallActivity.kt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt index f1c36fed9..3db3f9adc 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt @@ -19,6 +19,7 @@ package ru.solrudev.ackpine.impl.installer.activity import android.Manifest.permission.INSTALL_PACKAGES +import android.app.ActivityManager import android.content.Intent import android.content.pm.PackageInstaller import android.content.pm.PackageManager.PERMISSION_GRANTED @@ -29,6 +30,7 @@ import android.os.Looper import androidx.annotation.RequiresApi import androidx.annotation.RestrictTo import androidx.core.content.ContextCompat +import androidx.core.content.getSystemService import ru.solrudev.ackpine.impl.installer.activity.helpers.getParcelableCompat import ru.solrudev.ackpine.impl.session.helpers.commitSession import ru.solrudev.ackpine.impl.session.helpers.getSessionBasedSessionCommitProgressValue @@ -38,6 +40,7 @@ import ru.solrudev.ackpine.session.Session private const val CONFIRMATION_TAG = "SessionBasedInstallConfirmationActivity" private const val LAUNCHER_TAG = "SessionBasedInstallCommitActivity" private const val CAN_INSTALL_PACKAGES_KEY = "CAN_INSTALL_PACKAGES" +private const val IS_FIRST_RESUME_KEY = "IS_FIRST_RESUME" @RestrictTo(RestrictTo.Scope.LIBRARY) internal class SessionBasedInstallCommitActivity : InstallActivity(LAUNCHER_TAG, startsActivity = false) { @@ -59,6 +62,8 @@ internal class SessionBasedInstallConfirmationActivity : InstallActivity(CONFIRM private val sessionId by lazy(LazyThreadSafetyMode.NONE) { getSessionId(CONFIRMATION_TAG) } private val handler = Handler(Looper.getMainLooper()) private var canInstallPackages = false + private var isFirstResume = true + private var isOnActivityResultCalled = false private val deadSessionCompletionRunnable = Runnable { withCompletableSession { session -> @@ -71,11 +76,21 @@ internal class SessionBasedInstallConfirmationActivity : InstallActivity(CONFIRM override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) canInstallPackages = savedInstanceState?.getBoolean(CAN_INSTALL_PACKAGES_KEY) ?: canInstallPackages() + isFirstResume = savedInstanceState?.getBoolean(IS_FIRST_RESUME_KEY) ?: true if (savedInstanceState == null) { launchInstallActivity() } } + override fun onResume() { + super.onResume() + if (!isFirstResume && !isOnActivityResultCalled && getTopActivityClassName() == this::class.java.name) { + // Activity was recreated and brought to top, but install confirmation from OS was dismissed. + abortSession() + } + isFirstResume = false + } + override fun onDestroy() { super.onDestroy() if (isFinishing) { @@ -86,12 +101,14 @@ internal class SessionBasedInstallConfirmationActivity : InstallActivity(CONFIRM override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putBoolean(CAN_INSTALL_PACKAGES_KEY, canInstallPackages) + outState.putBoolean(IS_FIRST_RESUME_KEY, isFirstResume) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode != this.requestCode) { return } + isOnActivityResultCalled = true val isActivityCancelled = resultCode == RESULT_CANCELED val sessionInfo = packageInstaller.getSessionInfo(sessionId) val isSessionAlive = sessionInfo != null @@ -138,6 +155,18 @@ internal class SessionBasedInstallConfirmationActivity : InstallActivity(CONFIRM notifySessionCommitted() } + private fun getTopActivityClassName(): String? { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return null + } + return getSystemService() + ?.appTasks + ?.firstOrNull() + ?.taskInfo + ?.topActivity + ?.className + } + private fun canInstallPackages() = Build.VERSION.SDK_INT < Build.VERSION_CODES.O || packageManager.canRequestPackageInstalls() || ContextCompat.checkSelfPermission(this, INSTALL_PACKAGES) == PERMISSION_GRANTED From a6ed60944490bf4741692a251cf41cda4d207417 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 11:53:11 +0500 Subject: [PATCH 08/20] change install failure from Generic to Aborted if install permission is denied --- .../impl/installer/activity/SessionBasedInstallActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt index 3db3f9adc..bd42b1f83 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt @@ -121,7 +121,7 @@ internal class SessionBasedInstallConfirmationActivity : InstallActivity(CONFIRM // User has cancelled install permission request or hasn't granted permission. !canInstallPackages -> { withCompletableSession { session -> - session?.complete(Session.State.Failed(InstallFailure.Generic("Install permission denied"))) + session?.complete(Session.State.Failed(InstallFailure.Aborted("Install permission denied"))) } finish() } From 39445e027c08527b7fb2971a0b7d40e85ea95526 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 11:55:46 +0500 Subject: [PATCH 09/20] increment version --- README.md | 2 +- docs/index.md | 2 +- version.properties | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4f5ffa4df..d42d48094 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Ackpine depends on Jetpack libraries, so it's necessary to declare the `google() ```kotlin dependencies { - val ackpineVersion = "0.8.0" + val ackpineVersion = "0.8.1" implementation("ru.solrudev.ackpine:ackpine-core:$ackpineVersion") // optional - Kotlin extensions and Coroutines support diff --git a/docs/index.md b/docs/index.md index cec0269b0..6609bf5f4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -27,7 +27,7 @@ Ackpine depends on Jetpack libraries, so it's necessary to declare the `google() ```kotlin dependencies { - val ackpineVersion = "0.8.0" + val ackpineVersion = "0.8.1" implementation("ru.solrudev.ackpine:ackpine-core:$ackpineVersion") // optional - Kotlin extensions and Coroutines support diff --git a/version.properties b/version.properties index 6b81380b9..96270ea91 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ MAJOR_VERSION=0 MINOR_VERSION=8 -PATCH_VERSION=0 +PATCH_VERSION=1 SUFFIX= SNAPSHOT=false \ No newline at end of file From 95b70380d911fa4f380aaf4ed16cf94aa75d0b9b Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 12:00:10 +0500 Subject: [PATCH 10/20] accept optional message in abortSession() --- .../solrudev/ackpine/impl/activity/SessionCommitActivity.kt | 4 ++-- .../impl/installer/activity/SessionBasedInstallActivity.kt | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/activity/SessionCommitActivity.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/activity/SessionCommitActivity.kt index 49d76cf3a..42572ca29 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/activity/SessionCommitActivity.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/activity/SessionCommitActivity.kt @@ -127,10 +127,10 @@ internal abstract class SessionCommitActivity protected constructor } } - protected fun abortSession() = withCompletableSession { session -> + protected fun abortSession(message: String? = null) = withCompletableSession { session -> session?.complete( Session.State.Failed( - abortedStateFailureFactory("$tag was finished by user") + abortedStateFailureFactory(message ?: "$tag was finished by user") ) ) } diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt index bd42b1f83..7033c7d99 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt @@ -120,9 +120,7 @@ internal class SessionBasedInstallConfirmationActivity : InstallActivity(CONFIRM when { // User has cancelled install permission request or hasn't granted permission. !canInstallPackages -> { - withCompletableSession { session -> - session?.complete(Session.State.Failed(InstallFailure.Aborted("Install permission denied"))) - } + abortSession("Install permission denied") finish() } // User hasn't confirmed installation because confirmation activity didn't appear after permission request. From 4c1b9bea58a42efdff518406d1380765a94720bf Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 12:02:19 +0500 Subject: [PATCH 11/20] remove unnecessary finish() call --- .../impl/installer/activity/SessionBasedInstallActivity.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt index 7033c7d99..9fa6594bf 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/activity/SessionBasedInstallActivity.kt @@ -119,10 +119,7 @@ internal class SessionBasedInstallConfirmationActivity : InstallActivity(CONFIRM // Order of checks is important. when { // User has cancelled install permission request or hasn't granted permission. - !canInstallPackages -> { - abortSession("Install permission denied") - finish() - } + !canInstallPackages -> abortSession("Install permission denied") // User hasn't confirmed installation because confirmation activity didn't appear after permission request. // Unfortunately, on some OS versions session may stay stuck if confirmation was dismissed by clicking // outside of confirmation dialog, so this may lead to repeated confirmation if permission status changes. From c3567049cc7215f5bd04d1b27f2467e35c198bc0 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 12:46:26 +0500 Subject: [PATCH 12/20] update kotlin and ksp to 2.0.21 --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 804ceb0f3..20c73ebb9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] android-gradleplugin = "8.6.1" -kotlin = "2.0.20" -kotlin-ksp = "2.0.20-1.0.25" +kotlin = "2.0.21" +kotlin-ksp = "2.0.21-1.0.26" [libraries] materialcomponents = { module = "com.google.android.material:material", version = "1.12.0" } From 00e7cc3e3622064d453e363282331bdb1405792a Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 12:48:41 +0500 Subject: [PATCH 13/20] update guava to 33.3.1-android --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 20c73ebb9..f1c21c9ba 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ plugin-binaryCompatibilityValidator = { module = "org.jetbrains.kotlinx.binary-c apache-commons-compress = { module = "org.apache.commons:commons-compress", version = "1.27.1" } apksig = { module = "com.android.tools.build:apksig", version.ref = "android-gradleplugin" } listenablefuture = { module = "com.google.guava:listenablefuture", version = "1.0" } -guava = { module = "com.google.guava:guava", version = "33.3.0-android" } +guava = { module = "com.google.guava:guava", version = "33.3.1-android" } viewbindingpropertydelegate = { module = "com.github.kirich1409:viewbindingpropertydelegate-noreflection", version = "1.5.9" } [plugins] From 6d8b1cba52b92953f401f5224122deebb1a3fc3a Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 12:48:57 +0500 Subject: [PATCH 14/20] update androidx.constraintlayout to 2.2.0 --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index fd370c363..c224dbb96 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -10,7 +10,7 @@ annotation = { module = "androidx.annotation:annotation", version = "1.8.2" } appcompat = { module = "androidx.appcompat:appcompat", version = "1.7.0" } concurrent-futures-core = { module = "androidx.concurrent:concurrent-futures", version.ref = "concurrent" } concurrent-futures-ktx = { module = "androidx.concurrent:concurrent-futures-ktx", version.ref = "concurrent" } -constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version = "2.1.4" } +constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version = "2.2.0" } coordinatorlayout = { module = "androidx.coordinatorlayout:coordinatorlayout", version = "1.2.0" } core-ktx = { module = "androidx.core:core-ktx", version = "1.12.0" } lifecycle-livedata = { module = "androidx.lifecycle:lifecycle-livedata", version.ref = "lifecycle" } From 7ad9701a3c064e0be75d40745f871e68ea64b164 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 12:49:14 +0500 Subject: [PATCH 15/20] update androidx.annotation to 1.9.1 --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index c224dbb96..5ebcb3037 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -6,7 +6,7 @@ concurrent = "1.2.0" [libraries] activity = { module = "androidx.activity:activity", version = "1.9.2" } -annotation = { module = "androidx.annotation:annotation", version = "1.8.2" } +annotation = { module = "androidx.annotation:annotation", version = "1.9.1" } appcompat = { module = "androidx.appcompat:appcompat", version = "1.7.0" } concurrent-futures-core = { module = "androidx.concurrent:concurrent-futures", version.ref = "concurrent" } concurrent-futures-ktx = { module = "androidx.concurrent:concurrent-futures-ktx", version.ref = "concurrent" } From cea26339b6a5baf99a755f14f1722d90b992fd0d Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 12:49:25 +0500 Subject: [PATCH 16/20] update androidx.activity to 1.9.3 --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 5ebcb3037..3a8442a90 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -5,7 +5,7 @@ room = "2.6.1" concurrent = "1.2.0" [libraries] -activity = { module = "androidx.activity:activity", version = "1.9.2" } +activity = { module = "androidx.activity:activity", version = "1.9.3" } annotation = { module = "androidx.annotation:annotation", version = "1.9.1" } appcompat = { module = "androidx.appcompat:appcompat", version = "1.7.0" } concurrent-futures-core = { module = "androidx.concurrent:concurrent-futures", version.ref = "concurrent" } From e5da14a874b1cdbb28aaeaaf088501fd9d761f64 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 12:49:40 +0500 Subject: [PATCH 17/20] update androidx.lifecycle to 2.8.7 --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 3a8442a90..e39617fa2 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,5 +1,5 @@ [versions] -lifecycle = "2.8.6" +lifecycle = "2.8.7" navigation = "2.8.1" room = "2.6.1" concurrent = "1.2.0" From ed6987ab2e992c9f3914c057d8f045885423e837 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 12:49:53 +0500 Subject: [PATCH 18/20] update androidx.navigation to 2.8.3 --- gradle/androidx.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index e39617fa2..cd20c08af 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,6 +1,6 @@ [versions] lifecycle = "2.8.7" -navigation = "2.8.1" +navigation = "2.8.3" room = "2.6.1" concurrent = "1.2.0" From 20c51bfd9bd4f221fe1b0fbf59b071c56b81c5d2 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 13:36:46 +0500 Subject: [PATCH 19/20] implement readResolve() in serializable objects --- .../solrudev/ackpine/impl/installer/InstallSessionFactory.kt | 2 ++ .../ackpine/impl/uninstaller/UninstallSessionFactory.kt | 2 ++ .../ru/solrudev/ackpine/session/parameters/NotificationData.kt | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/InstallSessionFactory.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/InstallSessionFactory.kt index 7023df323..419ba55b6 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/InstallSessionFactory.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/InstallSessionFactory.kt @@ -132,11 +132,13 @@ internal class InstallSessionFactoryImpl internal constructor( private object AckpinePromptInstallTitle : ResolvableString.Resource() { private const val serialVersionUID = 7815666924791958742L override fun stringId() = R.string.ackpine_prompt_install_title + private fun readResolve(): Any = AckpinePromptInstallTitle } private object AckpinePromptInstallMessage : ResolvableString.Resource() { private const val serialVersionUID = 1224637050663404482L override fun stringId() = R.string.ackpine_prompt_install_message + private fun readResolve(): Any = AckpinePromptInstallMessage } private class AckpinePromptInstallMessageWithLabel(name: String) : ResolvableString.Resource(name) { diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/uninstaller/UninstallSessionFactory.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/uninstaller/UninstallSessionFactory.kt index e93e1b8fd..37af53dc1 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/uninstaller/UninstallSessionFactory.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/uninstaller/UninstallSessionFactory.kt @@ -102,11 +102,13 @@ internal class UninstallSessionFactoryImpl internal constructor( private object AckpinePromptUninstallTitle : ResolvableString.Resource() { private const val serialVersionUID = -4086992997791586590L override fun stringId() = R.string.ackpine_prompt_uninstall_title + private fun readResolve(): Any = AckpinePromptUninstallTitle } private object AckpinePromptUninstallMessage : ResolvableString.Resource() { private const val serialVersionUID = -3150252606151986307L override fun stringId(): Int = R.string.ackpine_prompt_uninstall_message + private fun readResolve(): Any = AckpinePromptUninstallMessage } private class AckpinePromptUninstallMessageWithLabel(label: String) : ResolvableString.Resource(label) { diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/session/parameters/NotificationData.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/session/parameters/NotificationData.kt index a0565121b..a0774e044 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/session/parameters/NotificationData.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/session/parameters/NotificationData.kt @@ -165,9 +165,10 @@ public interface DrawableId : Serializable { } } -private object DefaultNotificationIcon : DrawableId { +private data object DefaultNotificationIcon : DrawableId { private const val serialVersionUID = 6906923061913799903L override fun drawableId() = android.R.drawable.ic_dialog_alert + private fun readResolve(): Any = DefaultNotificationIcon } @RestrictTo(RestrictTo.Scope.LIBRARY) From 8cd162b1a83b57df5eee914e625bdd1b4e94e896 Mon Sep 17 00:00:00 2001 From: Ilya Fomichev Date: Thu, 31 Oct 2024 13:41:08 +0500 Subject: [PATCH 20/20] add version 0.8.1 to changelog --- docs/changelog.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 36ab7609e..bb82072a2 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,6 +1,25 @@ Change Log ========== +Version 0.8.1 (2024-10-31) +-------------------------- + +### Dependencies + +- Updated Kotlin to 2.0.21. +- Updated `androidx.annotation` to 1.9.1. +- Updated `androidx.activity` to 1.9.3 (sample apps dependency). +- Updated `androidx.constraintlayout` to 2.2.0 (sample apps dependency). +- Updated `androidx.lifecycle` to 2.8.7 (sample apps dependency). +- Updated `androidx.navigation` to 2.8.3 (sample apps dependency). +- Updated Guava to 33.3.1-android (sample apps dependency). +- Migrated from `gradle-nexus/publish-plugin` to `vanniktech/gradle-maven-publish-plugin` for publishing artifacts to Maven Central. + +### Bug fixes and improvements + +- Fix install confirmation from OS not displaying after granting install permission on some devices (particularly Android TV) using `SESSION_BASED` installer. This is a fix for #84. +- Fix various issues with dismissing install confirmation from OS via clicking outside of confirmation dialog using `SESSION_BASED` installer. + Version 0.8.0 (2024-10-25) --------------------------