Send bitmap to notifications and shortcuts
On API 23+, the platform unifies the way to handle drawable resources across processes: all drawables can be passed via Icon. This allows us to send raw bitmap to the system without the need to specify a resource ID. This means that we are allowed to NOT include these drawable resources within our stub APK, since our full APK can draw the images programmatically and send raw bitmaps to the system.
This commit is contained in:
parent
5e87483f34
commit
fdf04f77f2
@ -73,17 +73,6 @@ fun Context.intent(c: Class<*>): Intent {
|
|||||||
} ?: Intent(this, cls)
|
} ?: Intent(this, cls)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resolveRes(idx: Int): Int {
|
|
||||||
return Info.stub?.resourceMap?.get(idx) ?: when(idx) {
|
|
||||||
DynAPK.NOTIFICATION -> R.drawable.ic_magisk_outline
|
|
||||||
DynAPK.DOWNLOAD -> R.drawable.sc_cloud_download
|
|
||||||
DynAPK.SUPERUSER -> R.drawable.sc_superuser
|
|
||||||
DynAPK.MODULES -> R.drawable.sc_extension
|
|
||||||
DynAPK.MAGISKHIDE -> R.drawable.sc_magiskhide
|
|
||||||
else -> -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private open class GlobalResContext(base: Context) : ContextWrapper(base) {
|
private open class GlobalResContext(base: Context) : ContextWrapper(base) {
|
||||||
open val mRes: Resources get() = ResourceMgr.resource
|
open val mRes: Resources get() = ResourceMgr.resource
|
||||||
private val loader by lazy { javaClass.classLoader!! }
|
private val loader by lazy { javaClass.classLoader!! }
|
||||||
|
@ -12,12 +12,19 @@ import android.content.pm.PackageManager.*
|
|||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.drawable.AdaptiveIconDrawable
|
||||||
|
import android.graphics.drawable.BitmapDrawable
|
||||||
|
import android.graphics.drawable.LayerDrawable
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.os.Build.VERSION.SDK_INT
|
||||||
import android.provider.OpenableColumns
|
import android.provider.OpenableColumns
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.annotation.ColorRes
|
import androidx.annotation.ColorRes
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import com.topjohnwu.magisk.Const
|
import com.topjohnwu.magisk.Const
|
||||||
@ -97,6 +104,23 @@ fun Context.rawResource(id: Int) = resources.openRawResource(id)
|
|||||||
fun Context.readUri(uri: Uri) =
|
fun Context.readUri(uri: Uri) =
|
||||||
contentResolver.openInputStream(uri) ?: throw FileNotFoundException()
|
contentResolver.openInputStream(uri) ?: throw FileNotFoundException()
|
||||||
|
|
||||||
|
fun Context.getBitmap(id: Int): Bitmap {
|
||||||
|
var drawable = AppCompatResources.getDrawable(this, id)!!
|
||||||
|
if (drawable is BitmapDrawable)
|
||||||
|
return drawable.bitmap
|
||||||
|
if (SDK_INT >= 26 && drawable is AdaptiveIconDrawable) {
|
||||||
|
drawable = LayerDrawable(arrayOf(drawable.background, drawable.foreground))
|
||||||
|
}
|
||||||
|
val bitmap = Bitmap.createBitmap(
|
||||||
|
drawable.intrinsicWidth, drawable.intrinsicHeight,
|
||||||
|
Bitmap.Config.ARGB_8888
|
||||||
|
)
|
||||||
|
val canvas = Canvas(bitmap)
|
||||||
|
drawable.setBounds(0, 0, canvas.width, canvas.height)
|
||||||
|
drawable.draw(canvas)
|
||||||
|
return bitmap
|
||||||
|
}
|
||||||
|
|
||||||
fun Intent.startActivity(context: Context) = context.startActivity(this)
|
fun Intent.startActivity(context: Context) = context.startActivity(this)
|
||||||
|
|
||||||
fun Intent.startActivityWithRoot() {
|
fun Intent.startActivityWithRoot() {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package com.topjohnwu.magisk.model.download
|
package com.topjohnwu.magisk.model.download
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Notification
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.webkit.MimeTypeMap
|
import android.webkit.MimeTypeMap
|
||||||
import androidx.core.app.NotificationCompat
|
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.extensions.chooser
|
import com.topjohnwu.magisk.extensions.chooser
|
||||||
import com.topjohnwu.magisk.extensions.exists
|
import com.topjohnwu.magisk.extensions.exists
|
||||||
@ -69,14 +69,14 @@ open class DownloadService : RemoteFileService() {
|
|||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
override fun NotificationCompat.Builder.addActions(subject: DownloadSubject)
|
override fun Notification.Builder.addActions(subject: DownloadSubject)
|
||||||
= when (subject) {
|
= when (subject) {
|
||||||
is Magisk -> addActionsInternal(subject)
|
is Magisk -> addActionsInternal(subject)
|
||||||
is Module -> addActionsInternal(subject)
|
is Module -> addActionsInternal(subject)
|
||||||
is Manager -> addActionsInternal(subject)
|
is Manager -> addActionsInternal(subject)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun NotificationCompat.Builder.addActionsInternal(subject: Magisk)
|
private fun Notification.Builder.addActionsInternal(subject: Magisk)
|
||||||
= when (val conf = subject.configuration) {
|
= when (val conf = subject.configuration) {
|
||||||
Download -> this.apply {
|
Download -> this.apply {
|
||||||
fileIntent(subject.file.parentFile!!)
|
fileIntent(subject.file.parentFile!!)
|
||||||
@ -92,7 +92,7 @@ open class DownloadService : RemoteFileService() {
|
|||||||
else -> this
|
else -> this
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun NotificationCompat.Builder.addActionsInternal(subject: Module)
|
private fun Notification.Builder.addActionsInternal(subject: Module)
|
||||||
= when (subject.configuration) {
|
= when (subject.configuration) {
|
||||||
Download -> this.apply {
|
Download -> this.apply {
|
||||||
fileIntent(subject.file.parentFile!!)
|
fileIntent(subject.file.parentFile!!)
|
||||||
@ -106,19 +106,19 @@ open class DownloadService : RemoteFileService() {
|
|||||||
else -> this
|
else -> this
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun NotificationCompat.Builder.addActionsInternal(subject: Manager)
|
private fun Notification.Builder.addActionsInternal(subject: Manager)
|
||||||
= when (subject.configuration) {
|
= when (subject.configuration) {
|
||||||
APK.Upgrade -> setContentIntent(APKInstall.installIntent(context, subject.file))
|
APK.Upgrade -> setContentIntent(APKInstall.installIntent(context, subject.file))
|
||||||
else -> this
|
else -> this
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("ReplaceSingleLineLet")
|
@Suppress("ReplaceSingleLineLet")
|
||||||
private fun NotificationCompat.Builder.setContentIntent(intent: Intent) =
|
private fun Notification.Builder.setContentIntent(intent: Intent) =
|
||||||
PendingIntent.getActivity(context, nextInt(), intent, PendingIntent.FLAG_ONE_SHOT)
|
PendingIntent.getActivity(context, nextInt(), intent, PendingIntent.FLAG_ONE_SHOT)
|
||||||
.let { setContentIntent(it) }
|
.let { setContentIntent(it) }
|
||||||
|
|
||||||
@Suppress("ReplaceSingleLineLet")
|
@Suppress("ReplaceSingleLineLet")
|
||||||
private fun NotificationCompat.Builder.addAction(icon: Int, title: Int, intent: Intent) =
|
private fun Notification.Builder.addAction(icon: Int, title: Int, intent: Intent) =
|
||||||
PendingIntent.getActivity(context, nextInt(), intent, PendingIntent.FLAG_ONE_SHOT)
|
PendingIntent.getActivity(context, nextInt(), intent, PendingIntent.FLAG_ONE_SHOT)
|
||||||
.let { addAction(icon, getString(title), it) }
|
.let { addAction(icon, getString(title), it) }
|
||||||
|
|
||||||
|
@ -3,22 +3,20 @@ package com.topjohnwu.magisk.model.download
|
|||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import androidx.core.app.NotificationCompat
|
|
||||||
import androidx.core.app.NotificationManagerCompat
|
|
||||||
import com.topjohnwu.magisk.base.BaseService
|
import com.topjohnwu.magisk.base.BaseService
|
||||||
|
import com.topjohnwu.magisk.view.Notifications
|
||||||
import org.koin.core.KoinComponent
|
import org.koin.core.KoinComponent
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.random.Random.Default.nextInt
|
import kotlin.random.Random.Default.nextInt
|
||||||
|
|
||||||
abstract class NotificationService : BaseService(), KoinComponent {
|
abstract class NotificationService : BaseService(), KoinComponent {
|
||||||
|
|
||||||
abstract val defaultNotification: NotificationCompat.Builder
|
abstract val defaultNotification: Notification.Builder
|
||||||
|
|
||||||
private val manager by lazy { NotificationManagerCompat.from(this) }
|
|
||||||
private val hasNotifications get() = notifications.isNotEmpty()
|
private val hasNotifications get() = notifications.isNotEmpty()
|
||||||
|
|
||||||
private val notifications =
|
private val notifications =
|
||||||
Collections.synchronizedMap(mutableMapOf<Int, NotificationCompat.Builder>())
|
Collections.synchronizedMap(mutableMapOf<Int, Notification.Builder>())
|
||||||
|
|
||||||
override fun onTaskRemoved(rootIntent: Intent?) {
|
override fun onTaskRemoved(rootIntent: Intent?) {
|
||||||
super.onTaskRemoved(rootIntent)
|
super.onTaskRemoved(rootIntent)
|
||||||
@ -30,7 +28,7 @@ abstract class NotificationService : BaseService(), KoinComponent {
|
|||||||
|
|
||||||
fun update(
|
fun update(
|
||||||
id: Int,
|
id: Int,
|
||||||
body: (NotificationCompat.Builder) -> Unit = {}
|
body: (Notification.Builder) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val notification = notifications.getOrPut(id) { defaultNotification }
|
val notification = notifications.getOrPut(id) { defaultNotification }
|
||||||
|
|
||||||
@ -43,7 +41,7 @@ abstract class NotificationService : BaseService(), KoinComponent {
|
|||||||
|
|
||||||
protected fun finishNotify(
|
protected fun finishNotify(
|
||||||
id: Int,
|
id: Int,
|
||||||
editBody: (NotificationCompat.Builder) -> NotificationCompat.Builder? = { null }
|
editBody: (Notification.Builder) -> Notification.Builder? = { null }
|
||||||
) : Int {
|
) : Int {
|
||||||
val currentNotification = remove(id)?.run(editBody)
|
val currentNotification = remove(id)?.run(editBody)
|
||||||
|
|
||||||
@ -62,11 +60,11 @@ abstract class NotificationService : BaseService(), KoinComponent {
|
|||||||
// ---
|
// ---
|
||||||
|
|
||||||
private fun notify(id: Int, notification: Notification) {
|
private fun notify(id: Int, notification: Notification) {
|
||||||
manager.notify(id, notification)
|
Notifications.mgr.notify(id, notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cancel(id: Int) {
|
private fun cancel(id: Int) {
|
||||||
manager.cancel(id)
|
Notifications.mgr.cancel(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun remove(id: Int) = notifications.remove(id).also {
|
protected fun remove(id: Int) = notifications.remove(id).also {
|
||||||
@ -84,4 +82,4 @@ abstract class NotificationService : BaseService(), KoinComponent {
|
|||||||
// --
|
// --
|
||||||
|
|
||||||
override fun onBind(p0: Intent?): IBinder? = null
|
override fun onBind(p0: Intent?): IBinder? = null
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package com.topjohnwu.magisk.model.download
|
package com.topjohnwu.magisk.model.download
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.app.Notification
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.core.app.NotificationCompat
|
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.data.network.GithubRawServices
|
import com.topjohnwu.magisk.data.network.GithubRawServices
|
||||||
import com.topjohnwu.magisk.di.NullActivity
|
import com.topjohnwu.magisk.di.NullActivity
|
||||||
@ -24,7 +24,7 @@ abstract class RemoteFileService : NotificationService() {
|
|||||||
|
|
||||||
val service: GithubRawServices by inject()
|
val service: GithubRawServices by inject()
|
||||||
|
|
||||||
override val defaultNotification: NotificationCompat.Builder
|
override val defaultNotification
|
||||||
get() = Notifications.progress(this, "")
|
get() = Notifications.progress(this, "")
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
@ -108,8 +108,8 @@ abstract class RemoteFileService : NotificationService() {
|
|||||||
@Throws(Throwable::class)
|
@Throws(Throwable::class)
|
||||||
protected abstract fun onFinished(subject: DownloadSubject, id: Int)
|
protected abstract fun onFinished(subject: DownloadSubject, id: Int)
|
||||||
|
|
||||||
protected abstract fun NotificationCompat.Builder.addActions(subject: DownloadSubject)
|
protected abstract fun Notification.Builder.addActions(subject: DownloadSubject)
|
||||||
: NotificationCompat.Builder
|
: Notification.Builder
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val ARG_URL = "arg_url"
|
const val ARG_URL = "arg_url"
|
||||||
|
@ -1,35 +1,51 @@
|
|||||||
package com.topjohnwu.magisk.view
|
package com.topjohnwu.magisk.view
|
||||||
|
|
||||||
|
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.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build.VERSION.SDK_INT
|
||||||
import androidx.core.app.NotificationCompat
|
|
||||||
import androidx.core.app.NotificationManagerCompat
|
|
||||||
import androidx.core.app.TaskStackBuilder
|
import androidx.core.app.TaskStackBuilder
|
||||||
|
import androidx.core.content.getSystemService
|
||||||
|
import androidx.core.graphics.drawable.toIcon
|
||||||
import com.topjohnwu.magisk.*
|
import com.topjohnwu.magisk.*
|
||||||
|
import com.topjohnwu.magisk.Const.ID.PROGRESS_NOTIFICATION_CHANNEL
|
||||||
|
import com.topjohnwu.magisk.Const.ID.UPDATE_NOTIFICATION_CHANNEL
|
||||||
import com.topjohnwu.magisk.extensions.get
|
import com.topjohnwu.magisk.extensions.get
|
||||||
|
import com.topjohnwu.magisk.extensions.getBitmap
|
||||||
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
|
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
|
||||||
import com.topjohnwu.magisk.ui.SplashActivity
|
import com.topjohnwu.magisk.ui.SplashActivity
|
||||||
|
|
||||||
object Notifications {
|
object Notifications {
|
||||||
|
|
||||||
val mgr by lazy { NotificationManagerCompat.from(get()) }
|
val mgr by lazy { get<Context>().getSystemService<NotificationManager>()!! }
|
||||||
private val icon by lazy { resolveRes(DynAPK.NOTIFICATION) }
|
|
||||||
|
|
||||||
fun setup(context: Context) {
|
fun setup(context: Context) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (SDK_INT >= 26) {
|
||||||
mgr.deleteNotificationChannel("magisk_notification")
|
var channel = NotificationChannel(UPDATE_NOTIFICATION_CHANNEL,
|
||||||
var channel = NotificationChannel(Const.ID.UPDATE_NOTIFICATION_CHANNEL,
|
|
||||||
context.getString(R.string.update_channel), NotificationManager.IMPORTANCE_DEFAULT)
|
context.getString(R.string.update_channel), NotificationManager.IMPORTANCE_DEFAULT)
|
||||||
mgr.createNotificationChannel(channel)
|
mgr.createNotificationChannel(channel)
|
||||||
channel = NotificationChannel(Const.ID.PROGRESS_NOTIFICATION_CHANNEL,
|
channel = NotificationChannel(PROGRESS_NOTIFICATION_CHANNEL,
|
||||||
context.getString(R.string.progress_channel), NotificationManager.IMPORTANCE_LOW)
|
context.getString(R.string.progress_channel), NotificationManager.IMPORTANCE_LOW)
|
||||||
mgr.createNotificationChannel(channel)
|
mgr.createNotificationChannel(channel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateBuilder(context: Context): Notification.Builder {
|
||||||
|
return Notification.Builder(context).apply {
|
||||||
|
val bitmap = context.getBitmap(R.drawable.ic_magisk_outline)
|
||||||
|
setLargeIcon(bitmap)
|
||||||
|
if (SDK_INT >= 26) {
|
||||||
|
setSmallIcon(bitmap.toIcon())
|
||||||
|
setChannelId(UPDATE_NOTIFICATION_CHANNEL)
|
||||||
|
} else {
|
||||||
|
setSmallIcon(R.drawable.ic_magisk_outline)
|
||||||
|
setVibrate(longArrayOf(0, 100, 100, 100))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun magiskUpdate(context: Context) {
|
fun magiskUpdate(context: Context) {
|
||||||
val intent = context.intent(SplashActivity::class.java)
|
val intent = context.intent(SplashActivity::class.java)
|
||||||
.putExtra(Const.Key.OPEN_SECTION, "magisk")
|
.putExtra(Const.Key.OPEN_SECTION, "magisk")
|
||||||
@ -39,13 +55,11 @@ object Notifications {
|
|||||||
val pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID,
|
val pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT)
|
PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
|
||||||
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
|
val builder = updateBuilder(context)
|
||||||
builder.setSmallIcon(icon)
|
.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)
|
||||||
.setVibrate(longArrayOf(0, 100, 100, 100))
|
.setContentIntent(pendingIntent)
|
||||||
.setAutoCancel(true)
|
|
||||||
.setContentIntent(pendingIntent)
|
|
||||||
|
|
||||||
mgr.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build())
|
mgr.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build())
|
||||||
}
|
}
|
||||||
@ -58,13 +72,11 @@ object Notifications {
|
|||||||
val pendingIntent = PendingIntent.getBroadcast(context,
|
val pendingIntent = PendingIntent.getBroadcast(context,
|
||||||
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
|
||||||
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
|
val builder = updateBuilder(context)
|
||||||
builder.setSmallIcon(icon)
|
.setContentTitle(context.getString(R.string.manager_update_title))
|
||||||
.setContentTitle(context.getString(R.string.manager_update_title))
|
.setContentText(context.getString(R.string.manager_download_install))
|
||||||
.setContentText(context.getString(R.string.manager_download_install))
|
.setAutoCancel(true)
|
||||||
.setVibrate(longArrayOf(0, 100, 100, 100))
|
.setContentIntent(pendingIntent)
|
||||||
.setAutoCancel(true)
|
|
||||||
.setContentIntent(pendingIntent)
|
|
||||||
|
|
||||||
mgr.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build())
|
mgr.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build())
|
||||||
}
|
}
|
||||||
@ -75,23 +87,34 @@ object Notifications {
|
|||||||
val pendingIntent = PendingIntent.getBroadcast(context,
|
val pendingIntent = PendingIntent.getBroadcast(context,
|
||||||
Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
|
||||||
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
|
val builder = updateBuilder(context)
|
||||||
builder.setSmallIcon(icon)
|
.setContentTitle(context.getString(R.string.dtbo_patched_title))
|
||||||
.setContentTitle(context.getString(R.string.dtbo_patched_title))
|
.setContentText(context.getString(R.string.dtbo_patched_reboot))
|
||||||
.setContentText(context.getString(R.string.dtbo_patched_reboot))
|
|
||||||
.setVibrate(longArrayOf(0, 100, 100, 100))
|
if (SDK_INT >= 23) {
|
||||||
.addAction(R.drawable.ic_refresh, context.getString(R.string.reboot), pendingIntent)
|
val action = Notification.Action.Builder(
|
||||||
|
context.getBitmap(R.drawable.ic_refresh).toIcon(),
|
||||||
|
context.getString(R.string.reboot), pendingIntent).build()
|
||||||
|
builder.addAction(action)
|
||||||
|
} else {
|
||||||
|
builder.addAction(
|
||||||
|
R.drawable.ic_refresh,
|
||||||
|
context.getString(R.string.reboot), pendingIntent)
|
||||||
|
}
|
||||||
|
|
||||||
mgr.notify(Const.ID.DTBO_NOTIFICATION_ID, builder.build())
|
mgr.notify(Const.ID.DTBO_NOTIFICATION_ID, builder.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun progress(context: Context, title: CharSequence): NotificationCompat.Builder {
|
fun progress(context: Context, title: CharSequence): Notification.Builder {
|
||||||
val builder = NotificationCompat.Builder(context, Const.ID.PROGRESS_NOTIFICATION_CHANNEL)
|
val builder = if (SDK_INT >= 26) {
|
||||||
builder.setPriority(NotificationCompat.PRIORITY_LOW)
|
Notification.Builder(context, PROGRESS_NOTIFICATION_CHANNEL)
|
||||||
.setSmallIcon(android.R.drawable.stat_sys_download)
|
} else {
|
||||||
.setContentTitle(title)
|
Notification.Builder(context).setPriority(Notification.PRIORITY_LOW)
|
||||||
.setProgress(0, 0, true)
|
}
|
||||||
.setOngoing(true)
|
builder.setSmallIcon(android.R.drawable.stat_sys_download)
|
||||||
|
.setContentTitle(title)
|
||||||
|
.setProgress(0, 0, true)
|
||||||
|
.setOngoing(true)
|
||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,10 @@ import android.content.pm.ShortcutManager
|
|||||||
import android.graphics.drawable.Icon
|
import android.graphics.drawable.Icon
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.core.graphics.drawable.toAdaptiveIcon
|
||||||
|
import androidx.core.graphics.drawable.toIcon
|
||||||
import com.topjohnwu.magisk.*
|
import com.topjohnwu.magisk.*
|
||||||
|
import com.topjohnwu.magisk.extensions.getBitmap
|
||||||
import com.topjohnwu.magisk.ui.SplashActivity
|
import com.topjohnwu.magisk.ui.SplashActivity
|
||||||
import com.topjohnwu.magisk.utils.Utils
|
import com.topjohnwu.magisk.utils.Utils
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
@ -26,47 +29,71 @@ object Shortcuts {
|
|||||||
val shortCuts = mutableListOf<ShortcutInfo>()
|
val shortCuts = mutableListOf<ShortcutInfo>()
|
||||||
val root = Shell.rootAccess()
|
val root = Shell.rootAccess()
|
||||||
val intent = context.intent(SplashActivity::class.java)
|
val intent = context.intent(SplashActivity::class.java)
|
||||||
|
|
||||||
|
fun getIcon(id: Int): Icon {
|
||||||
|
return if (Build.VERSION.SDK_INT >= 26)
|
||||||
|
context.getBitmap(id).toAdaptiveIcon()
|
||||||
|
else
|
||||||
|
context.getBitmap(id).toIcon()
|
||||||
|
}
|
||||||
|
|
||||||
if (Utils.showSuperUser()) {
|
if (Utils.showSuperUser()) {
|
||||||
shortCuts.add(ShortcutInfo.Builder(context, "superuser")
|
shortCuts.add(
|
||||||
|
ShortcutInfo.Builder(context, "superuser")
|
||||||
.setShortLabel(context.getString(R.string.superuser))
|
.setShortLabel(context.getString(R.string.superuser))
|
||||||
.setIntent(Intent(intent)
|
.setIntent(
|
||||||
|
Intent(intent)
|
||||||
.putExtra(Const.Key.OPEN_SECTION, "superuser")
|
.putExtra(Const.Key.OPEN_SECTION, "superuser")
|
||||||
.setAction(Intent.ACTION_VIEW)
|
.setAction(Intent.ACTION_VIEW)
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||||
.setIcon(Icon.createWithResource(context, resolveRes(DynAPK.SUPERUSER)))
|
)
|
||||||
|
.setIcon(getIcon(R.drawable.sc_superuser))
|
||||||
.setRank(0)
|
.setRank(0)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (root && Info.env.magiskHide) {
|
if (root && Info.env.magiskHide) {
|
||||||
shortCuts.add(ShortcutInfo.Builder(context, "magiskhide")
|
shortCuts.add(
|
||||||
|
ShortcutInfo.Builder(context, "magiskhide")
|
||||||
.setShortLabel(context.getString(R.string.magiskhide))
|
.setShortLabel(context.getString(R.string.magiskhide))
|
||||||
.setIntent(Intent(intent)
|
.setIntent(
|
||||||
|
Intent(intent)
|
||||||
.putExtra(Const.Key.OPEN_SECTION, "magiskhide")
|
.putExtra(Const.Key.OPEN_SECTION, "magiskhide")
|
||||||
.setAction(Intent.ACTION_VIEW)
|
.setAction(Intent.ACTION_VIEW)
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||||
.setIcon(Icon.createWithResource(context, resolveRes(DynAPK.MAGISKHIDE)))
|
)
|
||||||
|
.setIcon(getIcon(R.drawable.sc_magiskhide))
|
||||||
.setRank(1)
|
.setRank(1)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (!Config.coreOnly && root && Info.env.magiskVersionCode >= 0) {
|
if (!Config.coreOnly && root && Info.env.magiskVersionCode >= 0) {
|
||||||
shortCuts.add(ShortcutInfo.Builder(context, "modules")
|
shortCuts.add(
|
||||||
|
ShortcutInfo.Builder(context, "modules")
|
||||||
.setShortLabel(context.getString(R.string.modules))
|
.setShortLabel(context.getString(R.string.modules))
|
||||||
.setIntent(Intent(intent)
|
.setIntent(
|
||||||
|
Intent(intent)
|
||||||
.putExtra(Const.Key.OPEN_SECTION, "modules")
|
.putExtra(Const.Key.OPEN_SECTION, "modules")
|
||||||
.setAction(Intent.ACTION_VIEW)
|
.setAction(Intent.ACTION_VIEW)
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||||
.setIcon(Icon.createWithResource(context, resolveRes(DynAPK.MODULES)))
|
)
|
||||||
|
.setIcon(getIcon(R.drawable.sc_extension))
|
||||||
.setRank(3)
|
.setRank(3)
|
||||||
.build())
|
.build()
|
||||||
shortCuts.add(ShortcutInfo.Builder(context, "downloads")
|
)
|
||||||
|
shortCuts.add(
|
||||||
|
ShortcutInfo.Builder(context, "downloads")
|
||||||
.setShortLabel(context.getString(R.string.downloads))
|
.setShortLabel(context.getString(R.string.downloads))
|
||||||
.setIntent(Intent(intent)
|
.setIntent(
|
||||||
|
Intent(intent)
|
||||||
.putExtra(Const.Key.OPEN_SECTION, "downloads")
|
.putExtra(Const.Key.OPEN_SECTION, "downloads")
|
||||||
.setAction(Intent.ACTION_VIEW)
|
.setAction(Intent.ACTION_VIEW)
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||||
.setIcon(Icon.createWithResource(context, resolveRes(DynAPK.DOWNLOAD)))
|
)
|
||||||
|
.setIcon(getIcon(R.drawable.sc_cloud_download))
|
||||||
.setRank(2)
|
.setRank(2)
|
||||||
.build())
|
.build()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return shortCuts
|
return shortCuts
|
||||||
}
|
}
|
||||||
|
@ -11,19 +11,11 @@ import static android.os.Build.VERSION.SDK_INT;
|
|||||||
|
|
||||||
public class DynAPK {
|
public class DynAPK {
|
||||||
|
|
||||||
private static final int STUB_VERSION = 2;
|
private static final int STUB_VERSION = 3;
|
||||||
|
|
||||||
// Indices of the object array
|
// Indices of the object array
|
||||||
private static final int STUB_VERSION_ENTRY = 0;
|
private static final int STUB_VERSION_ENTRY = 0;
|
||||||
private static final int COMPONENT_MAP = 1;
|
private static final int COMPONENT_MAP = 1;
|
||||||
private static final int RESOURCE_MAP = 2;
|
|
||||||
|
|
||||||
// Indices of the resource map
|
|
||||||
public static final int NOTIFICATION = 0;
|
|
||||||
public static final int DOWNLOAD = 1;
|
|
||||||
public static final int SUPERUSER = 2;
|
|
||||||
public static final int MODULES = 3;
|
|
||||||
public static final int MAGISKHIDE = 4;
|
|
||||||
|
|
||||||
private static File dynDir;
|
private static File dynDir;
|
||||||
private static Method addAssetPath;
|
private static Method addAssetPath;
|
||||||
@ -53,15 +45,13 @@ public class DynAPK {
|
|||||||
Data data = new Data();
|
Data data = new Data();
|
||||||
data.version = (int) arr[STUB_VERSION_ENTRY];
|
data.version = (int) arr[STUB_VERSION_ENTRY];
|
||||||
data.componentMap = (Map<String, String>) arr[COMPONENT_MAP];
|
data.componentMap = (Map<String, String>) arr[COMPONENT_MAP];
|
||||||
data.resourceMap = (int[]) arr[RESOURCE_MAP];
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object pack(Data data) {
|
public static Object pack(Data data) {
|
||||||
Object[] arr = new Object[3];
|
Object[] arr = new Object[2];
|
||||||
arr[STUB_VERSION_ENTRY] = STUB_VERSION;
|
arr[STUB_VERSION_ENTRY] = STUB_VERSION;
|
||||||
arr[COMPONENT_MAP] = data.componentMap;
|
arr[COMPONENT_MAP] = data.componentMap;
|
||||||
arr[RESOURCE_MAP] = data.resourceMap;
|
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +66,5 @@ public class DynAPK {
|
|||||||
public static class Data {
|
public static class Data {
|
||||||
public int version;
|
public int version;
|
||||||
public Map<String, String> componentMap;
|
public Map<String, String> componentMap;
|
||||||
public int[] resourceMap;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,7 @@ package com.topjohnwu.magisk.obfuscate;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static com.topjohnwu.magisk.DynAPK.*;
|
import static com.topjohnwu.magisk.DynAPK.Data;
|
||||||
import static com.topjohnwu.magisk.R.drawable.*;
|
|
||||||
|
|
||||||
public class Mapping {
|
public class Mapping {
|
||||||
private static Map<String, String> map = new HashMap<>();
|
private static Map<String, String> map = new HashMap<>();
|
||||||
@ -25,13 +24,6 @@ public class Mapping {
|
|||||||
for (Map.Entry<String, String> e : map.entrySet()) {
|
for (Map.Entry<String, String> e : map.entrySet()) {
|
||||||
data.componentMap.put(e.getValue(), e.getKey());
|
data.componentMap.put(e.getValue(), e.getKey());
|
||||||
}
|
}
|
||||||
int[] res = new int[5];
|
|
||||||
res[NOTIFICATION] = ic_magisk_outline;
|
|
||||||
res[SUPERUSER] = sc_superuser;
|
|
||||||
res[MAGISKHIDE] = sc_magiskhide;
|
|
||||||
res[DOWNLOAD] = sc_cloud_download;
|
|
||||||
res[MODULES] = sc_extension;
|
|
||||||
data.resourceMap = res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String get(String name) {
|
public static String get(String name) {
|
||||||
|
Loading…
Reference in New Issue
Block a user