mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-25 04:17:38 +00:00
Show notification after app upgrade
This commit is contained in:
parent
2414d5d7f5
commit
256ff31d11
@ -36,7 +36,7 @@ public final class APKInstall {
|
|||||||
// @WorkerThread
|
// @WorkerThread
|
||||||
public static void install(Context context, File apk) {
|
public static void install(Context context, File apk) {
|
||||||
try (var src = new FileInputStream(apk);
|
try (var src = new FileInputStream(apk);
|
||||||
var out = openStream(context, true)) {
|
var out = openStream(context)) {
|
||||||
if (out != null)
|
if (out != null)
|
||||||
transfer(src, out);
|
transfer(src, out);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -44,7 +44,7 @@ public final class APKInstall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OutputStream openStream(Context context, boolean silent) {
|
public static OutputStream openStream(Context context) {
|
||||||
//noinspection InlinedApi
|
//noinspection InlinedApi
|
||||||
var flag = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE;
|
var flag = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE;
|
||||||
var intent = new Intent(ACTION_SESSION_UPDATE).setPackage(context.getPackageName());
|
var intent = new Intent(ACTION_SESSION_UPDATE).setPackage(context.getPackageName());
|
||||||
@ -52,7 +52,7 @@ public final class APKInstall {
|
|||||||
|
|
||||||
var installer = context.getPackageManager().getPackageInstaller();
|
var installer = context.getPackageManager().getPackageInstaller();
|
||||||
var params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
|
var params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
|
||||||
if (silent && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
params.setRequireUserAction(SessionParams.USER_ACTION_NOT_REQUIRED);
|
params.setRequireUserAction(SessionParams.USER_ACTION_NOT_REQUIRED);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.LOCALE_CHANGED" />
|
<action android:name="android.intent.action.LOCALE_CHANGED" />
|
||||||
<action android:name="android.intent.action.UID_REMOVED" />
|
<action android:name="android.intent.action.UID_REMOVED" />
|
||||||
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
||||||
|
@ -61,6 +61,7 @@ object Config : PreferenceModel, DBConfig {
|
|||||||
const val BOOT_ID = "boot_id"
|
const val BOOT_ID = "boot_id"
|
||||||
const val ASKED_HOME = "asked_home"
|
const val ASKED_HOME = "asked_home"
|
||||||
const val DOH = "doh"
|
const val DOH = "doh"
|
||||||
|
const val SHOW_UPDATE_DONE = "update_done"
|
||||||
}
|
}
|
||||||
|
|
||||||
object Value {
|
object Value {
|
||||||
@ -133,6 +134,7 @@ object Config : PreferenceModel, DBConfig {
|
|||||||
var suTapjack by preference(Key.SU_TAPJACK, true)
|
var suTapjack by preference(Key.SU_TAPJACK, true)
|
||||||
var checkUpdate by preference(Key.CHECK_UPDATES, true)
|
var checkUpdate by preference(Key.CHECK_UPDATES, true)
|
||||||
var doh by preference(Key.DOH, false)
|
var doh by preference(Key.DOH, false)
|
||||||
|
var showUpdateDone by preference(Key.SHOW_UPDATE_DONE, false)
|
||||||
var showSystemApp by preference(Key.SHOW_SYSTEM_APP, false)
|
var showSystemApp by preference(Key.SHOW_SYSTEM_APP, false)
|
||||||
|
|
||||||
var customChannelUrl by preference(Key.CUSTOM_CHANNEL, "")
|
var customChannelUrl by preference(Key.CUSTOM_CHANNEL, "")
|
||||||
|
@ -37,8 +37,6 @@ object Const {
|
|||||||
|
|
||||||
object ID {
|
object ID {
|
||||||
const val JOB_SERVICE_ID = 7
|
const val JOB_SERVICE_ID = 7
|
||||||
const val UPDATE_NOTIFICATION_CHANNEL = "update"
|
|
||||||
const val PROGRESS_NOTIFICATION_CHANNEL = "progress"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object Url {
|
object Url {
|
||||||
|
@ -23,16 +23,20 @@ class JobService : BaseJobService() {
|
|||||||
override fun onStartJob(params: JobParameters): Boolean {
|
override fun onStartJob(params: JobParameters): Boolean {
|
||||||
val coroutineScope = CoroutineScope(Dispatchers.IO + job)
|
val coroutineScope = CoroutineScope(Dispatchers.IO + job)
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
svc.fetchUpdate()?.run {
|
doWork()
|
||||||
Info.remote = this
|
|
||||||
if (Info.env.isActive && BuildConfig.VERSION_CODE < magisk.versionCode)
|
|
||||||
Notifications.managerUpdate(this@JobService)
|
|
||||||
}
|
|
||||||
jobFinished(params, false)
|
jobFinished(params, false)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun doWork() {
|
||||||
|
svc.fetchUpdate()?.let {
|
||||||
|
Info.remote = it
|
||||||
|
if (Info.env.isActive && BuildConfig.VERSION_CODE < it.magisk.versionCode)
|
||||||
|
Notifications.updateAvailable(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onStopJob(params: JobParameters): Boolean {
|
override fun onStopJob(params: JobParameters): Boolean {
|
||||||
job.cancel()
|
job.cancel()
|
||||||
return false
|
return false
|
||||||
|
@ -5,6 +5,7 @@ import android.content.ContextWrapper
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import com.topjohnwu.magisk.core.base.BaseReceiver
|
import com.topjohnwu.magisk.core.base.BaseReceiver
|
||||||
import com.topjohnwu.magisk.di.ServiceLocator
|
import com.topjohnwu.magisk.di.ServiceLocator
|
||||||
|
import com.topjohnwu.magisk.view.Notifications
|
||||||
import com.topjohnwu.magisk.view.Shortcuts
|
import com.topjohnwu.magisk.view.Shortcuts
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
@ -45,6 +46,12 @@ open class Receiver : BaseReceiver() {
|
|||||||
getPkg(intent)?.let { Shell.su("magisk --denylist rm $it").submit() }
|
getPkg(intent)?.let { Shell.su("magisk --denylist rm $it").submit() }
|
||||||
}
|
}
|
||||||
Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setupDynamic(context)
|
Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setupDynamic(context)
|
||||||
|
Intent.ACTION_MY_PACKAGE_REPLACED -> {
|
||||||
|
if (Config.showUpdateDone) {
|
||||||
|
Notifications.updateDone(context)
|
||||||
|
Config.showUpdateDone = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,7 @@ import androidx.core.net.toFile
|
|||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.StubApk
|
import com.topjohnwu.magisk.StubApk
|
||||||
import com.topjohnwu.magisk.core.ActivityTracker
|
import com.topjohnwu.magisk.core.*
|
||||||
import com.topjohnwu.magisk.core.Info
|
|
||||||
import com.topjohnwu.magisk.core.intent
|
|
||||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
|
||||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
||||||
import com.topjohnwu.magisk.ktx.copyAndClose
|
import com.topjohnwu.magisk.ktx.copyAndClose
|
||||||
@ -75,32 +72,49 @@ class DownloadService : NotificationService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun openApkSession(): OutputStream {
|
||||||
|
Config.showUpdateDone = true
|
||||||
|
return APKInstall.openStream(this)
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun handleApp(stream: InputStream, subject: Subject.App) {
|
private suspend fun handleApp(stream: InputStream, subject: Subject.App) {
|
||||||
fun write(output: OutputStream) {
|
fun writeTee(output: OutputStream) {
|
||||||
val external = subject.externalFile.outputStream()
|
val external = subject.externalFile.outputStream()
|
||||||
stream.copyAndClose(TeeOutputStream(external, output))
|
stream.copyAndClose(TeeOutputStream(external, output))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRunningAsStub) {
|
if (isRunningAsStub) {
|
||||||
val apk = subject.file.toFile()
|
val updateApk = StubApk.update(this)
|
||||||
val id = subject.notifyId
|
|
||||||
try {
|
try {
|
||||||
write(StubApk.update(this).outputStream())
|
// Download full APK to stub update path
|
||||||
|
writeTee(updateApk.outputStream())
|
||||||
|
|
||||||
if (Info.stub!!.version < subject.stub.versionCode) {
|
if (Info.stub!!.version < subject.stub.versionCode) {
|
||||||
// Also upgrade stub
|
// Also upgrade stub
|
||||||
update(id) {
|
update(subject.notifyId) {
|
||||||
it.setProgress(0, 0, true)
|
it.setProgress(0, 0, true)
|
||||||
.setContentTitle(getString(R.string.hide_app_title))
|
.setContentTitle(getString(R.string.hide_app_title))
|
||||||
.setContentText("")
|
.setContentText("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Download
|
||||||
|
val apk = subject.file.toFile()
|
||||||
service.fetchFile(subject.stub.link).byteStream().writeTo(apk)
|
service.fetchFile(subject.stub.link).byteStream().writeTo(apk)
|
||||||
|
|
||||||
|
// Patch
|
||||||
val patched = File(apk.parent, "patched.apk")
|
val patched = File(apk.parent, "patched.apk")
|
||||||
val label = applicationInfo.nonLocalizedLabel
|
val label = applicationInfo.nonLocalizedLabel
|
||||||
if (!HideAPK.patch(this, apk, patched, packageName, label)) {
|
if (!HideAPK.patch(this, apk, patched, packageName, label)) {
|
||||||
throw IOException("HideAPK patch error")
|
throw IOException("HideAPK patch error")
|
||||||
}
|
}
|
||||||
apk.delete()
|
apk.delete()
|
||||||
patched.renameTo(apk)
|
|
||||||
|
// Install
|
||||||
|
val receiver = APKInstall.register(this, null, null)
|
||||||
|
patched.inputStream().copyAndClose(openApkSession())
|
||||||
|
subject.intent = receiver.waitIntent()
|
||||||
|
|
||||||
|
patched.delete()
|
||||||
} else {
|
} else {
|
||||||
ActivityTracker.foreground?.let {
|
ActivityTracker.foreground?.let {
|
||||||
// Relaunch the process if we are foreground
|
// Relaunch the process if we are foreground
|
||||||
@ -112,13 +126,16 @@ class DownloadService : NotificationService() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
StubApk.update(this).delete()
|
// If any error occurred, do not let stub load the new APK
|
||||||
}
|
updateApk.delete()
|
||||||
|
throw e
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
val receiver = APKInstall.register(this, null, null)
|
val receiver = APKInstall.register(this, null, null)
|
||||||
write(APKInstall.openStream(this, false))
|
writeTee(openApkSession())
|
||||||
subject.intent = receiver.waitIntent()
|
subject.intent = receiver.waitIntent()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleModule(src: InputStream, file: Uri) {
|
private fun handleModule(src: InputStream, file: Uri) {
|
||||||
val input = ZipInputStream(src.buffered())
|
val input = ZipInputStream(src.buffered())
|
||||||
|
@ -15,7 +15,10 @@ import com.topjohnwu.magisk.MainDirections
|
|||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.BaseMainActivity
|
import com.topjohnwu.magisk.arch.BaseMainActivity
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||||
import com.topjohnwu.magisk.core.*
|
import com.topjohnwu.magisk.core.Config
|
||||||
|
import com.topjohnwu.magisk.core.Const
|
||||||
|
import com.topjohnwu.magisk.core.Info
|
||||||
|
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||||
import com.topjohnwu.magisk.databinding.ActivityMainMd2Binding
|
import com.topjohnwu.magisk.databinding.ActivityMainMd2Binding
|
||||||
import com.topjohnwu.magisk.di.viewModel
|
import com.topjohnwu.magisk.di.viewModel
|
||||||
import com.topjohnwu.magisk.ktx.startAnimations
|
import com.topjohnwu.magisk.ktx.startAnimations
|
||||||
@ -48,10 +51,11 @@ class MainActivity : BaseMainActivity<ActivityMainMd2Binding>() {
|
|||||||
setContentView()
|
setContentView()
|
||||||
showUnsupportedMessage()
|
showUnsupportedMessage()
|
||||||
askForHomeShortcut()
|
askForHomeShortcut()
|
||||||
|
Config.showUpdateDone = false
|
||||||
|
|
||||||
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
|
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
|
||||||
|
|
||||||
navigation?.addOnDestinationChangedListener { _, destination, _ ->
|
navigation.addOnDestinationChangedListener { _, destination, _ ->
|
||||||
isRootFragment = when (destination.id) {
|
isRootFragment = when (destination.id) {
|
||||||
R.id.homeFragment,
|
R.id.homeFragment,
|
||||||
R.id.modulesFragment,
|
R.id.modulesFragment,
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
package com.topjohnwu.magisk.view
|
package com.topjohnwu.magisk.view
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Build.VERSION.SDK_INT
|
import android.os.Build.VERSION.SDK_INT
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.graphics.drawable.toIcon
|
import androidx.core.graphics.drawable.toIcon
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
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.DownloadService
|
||||||
import com.topjohnwu.magisk.core.download.Subject
|
import com.topjohnwu.magisk.core.download.Subject
|
||||||
import com.topjohnwu.magisk.di.AppContext
|
import com.topjohnwu.magisk.di.AppContext
|
||||||
@ -21,51 +22,75 @@ object Notifications {
|
|||||||
|
|
||||||
val mgr by lazy { AppContext.getSystemService<NotificationManager>()!! }
|
val mgr by lazy { AppContext.getSystemService<NotificationManager>()!! }
|
||||||
|
|
||||||
private const val APK_UPDATE_NOTIFICATION_ID = 5
|
private const val APP_UPDATED_NOTIFICATION_ID = 4
|
||||||
private val nextId = AtomicInteger(APK_UPDATE_NOTIFICATION_ID)
|
private const val APP_UPDATE_NOTIFICATION_ID = 5
|
||||||
|
|
||||||
|
private const val UPDATE_CHANNEL = "update"
|
||||||
|
private const val PROGRESS_CHANNEL = "progress"
|
||||||
|
private const val UPDATED_CHANNEL = "updated"
|
||||||
|
|
||||||
|
private val nextId = AtomicInteger(APP_UPDATE_NOTIFICATION_ID)
|
||||||
|
|
||||||
fun setup(context: Context) {
|
fun setup(context: Context) {
|
||||||
if (SDK_INT >= 26) {
|
if (SDK_INT >= 26) {
|
||||||
val channel = NotificationChannel(UPDATE_NOTIFICATION_CHANNEL,
|
val channel = NotificationChannel(UPDATE_CHANNEL,
|
||||||
context.getString(R.string.update_channel), NotificationManager.IMPORTANCE_DEFAULT)
|
context.getString(R.string.update_channel), NotificationManager.IMPORTANCE_DEFAULT)
|
||||||
val channel2 = NotificationChannel(PROGRESS_NOTIFICATION_CHANNEL,
|
val channel2 = NotificationChannel(PROGRESS_CHANNEL,
|
||||||
context.getString(R.string.progress_channel), NotificationManager.IMPORTANCE_LOW)
|
context.getString(R.string.progress_channel), NotificationManager.IMPORTANCE_LOW)
|
||||||
mgr.createNotificationChannels(listOf(channel, channel2))
|
val channel3 = NotificationChannel(UPDATED_CHANNEL,
|
||||||
|
context.getString(R.string.updated_channel), NotificationManager.IMPORTANCE_HIGH)
|
||||||
|
mgr.createNotificationChannels(listOf(channel, channel2, channel3))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateBuilder(context: Context): Notification.Builder {
|
@SuppressLint("InlinedApi")
|
||||||
return Notification.Builder(context).apply {
|
fun updateDone(context: Context) {
|
||||||
val bitmap = context.getBitmap(R.drawable.ic_magisk_outline)
|
val pm = context.packageManager
|
||||||
setLargeIcon(bitmap)
|
val intent = pm.getLaunchIntentForPackage(context.packageName) ?: return
|
||||||
if (SDK_INT >= 26) {
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||||
setSmallIcon(bitmap.toIcon())
|
val flag = PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
setChannelId(UPDATE_NOTIFICATION_CHANNEL)
|
val pending = PendingIntent.getActivity(context, 0, intent, flag)
|
||||||
|
val builder = if (SDK_INT >= 26) {
|
||||||
|
Notification.Builder(context, UPDATED_CHANNEL)
|
||||||
|
.setSmallIcon(context.getBitmap(R.drawable.ic_magisk_outline).toIcon())
|
||||||
} else {
|
} else {
|
||||||
setSmallIcon(R.drawable.ic_magisk_outline)
|
Notification.Builder(context).setPriority(Notification.PRIORITY_HIGH)
|
||||||
}
|
.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||||
}
|
}
|
||||||
|
.setContentIntent(pending)
|
||||||
|
.setContentTitle(context.getText(R.string.updated_title))
|
||||||
|
.setContentText(context.getText(R.string.updated_text))
|
||||||
|
.setAutoCancel(true)
|
||||||
|
mgr.notify(APP_UPDATED_NOTIFICATION_ID, builder.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun managerUpdate(context: Context) {
|
fun updateAvailable(context: Context) {
|
||||||
val intent = DownloadService.getPendingIntent(context, Subject.App())
|
val intent = DownloadService.getPendingIntent(context, Subject.App())
|
||||||
|
|
||||||
val builder = updateBuilder(context)
|
val bitmap = context.getBitmap(R.drawable.ic_magisk_outline)
|
||||||
|
val builder = if (SDK_INT >= 26) {
|
||||||
|
Notification.Builder(context, UPDATE_CHANNEL)
|
||||||
|
.setSmallIcon(bitmap.toIcon())
|
||||||
|
} else {
|
||||||
|
Notification.Builder(context)
|
||||||
|
.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||||
|
}
|
||||||
|
.setLargeIcon(bitmap)
|
||||||
.setContentTitle(context.getString(R.string.magisk_update_title))
|
.setContentTitle(context.getString(R.string.magisk_update_title))
|
||||||
.setContentText(context.getString(R.string.manager_download_install))
|
.setContentText(context.getString(R.string.manager_download_install))
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setContentIntent(intent)
|
.setContentIntent(intent)
|
||||||
|
|
||||||
mgr.notify(APK_UPDATE_NOTIFICATION_ID, builder.build())
|
mgr.notify(APP_UPDATE_NOTIFICATION_ID, builder.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun progress(context: Context, title: CharSequence): Notification.Builder {
|
fun progress(context: Context, title: CharSequence): Notification.Builder {
|
||||||
val builder = if (SDK_INT >= 26) {
|
val builder = if (SDK_INT >= 26) {
|
||||||
Notification.Builder(context, PROGRESS_NOTIFICATION_CHANNEL)
|
Notification.Builder(context, PROGRESS_CHANNEL)
|
||||||
} else {
|
} else {
|
||||||
Notification.Builder(context).setPriority(Notification.PRIORITY_LOW)
|
Notification.Builder(context).setPriority(Notification.PRIORITY_LOW)
|
||||||
}
|
}
|
||||||
builder.setSmallIcon(android.R.drawable.stat_sys_download)
|
.setSmallIcon(android.R.drawable.stat_sys_download)
|
||||||
.setContentTitle(title)
|
.setContentTitle(title)
|
||||||
.setProgress(0, 0, true)
|
.setProgress(0, 0, true)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
|
@ -190,9 +190,12 @@
|
|||||||
<!--Notifications-->
|
<!--Notifications-->
|
||||||
<string name="update_channel">Magisk Updates</string>
|
<string name="update_channel">Magisk Updates</string>
|
||||||
<string name="progress_channel">Progress Notifications</string>
|
<string name="progress_channel">Progress Notifications</string>
|
||||||
|
<string name="updated_channel">Update Complete</string>
|
||||||
<string name="download_complete">Download complete</string>
|
<string name="download_complete">Download complete</string>
|
||||||
<string name="download_file_error">Error downloading file</string>
|
<string name="download_file_error">Error downloading file</string>
|
||||||
<string name="magisk_update_title">Magisk Update Available!</string>
|
<string name="magisk_update_title">Magisk Update Available!</string>
|
||||||
|
<string name="updated_title">Magisk Updated</string>
|
||||||
|
<string name="updated_text">Tap to open app</string>
|
||||||
|
|
||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Yes</string>
|
<string name="yes">Yes</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user