diff --git a/README.md b/README.md index bc8d6d899..7aa66f165 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Ackpine depends on Jetpack libraries, so it's necessary to declare the `google() ```kotlin dependencies { - val ackpineVersion = "0.5.5" + val ackpineVersion = "0.6.0" implementation("ru.solrudev.ackpine:ackpine-core:$ackpineVersion") // optional - Kotlin extensions and Coroutines support diff --git a/ackpine-core/api/ackpine-core.api b/ackpine-core/api/ackpine-core.api index 938378438..643b4ee5e 100644 --- a/ackpine-core/api/ackpine-core.api +++ b/ackpine-core/api/ackpine-core.api @@ -240,11 +240,38 @@ public abstract interface class ru/solrudev/ackpine/installer/parameters/ApkList public abstract fun toList ()Ljava/util/List; } +public abstract interface class ru/solrudev/ackpine/installer/parameters/InstallMode { + public static final field Companion Lru/solrudev/ackpine/installer/parameters/InstallMode$Companion; + public static final field FULL Lru/solrudev/ackpine/installer/parameters/InstallMode$Full; +} + +public final class ru/solrudev/ackpine/installer/parameters/InstallMode$Companion { +} + +public final class ru/solrudev/ackpine/installer/parameters/InstallMode$Full : ru/solrudev/ackpine/installer/parameters/InstallMode { + public static final field INSTANCE Lru/solrudev/ackpine/installer/parameters/InstallMode$Full; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class ru/solrudev/ackpine/installer/parameters/InstallMode$InheritExisting : ru/solrudev/ackpine/installer/parameters/InstallMode { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lru/solrudev/ackpine/installer/parameters/InstallMode$InheritExisting; + public static synthetic fun copy$default (Lru/solrudev/ackpine/installer/parameters/InstallMode$InheritExisting;Ljava/lang/String;ILjava/lang/Object;)Lru/solrudev/ackpine/installer/parameters/InstallMode$InheritExisting; + public fun equals (Ljava/lang/Object;)Z + public final fun getPackageName ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class ru/solrudev/ackpine/installer/parameters/InstallParameters : ru/solrudev/ackpine/session/parameters/ConfirmationAware { - public synthetic fun (Lru/solrudev/ackpine/installer/parameters/ApkList;Lru/solrudev/ackpine/installer/parameters/InstallerType;Lru/solrudev/ackpine/session/parameters/Confirmation;Lru/solrudev/ackpine/session/parameters/NotificationData;Ljava/lang/String;ZLkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Lru/solrudev/ackpine/installer/parameters/ApkList;Lru/solrudev/ackpine/installer/parameters/InstallerType;Lru/solrudev/ackpine/session/parameters/Confirmation;Lru/solrudev/ackpine/session/parameters/NotificationData;Ljava/lang/String;ZLru/solrudev/ackpine/installer/parameters/InstallMode;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public fun equals (Ljava/lang/Object;)Z public final fun getApks ()Lru/solrudev/ackpine/installer/parameters/ApkList; public fun getConfirmation ()Lru/solrudev/ackpine/session/parameters/Confirmation; + public final fun getInstallMode ()Lru/solrudev/ackpine/installer/parameters/InstallMode; public final fun getInstallerType ()Lru/solrudev/ackpine/installer/parameters/InstallerType; public final fun getName ()Ljava/lang/String; public fun getNotificationData ()Lru/solrudev/ackpine/session/parameters/NotificationData; @@ -261,11 +288,13 @@ public final class ru/solrudev/ackpine/installer/parameters/InstallParameters$Bu public final fun build ()Lru/solrudev/ackpine/installer/parameters/InstallParameters; public final fun getApks ()Lru/solrudev/ackpine/installer/parameters/ApkList; public fun getConfirmation ()Lru/solrudev/ackpine/session/parameters/Confirmation; + public final fun getInstallMode ()Lru/solrudev/ackpine/installer/parameters/InstallMode; public final fun getInstallerType ()Lru/solrudev/ackpine/installer/parameters/InstallerType; public final fun getName ()Ljava/lang/String; public fun getNotificationData ()Lru/solrudev/ackpine/session/parameters/NotificationData; public final fun getRequireUserAction ()Z public final fun setConfirmation (Lru/solrudev/ackpine/session/parameters/Confirmation;)Lru/solrudev/ackpine/installer/parameters/InstallParameters$Builder; + public final fun setInstallMode (Lru/solrudev/ackpine/installer/parameters/InstallMode;)Lru/solrudev/ackpine/installer/parameters/InstallParameters$Builder; public final fun setInstallerType (Lru/solrudev/ackpine/installer/parameters/InstallerType;)Lru/solrudev/ackpine/installer/parameters/InstallParameters$Builder; public final fun setName (Ljava/lang/String;)Lru/solrudev/ackpine/installer/parameters/InstallParameters$Builder; public final fun setNotificationData (Lru/solrudev/ackpine/session/parameters/NotificationData;)Lru/solrudev/ackpine/installer/parameters/InstallParameters$Builder; diff --git a/ackpine-core/schemas/ru.solrudev.ackpine.impl.database.AckpineDatabase/6.json b/ackpine-core/schemas/ru.solrudev.ackpine.impl.database.AckpineDatabase/6.json new file mode 100644 index 000000000..5808d454e --- /dev/null +++ b/ackpine-core/schemas/ru.solrudev.ackpine.impl.database.AckpineDatabase/6.json @@ -0,0 +1,532 @@ +{ + "formatVersion": 1, + "database": { + "version": 6, + "identityHash": "3109e8b9d83a867de8bcf8b0d049f728", + "entities": [ + { + "tableName": "sessions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` TEXT NOT NULL, `state` TEXT NOT NULL, `confirmation` TEXT NOT NULL, `notification_title` BLOB NOT NULL, `notification_text` BLOB NOT NULL, `notification_icon` INTEGER NOT NULL, `require_user_action` INTEGER NOT NULL DEFAULT true, `last_launch_timestamp` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "confirmation", + "columnName": "confirmation", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "notificationTitle", + "columnName": "notification_title", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "notificationText", + "columnName": "notification_text", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "notificationIcon", + "columnName": "notification_icon", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "requireUserAction", + "columnName": "require_user_action", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "true" + }, + { + "fieldPath": "lastLaunchTimestamp", + "columnName": "last_launch_timestamp", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_sessions_type", + "unique": false, + "columnNames": [ + "type" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_sessions_type` ON `${TABLE_NAME}` (`type`)" + }, + { + "name": "index_sessions_state", + "unique": false, + "columnNames": [ + "state" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_sessions_state` ON `${TABLE_NAME}` (`state`)" + }, + { + "name": "index_sessions_last_launch_timestamp", + "unique": false, + "columnNames": [ + "last_launch_timestamp" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_sessions_last_launch_timestamp` ON `${TABLE_NAME}` (`last_launch_timestamp`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "sessions_installer_types", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`session_id` TEXT NOT NULL, `installer_type` TEXT NOT NULL, PRIMARY KEY(`session_id`), FOREIGN KEY(`session_id`) REFERENCES `sessions`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "sessionId", + "columnName": "session_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "installerType", + "columnName": "installer_type", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "session_id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "sessions", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "session_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "sessions_install_failures", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`session_id` TEXT NOT NULL, `failure` BLOB NOT NULL, PRIMARY KEY(`session_id`), FOREIGN KEY(`session_id`) REFERENCES `sessions`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "sessionId", + "columnName": "session_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "failure", + "columnName": "failure", + "affinity": "BLOB", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "session_id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "sessions", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "session_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "sessions_uninstall_failures", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`session_id` TEXT NOT NULL, `failure` BLOB NOT NULL, PRIMARY KEY(`session_id`), FOREIGN KEY(`session_id`) REFERENCES `sessions`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "sessionId", + "columnName": "session_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "failure", + "columnName": "failure", + "affinity": "BLOB", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "session_id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "sessions", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "session_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "sessions_install_uris", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `session_id` TEXT NOT NULL, `uri` TEXT NOT NULL, FOREIGN KEY(`session_id`) REFERENCES `sessions`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sessionId", + "columnName": "session_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "uri", + "columnName": "uri", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_sessions_install_uris_session_id", + "unique": false, + "columnNames": [ + "session_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_sessions_install_uris_session_id` ON `${TABLE_NAME}` (`session_id`)" + } + ], + "foreignKeys": [ + { + "table": "sessions", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "session_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "sessions_package_names", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `session_id` TEXT NOT NULL, `package_name` TEXT NOT NULL, FOREIGN KEY(`session_id`) REFERENCES `sessions`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sessionId", + "columnName": "session_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "packageName", + "columnName": "package_name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_sessions_package_names_session_id", + "unique": false, + "columnNames": [ + "session_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_sessions_package_names_session_id` ON `${TABLE_NAME}` (`session_id`)" + } + ], + "foreignKeys": [ + { + "table": "sessions", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "session_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "sessions_progress", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`session_id` TEXT NOT NULL, `progress` INTEGER NOT NULL DEFAULT 0, `max` INTEGER NOT NULL DEFAULT 100, PRIMARY KEY(`session_id`), FOREIGN KEY(`session_id`) REFERENCES `sessions`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "sessionId", + "columnName": "session_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "progress", + "columnName": "progress", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "max", + "columnName": "max", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "100" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "session_id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "sessions", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "session_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "sessions_native_session_ids", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`session_id` TEXT NOT NULL, `native_session_id` INTEGER NOT NULL, PRIMARY KEY(`session_id`), FOREIGN KEY(`session_id`) REFERENCES `sessions`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "sessionId", + "columnName": "session_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "nativeSessionId", + "columnName": "native_session_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "session_id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "sessions", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "session_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "sessions_notification_ids", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`session_id` TEXT NOT NULL, `notification_id` INTEGER NOT NULL, PRIMARY KEY(`session_id`), FOREIGN KEY(`session_id`) REFERENCES `sessions`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "sessionId", + "columnName": "session_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "notificationId", + "columnName": "notification_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "session_id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "sessions", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "session_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "sessions_names", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`session_id` TEXT NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`session_id`), FOREIGN KEY(`session_id`) REFERENCES `sessions`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "sessionId", + "columnName": "session_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "session_id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "sessions", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "session_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "sessions_install_modes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`session_id` TEXT NOT NULL, `install_mode` TEXT NOT NULL, PRIMARY KEY(`session_id`), FOREIGN KEY(`session_id`) REFERENCES `sessions`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "sessionId", + "columnName": "session_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "installMode", + "columnName": "install_mode", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "session_id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "sessions", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "session_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '3109e8b9d83a867de8bcf8b0d049f728')" + ] + } +} \ No newline at end of file diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/AckpineDatabase.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/AckpineDatabase.kt index cd3be3d1e..054c89a2d 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/AckpineDatabase.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/AckpineDatabase.kt @@ -37,6 +37,7 @@ import ru.solrudev.ackpine.impl.database.dao.SessionNameDao import ru.solrudev.ackpine.impl.database.dao.SessionProgressDao import ru.solrudev.ackpine.impl.database.dao.UninstallSessionDao import ru.solrudev.ackpine.impl.database.model.InstallFailureEntity +import ru.solrudev.ackpine.impl.database.model.InstallModeEntity import ru.solrudev.ackpine.impl.database.model.InstallUriEntity import ru.solrudev.ackpine.impl.database.model.NativeSessionIdEntity import ru.solrudev.ackpine.impl.database.model.NotificationIdEntity @@ -65,14 +66,16 @@ private const val PURGE_SQL = "DELETE FROM sessions WHERE state IN $TERMINAL_STA SessionProgressEntity::class, NativeSessionIdEntity::class, NotificationIdEntity::class, - SessionNameEntity::class + SessionNameEntity::class, + InstallModeEntity::class ], autoMigrations = [ AutoMigration(from = 1, to = 2), AutoMigration(from = 2, to = 3), - AutoMigration(from = 3, to = 4) + AutoMigration(from = 3, to = 4), + AutoMigration(from = 5, to = 6) ], - version = 5, + version = 6, exportSchema = true ) @TypeConverters( diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/dao/InstallSessionDao.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/dao/InstallSessionDao.kt index cbcfcf113..4bf8e7acd 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/dao/InstallSessionDao.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/dao/InstallSessionDao.kt @@ -23,6 +23,7 @@ import androidx.room.OnConflictStrategy import androidx.room.Query import androidx.room.Transaction import ru.solrudev.ackpine.impl.database.AckpineDatabase +import ru.solrudev.ackpine.impl.database.model.InstallModeEntity import ru.solrudev.ackpine.impl.database.model.InstallUriEntity import ru.solrudev.ackpine.impl.database.model.SessionEntity import ru.solrudev.ackpine.installer.InstallFailure @@ -46,6 +47,7 @@ internal abstract class InstallSessionDao protected constructor(private val data open fun insertInstallSession(session: SessionEntity.InstallSession) { database.sessionDao().insertSession(session.session) insertInstallerType(session.session.id, session.installerType) + insertInstallMode(session.session.id, session.installMode ?: InstallModeEntity.InstallMode.FULL) insertUris(session.uris.map { uri -> InstallUriEntity(sessionId = session.session.id, uri = uri) }) @@ -54,6 +56,9 @@ internal abstract class InstallSessionDao protected constructor(private val data if (!session.name.isNullOrEmpty()) { database.sessionNameDao().setSessionName(session.session.id, session.name) } + if (session.packageName != null) { + insertPackageName(session.session.id, session.packageName) + } } @Transaction @@ -74,6 +79,12 @@ internal abstract class InstallSessionDao protected constructor(private val data @Query("INSERT OR IGNORE INTO sessions_installer_types(session_id, installer_type) VALUES (:id, :installerType)") protected abstract fun insertInstallerType(id: String, installerType: InstallerType) + @Query("INSERT OR IGNORE INTO sessions_install_modes(session_id, install_mode) VALUES (:id, :installMode)") + protected abstract fun insertInstallMode(id: String, installMode: InstallModeEntity.InstallMode) + + @Query("INSERT OR IGNORE INTO sessions_package_names(session_id, package_name) VALUES (:id, :packageName)") + protected abstract fun insertPackageName(id: String, packageName: String) + @Insert(onConflict = OnConflictStrategy.IGNORE) protected abstract fun insertUris(uris: List) } \ No newline at end of file diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/model/InstallModeEntity.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/model/InstallModeEntity.kt new file mode 100644 index 000000000..5422ebf22 --- /dev/null +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/model/InstallModeEntity.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ru.solrudev.ackpine.impl.database.model + +import androidx.annotation.RestrictTo +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.PrimaryKey + +@RestrictTo(RestrictTo.Scope.LIBRARY) +@Entity( + tableName = "sessions_install_modes", + foreignKeys = [ForeignKey( + entity = SessionEntity::class, + parentColumns = ["id"], + childColumns = ["session_id"], + onDelete = ForeignKey.CASCADE, + onUpdate = ForeignKey.CASCADE + )] +) +internal data class InstallModeEntity internal constructor( + @PrimaryKey + @ColumnInfo(name = "session_id") + val sessionId: String, + @ColumnInfo(name = "install_mode") + val installMode: InstallMode +) { + + @RestrictTo(RestrictTo.Scope.LIBRARY) + internal enum class InstallMode { + FULL, INHERIT_EXISTING + } +} \ No newline at end of file diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/model/SessionEntity.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/model/SessionEntity.kt index e8f6fb061..87c73de29 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/model/SessionEntity.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/database/model/SessionEntity.kt @@ -18,7 +18,11 @@ package ru.solrudev.ackpine.impl.database.model import androidx.annotation.DrawableRes import androidx.annotation.RestrictTo -import androidx.room.* +import androidx.room.ColumnInfo +import androidx.room.Embedded +import androidx.room.Entity +import androidx.room.PrimaryKey +import androidx.room.Relation import ru.solrudev.ackpine.installer.parameters.InstallerType import ru.solrudev.ackpine.session.parameters.Confirmation import ru.solrudev.ackpine.session.parameters.NotificationString @@ -96,7 +100,21 @@ internal data class SessionEntity internal constructor( entity = NotificationIdEntity::class, projection = ["notification_id"] ) - val notificationId: Int? + val notificationId: Int?, + @Relation( + parentColumn = "id", + entityColumn = "session_id", + entity = InstallModeEntity::class, + projection = ["install_mode"] + ) + val installMode: InstallModeEntity.InstallMode?, + @Relation( + parentColumn = "id", + entityColumn = "session_id", + entity = PackageNameEntity::class, + projection = ["package_name"] + ) + val packageName: String? ) @RestrictTo(RestrictTo.Scope.LIBRARY) 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 39123e987..1bcaf9d6c 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 @@ -88,6 +88,7 @@ internal class InstallSessionFactoryImpl internal constructor( parameters.confirmation, parameters.notificationData.resolveDefault(parameters.name), parameters.requireUserAction, + parameters.installMode, sessionDao, sessionFailureDao, sessionProgressDao, nativeSessionIdDao, executor, SerialExecutor(executor), handler, notificationId ) diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/PackageInstallerImpl.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/PackageInstallerImpl.kt index b152cfddc..43c833967 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/PackageInstallerImpl.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/PackageInstallerImpl.kt @@ -24,10 +24,12 @@ import com.google.common.util.concurrent.ListenableFuture import ru.solrudev.ackpine.helpers.safeExecuteWith import ru.solrudev.ackpine.impl.database.dao.InstallSessionDao import ru.solrudev.ackpine.impl.database.dao.SessionProgressDao +import ru.solrudev.ackpine.impl.database.model.InstallModeEntity import ru.solrudev.ackpine.impl.database.model.SessionEntity import ru.solrudev.ackpine.impl.session.toSessionState import ru.solrudev.ackpine.installer.InstallFailure import ru.solrudev.ackpine.installer.PackageInstaller +import ru.solrudev.ackpine.installer.parameters.InstallMode import ru.solrudev.ackpine.installer.parameters.InstallParameters import ru.solrudev.ackpine.session.Progress import ru.solrudev.ackpine.session.ProgressSession @@ -70,6 +72,14 @@ internal class PackageInstallerImpl internal constructor( notificationId ) sessions[id] = session + var packageName: String? = null + val installMode = when (parameters.installMode) { + is InstallMode.Full -> InstallModeEntity.InstallMode.FULL + is InstallMode.InheritExisting -> { + packageName = parameters.installMode.packageName + InstallModeEntity.InstallMode.INHERIT_EXISTING + } + } executor.execute { installSessionDao.insertInstallSession( SessionEntity.InstallSession( @@ -86,7 +96,7 @@ internal class PackageInstallerImpl internal constructor( installerType = parameters.installerType, uris = parameters.apks.toList().map { it.toString() }, name = parameters.name, - notificationId + notificationId, installMode, packageName ) ) } @@ -151,6 +161,13 @@ internal class PackageInstallerImpl internal constructor( @SuppressLint("NewApi") private fun SessionEntity.InstallSession.toInstallSession(): ProgressSession { + val installMode = when (installMode) { + null -> InstallMode.Full + InstallModeEntity.InstallMode.FULL -> InstallMode.Full + InstallModeEntity.InstallMode.INHERIT_EXISTING -> InstallMode.InheritExisting( + requireNotNull(packageName) { "Package name was null when install mode is INHERIT_EXISTING" } + ) + } val parameters = InstallParameters.Builder(uris.map(String::toUri)) .setInstallerType(installerType) .setConfirmation(session.confirmation) @@ -168,6 +185,7 @@ internal class PackageInstallerImpl internal constructor( } } .setRequireUserAction(session.requireUserAction) + .setInstallMode(installMode) .build() return installSessionFactory.create( parameters, diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/session/SessionBasedInstallSession.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/session/SessionBasedInstallSession.kt index 084bf80d8..b331ed64a 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/session/SessionBasedInstallSession.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/session/SessionBasedInstallSession.kt @@ -19,6 +19,8 @@ package ru.solrudev.ackpine.impl.installer.session import android.annotation.SuppressLint import android.content.Context import android.content.pm.PackageInstaller +import android.content.pm.PackageInstaller.SessionParams.MODE_FULL_INSTALL +import android.content.pm.PackageInstaller.SessionParams.MODE_INHERIT_EXISTING import android.content.pm.PackageManager import android.content.res.AssetFileDescriptor import android.net.Uri @@ -45,6 +47,7 @@ import ru.solrudev.ackpine.impl.session.helpers.CANCEL_CURRENT_FLAGS import ru.solrudev.ackpine.impl.session.helpers.commitSession import ru.solrudev.ackpine.impl.session.helpers.launchConfirmation import ru.solrudev.ackpine.installer.InstallFailure +import ru.solrudev.ackpine.installer.parameters.InstallMode import ru.solrudev.ackpine.session.Progress import ru.solrudev.ackpine.session.Session import ru.solrudev.ackpine.session.Session.State.Committed @@ -68,6 +71,7 @@ internal class SessionBasedInstallSession internal constructor( private val confirmation: Confirmation, private val notificationData: NotificationData, private val requireUserAction: Boolean, + private val installMode: InstallMode, sessionDao: SessionDao, sessionFailureDao: SessionFailureDao, sessionProgressDao: SessionProgressDao, @@ -152,10 +156,12 @@ internal class SessionBasedInstallSession internal constructor( override fun launchConfirmation(cancellationSignal: CancellationSignal, notificationId: Int) { when (confirmation) { - Confirmation.IMMEDIATE -> packageInstaller.commitSession( - context, nativeSessionId, ackpineSessionId = id, generateRequestCode() - ) - + Confirmation.IMMEDIATE -> { + packageInstaller.commitSession( + context, nativeSessionId, ackpineSessionId = id, generateRequestCode() + ) + notifyCommitted() + } Confirmation.DEFERRED -> context.launchConfirmation( confirmation, notificationData, sessionId = id, @@ -164,9 +170,6 @@ internal class SessionBasedInstallSession internal constructor( CANCEL_CURRENT_FLAGS ) { intent -> intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, nativeSessionId) } } - if (!requireUserAction && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - notifyCommitted() - } } override fun doCleanup() { @@ -175,13 +178,18 @@ internal class SessionBasedInstallSession internal constructor( } private fun createSessionParams(): PackageInstaller.SessionParams { - val sessionParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - sessionParams.setInstallReason(PackageManager.INSTALL_REASON_USER) + val sessionParams = when (installMode) { + is InstallMode.Full -> PackageInstaller.SessionParams(MODE_FULL_INSTALL) + is InstallMode.InheritExisting -> PackageInstaller.SessionParams(MODE_INHERIT_EXISTING).apply { + setAppPackageName(installMode.packageName) + } } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { sessionParams.setOriginatingUid(Process.myUid()) } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + sessionParams.setInstallReason(PackageManager.INSTALL_REASON_USER) + } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val requireUserAction = if (requireUserAction) { PackageInstaller.SessionParams.USER_ACTION_REQUIRED diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/installer/parameters/InstallMode.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/installer/parameters/InstallMode.kt new file mode 100644 index 000000000..3de8b9c06 --- /dev/null +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/installer/parameters/InstallMode.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ru.solrudev.ackpine.installer.parameters + +import ru.solrudev.ackpine.installer.parameters.InstallMode.Full +import ru.solrudev.ackpine.installer.parameters.InstallMode.InheritExisting +import ru.solrudev.ackpine.installer.parameters.InstallerType.INTENT_BASED + +/** + * Mode for an install session. Takes effect only when using [InstallerType.SESSION_BASED] installer. + * + * * [Full] (default) — mode for an install session whose staged APKs should fully replace any existing APKs for + * the target app. + * * [InheritExisting] — mode for an install session that should inherit any existing APKs for the target app, + * unless they have been explicitly overridden (based on split name) by the session. + */ +public sealed interface InstallMode { + + /** + * Mode for an install session whose staged APKs should fully replace any existing APKs for the target app. + */ + public data object Full : InstallMode + + /** + * Mode for an install session that should inherit any existing APKs for the target app, unless they have been + * explicitly overridden (based on split name) by the session. For example, this can be used to add one or more + * split APKs to an existing installation. + * + * If there are no existing APKs for the target app, this behaves like [Full]. + * + * When using [INTENT_BASED] installer, this mode is ignored. + * + * @property packageName Package name of the app being installed. If the APKs staged in the session aren't + * consistent with this package name, the install will fail. + */ + public data class InheritExisting(val packageName: String) : InstallMode + + public companion object { + + /** + * Mode for an install session whose staged APKs should fully replace any existing APKs for the target app. + */ + @JvmField + public val FULL: Full = Full + } +} \ No newline at end of file diff --git a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/installer/parameters/InstallParameters.kt b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/installer/parameters/InstallParameters.kt index 757831633..e425c1522 100644 --- a/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/installer/parameters/InstallParameters.kt +++ b/ackpine-core/src/main/kotlin/ru/solrudev/ackpine/installer/parameters/InstallParameters.kt @@ -73,7 +73,14 @@ public class InstallParameters private constructor( * * @see [PackageInstaller.SessionParams.setRequireUserAction] */ - public val requireUserAction: Boolean + public val requireUserAction: Boolean, + + /** + * Mode for an install session. Takes effect only when using [InstallerType.SESSION_BASED] installer. + * + * Default value is [InstallMode.Full]. + */ + public val installMode: InstallMode ) : ConfirmationAware { override fun equals(other: Any?): Boolean { @@ -86,6 +93,7 @@ public class InstallParameters private constructor( if (notificationData != other.notificationData) return false if (name != other.name) return false if (requireUserAction != other.requireUserAction) return false + if (installMode != other.installMode) return false return true } @@ -96,6 +104,7 @@ public class InstallParameters private constructor( result = 31 * result + notificationData.hashCode() result = 31 * result + name.hashCode() result = 31 * result + requireUserAction.hashCode() + result = 31 * result + installMode.hashCode() return result } @@ -105,7 +114,8 @@ public class InstallParameters private constructor( "confirmation=$confirmation, " + "notificationData=$notificationData, " + "name='$name', " + - "requireUserAction=$requireUserAction)" + "requireUserAction=$requireUserAction, " + + "installMode=$installMode)" } /** @@ -190,6 +200,14 @@ public class InstallParameters private constructor( public var requireUserAction: Boolean = true private set + /** + * Mode for an install session. Takes effect only when using [InstallerType.SESSION_BASED] installer. + * + * Default value is [InstallMode.Full]. + */ + public var installMode: InstallMode = InstallMode.Full + private set + /** * Adds [apk] to [InstallParameters.apks]. */ @@ -244,12 +262,21 @@ public class InstallParameters private constructor( this.requireUserAction = requireUserAction } + /** + * Sets [InstallParameters.installMode]. + */ + public fun setInstallMode(installMode: InstallMode): Builder = apply { + this.installMode = installMode + } + /** * Constructs a new instance of [InstallParameters]. */ @SuppressLint("NewApi") public fun build(): InstallParameters { - return InstallParameters(apks, installerType, confirmation, notificationData, name, requireUserAction) + return InstallParameters( + apks, installerType, confirmation, notificationData, name, requireUserAction, installMode + ) } private fun applyInstallerTypeInvariants(value: InstallerType) = when { diff --git a/ackpine-ktx/api/ackpine-ktx.api b/ackpine-ktx/api/ackpine-ktx.api index 873a56dcf..6fa53486d 100644 --- a/ackpine-ktx/api/ackpine-ktx.api +++ b/ackpine-ktx/api/ackpine-ktx.api @@ -19,9 +19,11 @@ public final class ru/solrudev/ackpine/installer/parameters/ApkListKt { public abstract interface class ru/solrudev/ackpine/installer/parameters/InstallParametersDsl : ru/solrudev/ackpine/session/parameters/ConfirmationDsl { public abstract fun getApks ()Lru/solrudev/ackpine/installer/parameters/MutableApkList; + public abstract fun getInstallMode ()Lru/solrudev/ackpine/installer/parameters/InstallMode; public abstract fun getInstallerType ()Lru/solrudev/ackpine/installer/parameters/InstallerType; public abstract fun getName ()Ljava/lang/String; public abstract fun getRequireUserAction ()Z + public abstract fun setInstallMode (Lru/solrudev/ackpine/installer/parameters/InstallMode;)V public abstract fun setInstallerType (Lru/solrudev/ackpine/installer/parameters/InstallerType;)V public abstract fun setName (Ljava/lang/String;)V public abstract fun setRequireUserAction (Z)V @@ -33,11 +35,13 @@ public final class ru/solrudev/ackpine/installer/parameters/InstallParametersDsl public final fun build ()Lru/solrudev/ackpine/installer/parameters/InstallParameters; public fun getApks ()Lru/solrudev/ackpine/installer/parameters/MutableApkList; public fun getConfirmation ()Lru/solrudev/ackpine/session/parameters/Confirmation; + public fun getInstallMode ()Lru/solrudev/ackpine/installer/parameters/InstallMode; public fun getInstallerType ()Lru/solrudev/ackpine/installer/parameters/InstallerType; public fun getName ()Ljava/lang/String; public fun getNotificationData ()Lru/solrudev/ackpine/session/parameters/NotificationData; public fun getRequireUserAction ()Z public fun setConfirmation (Lru/solrudev/ackpine/session/parameters/Confirmation;)V + public fun setInstallMode (Lru/solrudev/ackpine/installer/parameters/InstallMode;)V public fun setInstallerType (Lru/solrudev/ackpine/installer/parameters/InstallerType;)V public fun setName (Ljava/lang/String;)V public fun setNotificationData (Lru/solrudev/ackpine/session/parameters/NotificationData;)V diff --git a/ackpine-ktx/src/main/kotlin/ru/solrudev/ackpine/installer/parameters/InstallParametersDsl.kt b/ackpine-ktx/src/main/kotlin/ru/solrudev/ackpine/installer/parameters/InstallParametersDsl.kt index efa0e5164..2afd277a1 100644 --- a/ackpine-ktx/src/main/kotlin/ru/solrudev/ackpine/installer/parameters/InstallParametersDsl.kt +++ b/ackpine-ktx/src/main/kotlin/ru/solrudev/ackpine/installer/parameters/InstallParametersDsl.kt @@ -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. @@ -64,6 +64,13 @@ public interface InstallParametersDsl : ConfirmationDsl { * @see [PackageInstaller.SessionParams.setRequireUserAction] */ public var requireUserAction: Boolean + + /** + * Mode for an install session. Takes effect only when using [InstallerType.SESSION_BASED] installer. + * + * Default value is [InstallMode.Full]. + */ + public var installMode: InstallMode } @PublishedApi @@ -113,5 +120,11 @@ internal class InstallParametersDslBuilder : InstallParametersDsl { builder.setRequireUserAction(value) } + override var installMode: InstallMode + get() = builder.installMode + set(value) { + builder.setInstallMode(value) + } + fun build() = builder.build() } \ No newline at end of file diff --git a/docs/changelog.md b/docs/changelog.md index a9b2e8fc6..50cab9c34 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,6 +1,28 @@ Change Log ========== +Version 0.6.0 (2024-05-20) +-------------------------- + +### Dependencies + +- Updated Kotlin to 1.9.24. +- Updated `androidx.annotation` to 1.8.0. +- Updated `androidx.activity` to 1.9.0 (sample apps dependency). +- Updated Guava to 33.2.0-android (sample apps dependency). +- Updated Material Components to 1.12.0 (sample apps dependency). + +### Bug fixes and improvements + +- Introduce an install mode option for `InstallParameters`. +- More consistent behavior of `COMMITTED` session state notifications when installer app is privileged for silent installs. + +### Public API changes + +- Added `InstallMode` sealed interface with two children (`Full` and `InheritExisting`) in `ackpine-core` module. +- Added `installMode` property to `InstallParameters` and its builder in `ackpine-core` module. +- Added `installMode` property to `InstallParametersDsl` in `ackpine-ktx` module. + Version 0.5.5 (2024-04-29) -------------------------- diff --git a/docs/configuration.md b/docs/configuration.md index 22a767e3f..5eb2b17ec 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -17,6 +17,7 @@ An example of creating a session with custom parameters: apks += apkSplitsUris confirmation = Confirmation.DEFERRED installerType = InstallerType.SESSION_BASED + installMode = InstallMode.InheritExisting("com.example.package") name = fileName requireUserAction = false notification { @@ -34,6 +35,7 @@ An example of creating a session with custom parameters: .addApks(apkSplitsUris) .setConfirmation(Confirmation.DEFERRED) .setInstallerType(InstallerType.SESSION_BASED) + .setInstallMode(new InstallMode.InheritExisting("com.example.package")) .setName(fileName) .setRequireUserAction(false) .setNotificationData(new NotificationData.Builder() @@ -49,9 +51,9 @@ User's confirmation A strategy for handling user's confirmation of installation or uninstallation. Can be `DEFERRED` (used by default) or `IMMEDIATE`. -`DEFERRED` (default) — user will be shown a high-priority notification which will launch confirmation activity. +- `DEFERRED` (default) — user will be shown a high-priority notification which will launch confirmation activity. -`IMMEDIATE` — user will be prompted to confirm installation or uninstallation right away. Suitable for launching session directly from the UI when app is in foreground. +- `IMMEDIATE` — user will be prompted to confirm installation or uninstallation right away. Suitable for launching session directly from the UI when app is in foreground. It's also possible to configure `requireUserAction` option for install sessions. It will have effect only on API level >= 31. If set to `false`, user's confirmation from system won't be triggered if some conditions are met. See the details [here](https://developer.android.com/reference/android/content/pm/PackageInstaller.SessionParams#setRequireUserAction(int)). @@ -82,4 +84,17 @@ Available for install sessions. Ackpine supports two different package installer - When on API level < 21, `INTENT_BASED` is always set regardless of the provided value; - When on API level >= 21 and `InstallParameters.Builder.apks` contains more than one entry, `SESSION_BASED` is always set regardless of the provided value. -By default, the value of installer type on API level < 21 is `INTENT_BASED`, and on API level >= 21 is `SESSION_BASED`. \ No newline at end of file +By default, the value of installer type on API level < 21 is `INTENT_BASED`, and on API level >= 21 is `SESSION_BASED`. + +Install mode +------------ + +Takes effect only when using `SESSION_BASED` installer. + +- `Full` (default) — mode for an install session whose staged APKs should fully replace any existing APKs for the target app. + +- `InheritExisting` — mode for an install session that should inherit any existing APKs for the target app, unless they have been explicitly overridden (based on split name) by the session. + + If there are no existing APKs for the target app, this behaves like `Full`. + + Requires package name of the app being installed. If the APKs staged in the session aren't consistent with the set package name, the install will fail. \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index d8a8c29f3..c116bbba9 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.5.5" + val ackpineVersion = "0.6.0" implementation("ru.solrudev.ackpine:ackpine-core:$ackpineVersion") // optional - Kotlin extensions and Coroutines support diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index edaa1fff9..c1b4df73b 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -6,9 +6,8 @@ room = "2.6.1" concurrent = "1.1.0" [libraries] -activity-java = { module = "androidx.activity:activity", version.ref = "activity" } -activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activity" } -annotation = { module = "androidx.annotation:annotation", version = "1.7.1" } +activity = { module = "androidx.activity:activity", version = "1.9.0" } +annotation = { module = "androidx.annotation:annotation", version = "1.8.0" } appcompat = { module = "androidx.appcompat:appcompat", version = "1.6.1" } concurrent-futures-core = { module = "androidx.concurrent:concurrent-futures", version.ref = "concurrent" } concurrent-futures-ktx = { module = "androidx.concurrent:concurrent-futures-ktx", version.ref = "concurrent" } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 90753b6fa..7ad8b1bd1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,10 +1,10 @@ [versions] android-gradleplugin = "8.3.2" -kotlin = "1.9.23" -kotlin-ksp = "1.9.23-1.0.19" +kotlin = "1.9.24" +kotlin-ksp = "1.9.24-1.0.20" [libraries] -materialcomponents = { module = "com.google.android.material:material", version = "1.11.0" } +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-agp = { module = "com.android.tools.build:gradle", version.ref = "android-gradleplugin" } plugin-kotlin-android = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } @@ -13,7 +13,7 @@ plugin-binaryCompatibilityValidator = { module = "org.jetbrains.kotlinx.binary-c apache-commons-compress = { module = "org.apache.commons:commons-compress", version = "1.26.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.1.0-android" } +guava = { module = "com.google.guava:guava", version = "33.2.0-android" } viewbindingpropertydelegate = { module = "com.github.kirich1409:viewbindingpropertydelegate-noreflection", version = "1.5.9" } [plugins] diff --git a/sample-java/build.gradle.kts b/sample-java/build.gradle.kts index 17c5e31e5..12a262e10 100644 --- a/sample-java/build.gradle.kts +++ b/sample-java/build.gradle.kts @@ -64,7 +64,7 @@ android { dependencies { implementation(projects.ackpineCore) implementation(projects.ackpineSplits) - implementation(androidx.activity.java) + implementation(androidx.activity) implementation(androidx.appcompat) implementation(androidx.recyclerview) implementation(androidx.constraintlayout) diff --git a/sample-java/src/main/java/ru/solrudev/ackpine/sample/install/InstallViewModel.java b/sample-java/src/main/java/ru/solrudev/ackpine/sample/install/InstallViewModel.java index a1d43689e..8294b8efe 100644 --- a/sample-java/src/main/java/ru/solrudev/ackpine/sample/install/InstallViewModel.java +++ b/sample-java/src/main/java/ru/solrudev/ackpine/sample/install/InstallViewModel.java @@ -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. diff --git a/sample-java/src/main/res/values/styles.xml b/sample-java/src/main/res/values/styles.xml index 85619a389..94332c5c2 100644 --- a/sample-java/src/main/res/values/styles.xml +++ b/sample-java/src/main/res/values/styles.xml @@ -1,6 +1,6 @@