mirror of
https://github.com/f-droid/fdroidclient.git
synced 2026-02-05 12:42:34 -05:00
Merge branch 'unarchive' into 'master'
Experimental support for un-archiving apps on Android 15 See merge request fdroid/fdroidclient!1450
This commit is contained in:
@@ -496,6 +496,13 @@
|
||||
<action android:name="org.fdroid.action.UPDATE_REPOS" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".receiver.UnarchivePackageReceiver"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.UNARCHIVE_PACKAGE" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".net.DownloaderService"
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.fdroid.fdroid.receiver
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.Intent.ACTION_UNARCHIVE_PACKAGE
|
||||
import android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_ALL_USERS
|
||||
import android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_ID
|
||||
import android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_PACKAGE_NAME
|
||||
import android.util.Log
|
||||
import org.fdroid.fdroid.work.UnarchiveWorker
|
||||
|
||||
private val TAG = UnarchivePackageReceiver::class.java.simpleName
|
||||
|
||||
@TargetApi(35)
|
||||
class UnarchivePackageReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action != ACTION_UNARCHIVE_PACKAGE) {
|
||||
Log.w(TAG, "Unknown action: ${intent.action}")
|
||||
return
|
||||
}
|
||||
val packageName = intent.getStringExtra(EXTRA_UNARCHIVE_PACKAGE_NAME) ?: error("")
|
||||
val unarchiveId = intent.getIntExtra(EXTRA_UNARCHIVE_ID, -1)
|
||||
val allUsers = intent.getBooleanExtra(EXTRA_UNARCHIVE_ALL_USERS, false)
|
||||
|
||||
Log.i(TAG, "Intent received, un-archiving $packageName...")
|
||||
|
||||
UnarchiveWorker.updateNow(context, packageName, unarchiveId, allUsers)
|
||||
}
|
||||
}
|
||||
97
app/src/main/java/org/fdroid/fdroid/work/UnarchiveWorker.kt
Normal file
97
app/src/main/java/org/fdroid/fdroid/work/UnarchiveWorker.kt
Normal file
@@ -0,0 +1,97 @@
|
||||
package org.fdroid.fdroid.work
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_ALL_USERS
|
||||
import android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_ID
|
||||
import android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_PACKAGE_NAME
|
||||
import android.content.pm.PackageManager.MATCH_ARCHIVED_PACKAGES
|
||||
import android.content.pm.PackageManager.PackageInfoFlags
|
||||
import android.util.Log
|
||||
import androidx.annotation.UiThread
|
||||
import androidx.lifecycle.asFlow
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.Data
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkerParameters
|
||||
import kotlinx.coroutines.flow.first
|
||||
import org.fdroid.database.DbUpdateChecker
|
||||
import org.fdroid.fdroid.FDroidApp
|
||||
import org.fdroid.fdroid.data.Apk
|
||||
import org.fdroid.fdroid.data.App
|
||||
import org.fdroid.fdroid.data.DBHelper
|
||||
import org.fdroid.fdroid.installer.InstallManagerService
|
||||
|
||||
private val TAG = UnarchiveWorker::class.java.simpleName
|
||||
|
||||
@TargetApi(35)
|
||||
class UnarchiveWorker(
|
||||
appContext: Context,
|
||||
workerParams: WorkerParameters,
|
||||
) : CoroutineWorker(appContext, workerParams) {
|
||||
|
||||
companion object {
|
||||
@UiThread
|
||||
fun updateNow(context: Context, packageName: String, unarchiveId: Int, allUsers: Boolean) {
|
||||
val data = Data.Builder()
|
||||
.putString(EXTRA_UNARCHIVE_PACKAGE_NAME, packageName)
|
||||
.putInt(EXTRA_UNARCHIVE_ID, unarchiveId)
|
||||
.putBoolean(EXTRA_UNARCHIVE_ALL_USERS, allUsers)
|
||||
.build()
|
||||
val request = OneTimeWorkRequestBuilder<UnarchiveWorker>()
|
||||
.setExpedited(RUN_AS_NON_EXPEDITED_WORK_REQUEST)
|
||||
.setInputData(data)
|
||||
.build()
|
||||
WorkManager.getInstance(context)
|
||||
.enqueue(request)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
val packageName = inputData.getString(EXTRA_UNARCHIVE_PACKAGE_NAME)
|
||||
?: error("No packageName")
|
||||
val unarchiveId = inputData.getInt(EXTRA_UNARCHIVE_ID, -1)
|
||||
val allUsers = inputData.getBoolean(EXTRA_UNARCHIVE_ALL_USERS, false)
|
||||
|
||||
Log.i(TAG, "$packageName $unarchiveId $allUsers")
|
||||
|
||||
// get archived PackageInfo
|
||||
val pm = applicationContext.packageManager
|
||||
|
||||
@SuppressLint("WrongConstant") // not sure why MATCH_ARCHIVED_PACKAGES is considered wrong
|
||||
val packageInfo =
|
||||
pm.getPackageInfo(packageName, PackageInfoFlags.of(MATCH_ARCHIVED_PACKAGES))
|
||||
|
||||
// find suggested version for that app
|
||||
val db = DBHelper.getDb(applicationContext)
|
||||
val updateChecker = DbUpdateChecker(db, pm)
|
||||
val appPrefs = db.getAppPrefsDao().getAppPrefs(packageName).asFlow().first()
|
||||
val version = updateChecker.getSuggestedVersion(
|
||||
packageName = packageName,
|
||||
// TODO we could try to get the old signer (if still available) and search for the same
|
||||
preferredSigner = null,
|
||||
releaseChannels = appPrefs.releaseChannels,
|
||||
onlyFromPreferredRepo = true,
|
||||
)
|
||||
// install version, if available
|
||||
return if (version == null) {
|
||||
Log.e(TAG, "Could not find a version to unarchive for $packageName")
|
||||
Result.failure()
|
||||
} else {
|
||||
// get all the objects our InstallManagerService requires
|
||||
val repoManager = FDroidApp.getRepoManager(applicationContext)
|
||||
// repos may not have loaded yet, so we use the flow and wait for repos to be ready
|
||||
val repo = repoManager.repositoriesState.first().find { it.repoId == version.repoId }
|
||||
val dbApp = db.getAppDao().getApp(version.repoId, packageName)
|
||||
val app = App(dbApp, packageInfo)
|
||||
val apk = Apk(version, repo)
|
||||
// fire off installation, should happen automatically from here on
|
||||
InstallManagerService.queue(applicationContext, app, apk)
|
||||
Result.success()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
org.gradle.jvmargs=-Xms1g -Xmx2g
|
||||
org.gradle.jvmargs=-Xms2g -Xmx4g
|
||||
android.enableJetifier=false
|
||||
android.useAndroidX=true
|
||||
|
||||
|
||||
Reference in New Issue
Block a user