diff --git a/app/src/main/java/com/topjohnwu/magisk/core/Const.kt b/app/src/main/java/com/topjohnwu/magisk/core/Const.kt index 22c2d15d3..db818caa2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/Const.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/Const.kt @@ -39,8 +39,6 @@ object Const { } object ID { - // notifications - const val APK_UPDATE_NOTIFICATION_ID = 5 const val JOB_SERVICE_ID = 7 const val UPDATE_NOTIFICATION_CHANNEL = "update" const val PROGRESS_NOTIFICATION_CHANNEL = "progress" diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt index 7922896d6..378daa1cb 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt @@ -3,66 +3,47 @@ package com.topjohnwu.magisk.core.download import android.annotation.SuppressLint import android.app.Notification import android.app.PendingIntent +import android.app.PendingIntent.* import android.content.Context import android.content.Intent import android.os.Build import android.os.IBinder -import androidx.core.net.toFile import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.MutableLiveData import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.arch.BaseUIActivity import com.topjohnwu.magisk.core.ForegroundTracker import com.topjohnwu.magisk.core.base.BaseService -import com.topjohnwu.magisk.core.download.Action.Flash -import com.topjohnwu.magisk.core.download.Subject.Manager -import com.topjohnwu.magisk.core.download.Subject.Module import com.topjohnwu.magisk.core.intent +import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream import com.topjohnwu.magisk.core.utils.ProgressInputStream import com.topjohnwu.magisk.di.ServiceLocator -import com.topjohnwu.magisk.ui.flash.FlashFragment -import com.topjohnwu.magisk.utils.APKInstall +import com.topjohnwu.magisk.ktx.copyAndClose +import com.topjohnwu.magisk.ktx.synchronized import com.topjohnwu.magisk.view.Notifications -import com.topjohnwu.superuser.internal.UiThreadHandler -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.cancel -import kotlinx.coroutines.launch +import com.topjohnwu.magisk.view.Notifications.mgr +import kotlinx.coroutines.* import okhttp3.ResponseBody import timber.log.Timber import java.io.IOException import java.io.InputStream import java.util.* import kotlin.collections.HashMap -import kotlin.random.Random.Default.nextInt class DownloadService : BaseService() { - private val context get() = this private val hasNotifications get() = notifications.isNotEmpty() - private val notifications = Collections.synchronizedMap(HashMap()) - private val coroutineScope = CoroutineScope(Dispatchers.IO) + private val notifications = HashMap().synchronized() + private val job = Job() val service get() = ServiceLocator.networkService - private val mgr get() = Notifications.mgr // -- Service overrides override fun onBind(intent: Intent?): IBinder? = null override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { - intent.getParcelableExtra(SUBJECT_KEY)?.let { subject -> - update(subject.notifyID()) - coroutineScope.launch { - try { - subject.startDownload() - } catch (e: IOException) { - Timber.e(e) - notifyFail(subject) - } - } - } - return START_REDELIVER_INTENT + intent.getParcelableExtra(SUBJECT_KEY)?.let { doDownload(it) } + return START_NOT_STICKY } override fun onTaskRemoved(rootIntent: Intent?) { @@ -73,29 +54,40 @@ class DownloadService : BaseService() { override fun onDestroy() { super.onDestroy() - coroutineScope.cancel() + job.cancel() } // -- Download logic - private suspend fun Subject.startDownload() { - val stream = service.fetchFile(url).toProgressStream(this) - when (this) { - is Module -> // Download and process on-the-fly - stream.toModule(file, service.fetchInstaller().byteStream()) - is Manager -> handleAPK(this, stream) + private fun doDownload(subject: Subject) { + update(subject.notifyId) + val coroutineScope = CoroutineScope(job + Dispatchers.IO) + coroutineScope.launch { + try { + val stream = service.fetchFile(subject.url).toProgressStream(subject) + when (subject) { + is Subject.Manager -> handleAPK(subject, stream) + else -> stream.copyAndClose(subject.file.outputStream()) + } + if (ForegroundTracker.hasForeground) { + remove(subject.notifyId) + subject.pendingIntent(this@DownloadService).send() + } else { + notifyFinish(subject) + } + if (!hasNotifications) + stopSelf() + } catch (e: IOException) { + Timber.e(e) + notifyFail(subject) + } } - val newId = notifyFinish(this) - if (ForegroundTracker.hasForeground) - onFinish(this, newId) - if (!hasNotifications) - stopSelf() } private fun ResponseBody.toProgressStream(subject: Subject): InputStream { val max = contentLength() val total = max.toFloat() / 1048576 - val id = subject.notifyID() + val id = subject.notifyId update(id) { it.setContentTitle(subject.title) } @@ -115,18 +107,18 @@ class DownloadService : BaseService() { } } - // --- Notifications + // --- Notification management - private fun notifyFail(subject: Subject) = finalNotify(subject.notifyID()) { + private fun notifyFail(subject: Subject) = finalNotify(subject.notifyId) { broadcast(-2f, subject) it.setContentText(getString(R.string.download_file_error)) .setSmallIcon(android.R.drawable.stat_notify_error) .setOngoing(false) } - private fun notifyFinish(subject: Subject) = finalNotify(subject.notifyID()) { + private fun notifyFinish(subject: Subject) = finalNotify(subject.notifyId) { broadcast(1f, subject) - it.setIntent(subject) + it.setContentIntent(subject.pendingIntent(this)) .setContentTitle(subject.title) .setContentText(getString(R.string.download_complete)) .setSmallIcon(android.R.drawable.stat_sys_download_done) @@ -135,17 +127,14 @@ class DownloadService : BaseService() { .setAutoCancel(true) } - private fun finalNotify( - id: Int, - editor: (Notification.Builder) -> Notification.Builder - ) : Int { - val notification = remove(id)?.run(editor) ?: return -1 - val newId = nextInt() + private fun finalNotify(id: Int, editor: (Notification.Builder) -> Unit): Int { + val notification = remove(id)?.also(editor) ?: return -1 + val newId = Notifications.nextId() mgr.notify(newId, notification.build()) return newId } - fun create() = Notifications.progress(this, "") + private fun create() = Notifications.progress(this, "") fun update(id: Int, editor: (Notification.Builder) -> Unit = {}) { val wasEmpty = !hasNotifications @@ -171,49 +160,9 @@ class DownloadService : BaseService() { } } - private fun Notification.Builder.setIntent(subject: Subject) = when (subject) { - is Module -> setIntent(subject) - is Manager -> setIntent(subject) - } - - private fun Notification.Builder.setIntent(subject: Module) - = when (subject.action) { - Flash -> setContentIntent(FlashFragment.installIntent(context, subject.file)) - else -> setContentIntent(Intent()) - } - - private fun Notification.Builder.setIntent(subject: Manager) = - setContentIntent(APKInstall.installIntent(context, subject.file.toFile())) - - @SuppressLint("InlinedApi") - private fun Notification.Builder.setContentIntent(intent: Intent) = - setContentIntent(PendingIntent.getActivity(context, nextInt(), intent, - PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_ONE_SHOT)) - - // -- Post download processing - - private fun onFinish(subject: Subject, id: Int) = when (subject) { - is Module -> subject.onFinish(id) - is Manager -> subject.onFinish(id) - } - - private fun Module.onFinish(id: Int) = when (action) { - Flash -> { - UiThreadHandler.run { - (ForegroundTracker.foreground as? BaseUIActivity<*, *>) - ?.navigation?.navigate(FlashFragment.install(file, id)) - } - } - else -> Unit - } - - private fun Manager.onFinish(id: Int) { - remove(id) - APKInstall.install(context, file.toFile()) - } - companion object { private const val SUBJECT_KEY = "download_subject" + private const val REQUEST_CODE = 1 private val progressBroadcast = MutableLiveData?>() @@ -233,13 +182,13 @@ class DownloadService : BaseService() { context.intent().putExtra(SUBJECT_KEY, subject) @SuppressLint("InlinedApi") - fun pendingIntent(context: Context, subject: Subject): PendingIntent { + fun getPendingIntent(context: Context, subject: Subject): PendingIntent { + val flag = FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT or FLAG_ONE_SHOT + val intent = intent(context, subject) return if (Build.VERSION.SDK_INT >= 26) { - PendingIntent.getForegroundService(context, nextInt(), intent(context, subject), - PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT) + getForegroundService(context, REQUEST_CODE, intent, flag) } else { - PendingIntent.getService(context, nextInt(), intent(context, subject), - PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT) + getService(context, REQUEST_CODE, intent, flag) } } diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/ManagerHandler.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/ManagerHandler.kt index 101d4cea0..9e3f0c4f4 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/download/ManagerHandler.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/download/ManagerHandler.kt @@ -1,6 +1,5 @@ package com.topjohnwu.magisk.core.download -import android.content.Context import androidx.core.net.toFile import com.topjohnwu.magisk.DynAPK import com.topjohnwu.magisk.R @@ -8,29 +7,14 @@ import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.isRunningAsStub import com.topjohnwu.magisk.core.tasks.HideAPK import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream +import com.topjohnwu.magisk.ktx.copyAndClose import com.topjohnwu.magisk.ktx.relaunchApp -import com.topjohnwu.magisk.ktx.withStreams import com.topjohnwu.magisk.ktx.writeTo import java.io.File import java.io.InputStream import java.io.OutputStream -private fun Context.patch(apk: File) { - val patched = File(apk.parent, "patched.apk") - HideAPK.patch(this, apk, patched, packageName, applicationInfo.nonLocalizedLabel) - apk.delete() - patched.renameTo(apk) -} - -private fun DownloadService.notifyHide(id: Int) { - update(id) { - it.setProgress(0, 0, true) - .setContentTitle(getString(R.string.hide_app_title)) - .setContentText("") - } -} - -private class DupOutputStream( +private class TeeOutputStream( private val o1: OutputStream, private val o2: OutputStream ) : OutputStream() { @@ -50,20 +34,26 @@ private class DupOutputStream( suspend fun DownloadService.handleAPK(subject: Subject.Manager, stream: InputStream) { fun write(output: OutputStream) { - val ext = subject.externalFile.outputStream() - val o = DupOutputStream(ext, output) - withStreams(stream, o) { src, out -> src.copyTo(out) } + val external = subject.externalFile.outputStream() + stream.copyAndClose(TeeOutputStream(external, output)) } if (isRunningAsStub) { val apk = subject.file.toFile() - val id = subject.notifyID() + val id = subject.notifyId write(DynAPK.update(this).outputStream()) if (Info.stub!!.version < subject.stub.versionCode) { // Also upgrade stub - notifyHide(id) + update(id) { + it.setProgress(0, 0, true) + .setContentTitle(getString(R.string.hide_app_title)) + .setContentText("") + } service.fetchFile(subject.stub.link).byteStream().writeTo(apk) - patch(apk) + val patched = File(apk.parent, "patched.apk") + HideAPK.patch(this, apk, patched, packageName, applicationInfo.nonLocalizedLabel) + apk.delete() + patched.renameTo(apk) } else { // Simply relaunch the app stopSelf() diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/ModuleProcessor.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/ModuleProcessor.kt deleted file mode 100644 index 7c891fb45..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/core/download/ModuleProcessor.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.topjohnwu.magisk.core.download - -import android.net.Uri -import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream -import com.topjohnwu.magisk.ktx.forEach -import com.topjohnwu.magisk.ktx.withStreams -import java.io.InputStream -import java.util.zip.ZipEntry -import java.util.zip.ZipInputStream -import java.util.zip.ZipOutputStream - -fun InputStream.toModule(file: Uri, installer: InputStream) { - - val input = ZipInputStream(buffered()) - val output = ZipOutputStream(file.outputStream().buffered()) - - withStreams(input, output) { zin, zout -> - zout.putNextEntry(ZipEntry("META-INF/")) - zout.putNextEntry(ZipEntry("META-INF/com/")) - zout.putNextEntry(ZipEntry("META-INF/com/google/")) - zout.putNextEntry(ZipEntry("META-INF/com/google/android/")) - zout.putNextEntry(ZipEntry("META-INF/com/google/android/update-binary")) - installer.copyTo(zout) - - zout.putNextEntry(ZipEntry("META-INF/com/google/android/updater-script")) - zout.write("#MAGISK\n".toByteArray(charset("UTF-8"))) - - var off = -1 - zin.forEach { entry -> - if (off < 0) { - off = entry.name.indexOf('/') + 1 - } - - val path = entry.name.substring(off) - if (path.isNotEmpty() && !path.startsWith("META-INF")) { - zout.putNextEntry(ZipEntry(path)) - if (!entry.isDirectory) { - zin.copyTo(zout) - } - } - } - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt index 47bb50062..f635e805b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt @@ -1,7 +1,12 @@ package com.topjohnwu.magisk.core.download +import android.annotation.SuppressLint +import android.app.PendingIntent +import android.content.Context +import android.content.Intent import android.net.Uri import android.os.Parcelable +import androidx.core.net.toFile import androidx.core.net.toUri import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.model.MagiskJson @@ -10,22 +15,33 @@ import com.topjohnwu.magisk.core.model.module.OnlineModule import com.topjohnwu.magisk.core.utils.MediaStoreUtils import com.topjohnwu.magisk.di.AppContext import com.topjohnwu.magisk.ktx.cachedFile +import com.topjohnwu.magisk.ui.flash.FlashFragment +import com.topjohnwu.magisk.utils.APKInstall +import com.topjohnwu.magisk.view.Notifications import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize private fun cachedFile(name: String) = AppContext.cachedFile(name).apply { delete() }.toUri() +enum class Action { + Flash, + Download +} + sealed class Subject : Parcelable { abstract val url: String abstract val file: Uri - abstract val action: Action abstract val title: String + abstract val notifyId: Int + + abstract fun pendingIntent(context: Context): PendingIntent @Parcelize class Module( val module: OnlineModule, - override val action: Action + val action: Action, + override val notifyId: Int = Notifications.nextId() ) : Subject() { override val url: String get() = module.zip_url override val title: String get() = module.downloadFilename @@ -34,14 +50,19 @@ sealed class Subject : Parcelable { override val file by lazy { MediaStoreUtils.getFile(title).uri } + + override fun pendingIntent(context: Context) = when (action) { + Action.Flash -> FlashFragment.installIntent(context, file) + else -> Intent().toPending(context) + } } @Parcelize class Manager( private val json: MagiskJson = Info.remote.magisk, - val stub: StubJson = Info.remote.stub + val stub: StubJson = Info.remote.stub, + override val notifyId: Int = Notifications.nextId() ) : Subject() { - override val action get() = Action.Download override val title: String get() = "Magisk-${json.version}(${json.versionCode})" override val url: String get() = json.link @@ -51,15 +72,14 @@ sealed class Subject : Parcelable { } val externalFile get() = MediaStoreUtils.getFile("$title.apk").uri + + override fun pendingIntent(context: Context) = + APKInstall.installIntent(context, file.toFile()).toPending(context) } - fun notifyID() = hashCode() -} - -sealed class Action : Parcelable { - @Parcelize - object Flash : Action() - - @Parcelize - object Download : Action() + @SuppressLint("InlinedApi") + protected fun Intent.toPending(context: Context): PendingIntent { + return PendingIntent.getActivity(context, notifyId, this, + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_ONE_SHOT) + } } diff --git a/app/src/main/java/com/topjohnwu/magisk/core/utils/ProgressInputStream.kt b/app/src/main/java/com/topjohnwu/magisk/core/utils/ProgressInputStream.kt index 5dfa45a7b..8de8799c1 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/utils/ProgressInputStream.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/utils/ProgressInputStream.kt @@ -5,7 +5,7 @@ import java.io.InputStream class ProgressInputStream( base: InputStream, - val progressEmitter: (Long) -> Unit = {} + val progressEmitter: (Long) -> Unit ) : FilterInputStream(base) { private var bytesRead = 0L @@ -40,4 +40,9 @@ class ProgressInputStream( } return sz } + + override fun close() { + super.close() + progressEmitter(bytesRead) + } } diff --git a/app/src/main/java/com/topjohnwu/magisk/events/dialog/ModuleInstallDialog.kt b/app/src/main/java/com/topjohnwu/magisk/events/dialog/ModuleInstallDialog.kt index 0e0711940..2b70df116 100644 --- a/app/src/main/java/com/topjohnwu/magisk/events/dialog/ModuleInstallDialog.kt +++ b/app/src/main/java/com/topjohnwu/magisk/events/dialog/ModuleInstallDialog.kt @@ -14,8 +14,8 @@ class ModuleInstallDialog(private val item: OnlineModule) : DialogEvent() { with(dialog) { fun download(install: Boolean) { - val config = if (install) Action.Flash else Action.Download - val subject = Subject.Module(item, config) + val action = if (install) Action.Flash else Action.Download + val subject = Subject.Module(item, action) DownloadService.start(context, subject) } diff --git a/app/src/main/java/com/topjohnwu/magisk/ktx/XJava.kt b/app/src/main/java/com/topjohnwu/magisk/ktx/XJava.kt index a3a725515..1e6c32f56 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ktx/XJava.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ktx/XJava.kt @@ -19,9 +19,6 @@ inline fun ZipInputStream.forEach(callback: (ZipEntry) -> Unit) { } } -fun InputStream.writeTo(file: File) = - withStreams(this, file.outputStream()) { reader, writer -> reader.copyTo(writer) } - inline fun withStreams( inStream: In, outStream: Out, @@ -34,18 +31,19 @@ inline fun withStreams( } } -fun MutableList.update(newList: List) { - clear() - addAll(newList) -} +fun InputStream.copyAndClose(out: OutputStream) = withStreams(this, out) { i, o -> i.copyTo(o) } + +fun InputStream.writeTo(file: File) = copyAndClose(file.outputStream()) operator fun SparseArrayCompat.set(key: Int, value: E) { put(key, value) } -fun MutableList.synchronized() = Collections.synchronizedList(this) -fun MutableSet.synchronized() = Collections.synchronizedSet(this) -fun MutableMap.synchronized() = Collections.synchronizedMap(this) +fun MutableList.synchronized(): MutableList = Collections.synchronizedList(this) + +fun MutableSet.synchronized(): MutableSet = Collections.synchronizedSet(this) + +fun MutableMap.synchronized(): MutableMap = Collections.synchronizedMap(this) fun SimpleDateFormat.parseOrNull(date: String) = runCatching { parse(date) }.onFailure { Timber.e(it) }.getOrNull() diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt index 8c63e43bb..9151dc3a9 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt @@ -111,16 +111,14 @@ class FlashFragment : BaseUIFragment() /* Installing is understood as flashing modules / zips */ - fun installIntent(context: Context, file: Uri, id: Int = -1) = FlashFragmentArgs( + fun installIntent(context: Context, file: Uri) = FlashFragmentArgs( action = Const.Value.FLASH_ZIP, additionalData = file, - dismissId = id ).let { createIntent(context, it) } - fun install(file: Uri, id: Int) = MainDirections.actionFlashFragment( + fun install(file: Uri) = MainDirections.actionFlashFragment( action = Const.Value.FLASH_ZIP, additionalData = file, - dismissId = id ) } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt index 14b88fd13..02aa41992 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt @@ -20,7 +20,6 @@ import com.topjohnwu.magisk.databinding.itemBindingOf import com.topjohnwu.magisk.databinding.set import com.topjohnwu.magisk.events.SnackbarEvent import com.topjohnwu.magisk.ktx.* -import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.superuser.CallbackList import com.topjohnwu.superuser.Shell import kotlinx.coroutines.Dispatchers @@ -50,9 +49,7 @@ class FlashViewModel : BaseViewModel() { } fun startFlashing() { - val (action, uri, id) = args - if (id != -1) - Notifications.mgr.cancel(id) + val (action, uri) = args viewModelScope.launch { val result = when (action) { diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt index 21c460f97..f4bacb1f2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt @@ -70,4 +70,8 @@ class HomeFragment : BaseUIFragment() { return true } + override fun onResume() { + super.onResume() + viewModel.stateManagerProgress = 0 + } } diff --git a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt index d14749945..f095f7de0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt @@ -8,19 +8,22 @@ import android.os.Build.VERSION.SDK_INT import androidx.core.content.getSystemService import androidx.core.graphics.drawable.toIcon import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Const.ID.PROGRESS_NOTIFICATION_CHANNEL import com.topjohnwu.magisk.core.Const.ID.UPDATE_NOTIFICATION_CHANNEL import com.topjohnwu.magisk.core.download.DownloadService import com.topjohnwu.magisk.core.download.Subject import com.topjohnwu.magisk.di.AppContext import com.topjohnwu.magisk.ktx.getBitmap +import java.util.concurrent.atomic.AtomicInteger @Suppress("DEPRECATION") object Notifications { val mgr by lazy { AppContext.getSystemService()!! } + private const val APK_UPDATE_NOTIFICATION_ID = 5 + private val nextId = AtomicInteger(APK_UPDATE_NOTIFICATION_ID) + fun setup(context: Context) { if (SDK_INT >= 26) { var channel = NotificationChannel(UPDATE_NOTIFICATION_CHANNEL, @@ -46,7 +49,7 @@ object Notifications { } fun managerUpdate(context: Context) { - val intent = DownloadService.pendingIntent(context, Subject.Manager()) + val intent = DownloadService.getPendingIntent(context, Subject.Manager()) val builder = updateBuilder(context) .setContentTitle(context.getString(R.string.magisk_update_title)) @@ -54,7 +57,7 @@ object Notifications { .setAutoCancel(true) .setContentIntent(intent) - mgr.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build()) + mgr.notify(APK_UPDATE_NOTIFICATION_ID, builder.build()) } fun progress(context: Context, title: CharSequence): Notification.Builder { @@ -69,4 +72,6 @@ object Notifications { .setOngoing(true) return builder } + + fun nextId() = nextId.incrementAndGet() } diff --git a/app/src/main/res/navigation/main.xml b/app/src/main/res/navigation/main.xml index 7cf95732f..5e2680680 100644 --- a/app/src/main/res/navigation/main.xml +++ b/app/src/main/res/navigation/main.xml @@ -51,11 +51,6 @@ app:argType="android.net.Uri" app:nullable="true" /> - -