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:
topjohnwu 2019-10-30 01:02:53 -04:00
parent 5e87483f34
commit fdf04f77f2
18 changed files with 152 additions and 110 deletions

View File

@ -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!! }

View File

@ -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() {

View File

@ -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) }

View File

@ -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
} }

View File

@ -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"

View File

@ -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
} }
} }

View File

@ -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
} }

View File

@ -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;
} }
} }

View File

@ -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) {