diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 0cf717e23..5af4ef80b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -123,12 +123,11 @@ dependencies { implementation("androidx.biometric:biometric:1.1.0") implementation("androidx.constraintlayout:constraintlayout:2.1.1") implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") - implementation("androidx.browser:browser:1.3.0") + implementation("androidx.browser:browser:1.4.0") implementation("androidx.preference:preference:1.1.1") implementation("androidx.recyclerview:recyclerview:1.2.1") implementation("androidx.fragment:fragment-ktx:1.3.6") - implementation("androidx.work:work-runtime-ktx:2.7.0") implementation("androidx.transition:transition:1.4.1") - implementation("androidx.core:core-ktx:1.6.0") + implementation("androidx.core:core-ktx:1.7.0") implementation("com.google.android.material:material:1.4.0") } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0d621bda2..70e733f99 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,6 @@ android:multiArch="true" tools:ignore="UnusedAttribute,GoogleAppIndexingWarning"> - - - + - - - - + + + - - - - - it - name == JOB_SCHEDULER_SERVICE -> JobSchedulerWrapper(it as JobScheduler) - else -> it - } - } - } -} - fun Class<*>.cmp(pkg: String) = ComponentName(pkg, Info.stub?.classToComponent?.get(name) ?: name) @@ -99,28 +78,6 @@ object AssetHack { } } -@RequiresApi(28) -private class JobSchedulerWrapper(private val base: JobScheduler) : JobScheduler() { - override fun schedule(job: JobInfo) = base.schedule(job.patch()) - override fun enqueue(job: JobInfo, work: JobWorkItem) = base.enqueue(job.patch(), work) - override fun cancel(jobId: Int) = base.cancel(jobId) - override fun cancelAll() = base.cancelAll() - override fun getAllPendingJobs(): List = base.allPendingJobs - override fun getPendingJob(jobId: Int) = base.getPendingJob(jobId) - private fun JobInfo.patch(): JobInfo { - // Swap out the service of JobInfo - val component = service.run { - ComponentName(packageName, - Info.stub?.classToComponent?.get(className) ?: className) - } - javaClass.getDeclaredField("service").apply { - isAccessible = true - }.set(this, component) - - return this - } -} - // Keep a reference to these resources to prevent it from // being removed when running "remove unused resources" val shouldKeepResources = listOf( diff --git a/app/src/main/java/com/topjohnwu/magisk/core/JobService.kt b/app/src/main/java/com/topjohnwu/magisk/core/JobService.kt new file mode 100644 index 000000000..eb283ddd8 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/core/JobService.kt @@ -0,0 +1,56 @@ +package com.topjohnwu.magisk.core + +import android.app.job.JobInfo +import android.app.job.JobParameters +import android.app.job.JobScheduler +import android.content.Context +import androidx.core.content.getSystemService +import com.topjohnwu.magisk.BuildConfig +import com.topjohnwu.magisk.core.base.BaseJobService +import com.topjohnwu.magisk.di.ServiceLocator +import com.topjohnwu.magisk.view.Notifications +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import java.util.concurrent.TimeUnit + +class JobService : BaseJobService() { + + private val job = Job() + private val svc get() = ServiceLocator.networkService + + override fun onStartJob(params: JobParameters): Boolean { + val coroutineScope = CoroutineScope(Dispatchers.IO + job) + coroutineScope.launch { + svc.fetchUpdate()?.run { + if (Info.env.isActive && BuildConfig.VERSION_CODE < magisk.versionCode) + Notifications.managerUpdate(this@JobService) + } + jobFinished(params, false) + } + return false + } + + override fun onStopJob(params: JobParameters): Boolean { + job.cancel() + return false + } + + companion object { + fun schedule(context: Context) { + val svc = context.getSystemService() ?: return + if (Config.checkUpdate) { + val cmp = JobService::class.java.cmp(context.packageName) + val info = JobInfo.Builder(Const.ID.JOB_SERVICE_ID, cmp) + .setPeriodic(TimeUnit.HOURS.toMillis(12)) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) + .setRequiresDeviceIdle(true) + .build() + svc.schedule(info) + } else { + svc.cancel(Const.ID.JOB_SERVICE_ID) + } + } + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/core/SplashActivity.kt b/app/src/main/java/com/topjohnwu/magisk/core/SplashActivity.kt index 6f6d2e9e9..666044b24 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/SplashActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/SplashActivity.kt @@ -15,7 +15,7 @@ import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.superuser.Shell import java.util.concurrent.CountDownLatch -open class SplashActivity : BaseActivity() { +class SplashActivity : BaseActivity() { private val latch = CountDownLatch(1) @@ -63,7 +63,7 @@ open class SplashActivity : BaseActivity() { Config.load(prevPkg) handleRepackage(prevPkg) Notifications.setup(this) - UpdateCheckService.schedule(this) + JobService.schedule(this) Shortcuts.setupDynamic(this) // Pre-fetch network services diff --git a/app/src/main/java/com/topjohnwu/magisk/core/UpdateCheckService.kt b/app/src/main/java/com/topjohnwu/magisk/core/UpdateCheckService.kt deleted file mode 100644 index 89d01a111..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/core/UpdateCheckService.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.topjohnwu.magisk.core - -import android.annotation.SuppressLint -import android.content.Context -import androidx.work.* -import com.topjohnwu.magisk.BuildConfig -import com.topjohnwu.magisk.di.ServiceLocator -import com.topjohnwu.magisk.view.Notifications -import java.util.concurrent.TimeUnit - -class UpdateCheckService(context: Context, workerParams: WorkerParameters) - : CoroutineWorker(context, workerParams) { - - private val svc get() = ServiceLocator.networkService - - override suspend fun doWork(): Result { - return svc.fetchUpdate()?.run { - if (Info.env.isActive && BuildConfig.VERSION_CODE < magisk.versionCode) - Notifications.managerUpdate(applicationContext) - Result.success() - } ?: Result.failure() - } - - companion object { - @SuppressLint("NewApi") - fun schedule(context: Context) { - if (Config.checkUpdate) { - val constraints = Constraints.Builder() - .setRequiredNetworkType(NetworkType.CONNECTED) - .setRequiresDeviceIdle(true) - .build() - val request = PeriodicWorkRequestBuilder(12, TimeUnit.HOURS) - .setConstraints(constraints) - .build() - WorkManager.getInstance(context).enqueueUniquePeriodicWork( - Const.ID.CHECK_MAGISK_UPDATE_WORKER_ID, - ExistingPeriodicWorkPolicy.REPLACE, request) - } else { - WorkManager.getInstance(context) - .cancelUniqueWork(Const.ID.CHECK_MAGISK_UPDATE_WORKER_ID) - } - } - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/core/base/BaseJobService.kt b/app/src/main/java/com/topjohnwu/magisk/core/base/BaseJobService.kt new file mode 100644 index 000000000..3208be75c --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/core/base/BaseJobService.kt @@ -0,0 +1,11 @@ +package com.topjohnwu.magisk.core.base + +import android.app.job.JobService +import android.content.Context +import com.topjohnwu.magisk.core.wrap + +abstract class BaseJobService : JobService() { + override fun attachBaseContext(base: Context) { + super.attachBaseContext(base.wrap()) + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/core/base/BaseWorkerWrapper.kt b/app/src/main/java/com/topjohnwu/magisk/core/base/BaseWorkerWrapper.kt deleted file mode 100644 index 52f9ab2e3..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/core/base/BaseWorkerWrapper.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.topjohnwu.magisk.core.base - -import android.content.Context -import android.net.Network -import android.net.Uri -import androidx.annotation.MainThread -import androidx.annotation.RequiresApi -import androidx.work.Data -import androidx.work.ListenableWorker -import com.google.common.util.concurrent.ListenableFuture -import java.util.* - -abstract class BaseWorkerWrapper { - - private lateinit var worker: ListenableWorker - - val applicationContext: Context - get() = worker.applicationContext - - val id: UUID - get() = worker.id - - val inputData: Data - get() = worker.inputData - - val tags: Set - get() = worker.tags - - val triggeredContentUris: List - @RequiresApi(24) - get() = worker.triggeredContentUris - - val triggeredContentAuthorities: List - @RequiresApi(24) - get() = worker.triggeredContentAuthorities - - val network: Network? - @RequiresApi(28) - get() = worker.network - - val runAttemptCount: Int - get() = worker.runAttemptCount - - val isStopped: Boolean - get() = worker.isStopped - - abstract fun doWork(): ListenableWorker.Result - - fun onStopped() {} - - fun attachWorker(w: ListenableWorker) { - worker = w - } - - @MainThread - fun startWork(): ListenableFuture { - return worker.startWork() - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt index ca51108a0..9ce4dd917 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt @@ -12,7 +12,7 @@ import com.topjohnwu.magisk.R import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Info -import com.topjohnwu.magisk.core.UpdateCheckService +import com.topjohnwu.magisk.core.JobService import com.topjohnwu.magisk.core.tasks.HideAPK import com.topjohnwu.magisk.core.utils.BiometricHelper import com.topjohnwu.magisk.core.utils.MediaStoreUtils @@ -185,7 +185,7 @@ object UpdateChecker : BaseSettingsItem.Toggle() { override var value = Config.checkUpdate set(value) = setV(value, field, { field = it }) { Config.checkUpdate = it - UpdateCheckService.schedule(AppContext) + JobService.schedule(AppContext) } } diff --git a/buildSrc/src/main/java/Codegen.kt b/buildSrc/src/main/java/Codegen.kt index b8df250c0..94f415f14 100644 --- a/buildSrc/src/main/java/Codegen.kt +++ b/buildSrc/src/main/java/Codegen.kt @@ -153,7 +153,10 @@ fun genStubManifest(srcDir: File, outDir: File): String { cmpList.add(Component( "com.topjohnwu.magisk.ui.MainActivity", "", - """|""".ind(2) + """ + |""".ind(2) )) cmpList.add(Component( @@ -176,18 +179,19 @@ fun genStubManifest(srcDir: File, outDir: File): String { cmpList.add(Component( "com.topjohnwu.magisk.core.download.DownloadService", "", - """|""".ind(2) + """ + |""".trimIndent().ind(2) )) cmpList.add(Component( - "androidx.work.impl.background.systemjob.SystemJobService", + "com.topjohnwu.magisk.core.JobService", "", """ |""".ind(2) )) diff --git a/gradle.properties b/gradle.properties index ed1d321fb..60a6c00de 100644 --- a/gradle.properties +++ b/gradle.properties @@ -30,7 +30,7 @@ android.injected.testOnly=false kapt.incremental.apt=true # Magisk -magisk.stubVersion=21 +magisk.stubVersion=22 magisk.versionCode=23012 magisk.ndkVersion=21e magisk.fullNdkVersion=21.4.7075529