package com.topjohnwu.magisk.extensions import android.content.Context import android.content.Intent import android.content.pm.ApplicationInfo import android.content.pm.ComponentInfo import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.content.pm.PackageManager.* import android.content.res.Configuration import android.content.res.Resources import android.database.Cursor import android.net.Uri import android.os.Build import android.provider.OpenableColumns import android.view.View import androidx.annotation.ColorRes import androidx.annotation.DrawableRes import androidx.core.content.ContextCompat import com.topjohnwu.magisk.utils.FileProvider import com.topjohnwu.magisk.utils.currentLocale import java.io.File import java.io.FileNotFoundException val packageName: String get() = get().packageName val PackageInfo.processes get() = activities?.processNames.orEmpty() + services?.processNames.orEmpty() + receivers?.processNames.orEmpty() + providers?.processNames.orEmpty() val Array.processNames get() = mapNotNull { it.processName } val ApplicationInfo.packageInfo: PackageInfo? get() { val pm: PackageManager by inject() return try { val request = GET_ACTIVITIES or GET_SERVICES or GET_RECEIVERS or GET_PROVIDERS pm.getPackageInfo(packageName, request) } catch (e1: Exception) { try { pm.activities(packageName).apply { services = pm.services(packageName) receivers = pm.receivers(packageName) providers = pm.providers(packageName) } } catch (e2: Exception) { null } } } val Uri.fileName: String get() { var name: String? = null get().contentResolver.query(this, null, null, null, null)?.use { c -> val nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME) if (nameIndex != -1) { c.moveToFirst() name = c.getString(nameIndex) } } if (name == null && path != null) { val idx = path!!.lastIndexOf('/') name = path!!.substring(idx + 1) } return name.orEmpty() } fun PackageManager.activities(packageName: String) = getPackageInfo(packageName, GET_ACTIVITIES) fun PackageManager.services(packageName: String) = getPackageInfo(packageName, GET_SERVICES).services fun PackageManager.receivers(packageName: String) = getPackageInfo(packageName, GET_RECEIVERS).receivers fun PackageManager.providers(packageName: String) = getPackageInfo(packageName, GET_PROVIDERS).providers fun Context.rawResource(id: Int) = resources.openRawResource(id) fun Context.readUri(uri: Uri) = contentResolver.openInputStream(uri) ?: throw FileNotFoundException() fun Intent.startActivity(context: Context) = context.startActivity(this) fun File.provide(context: Context = get()): Uri { return FileProvider.getUriForFile(context, context.packageName + ".provider", this) } fun File.mv(destination: File) { inputStream().writeTo(destination) deleteRecursively() } fun String.toFile() = File(this) fun Intent.chooser(title: String = "Pick an app") = Intent.createChooser(this, title) fun Context.cachedFile(name: String) = File(cacheDir, name) fun Cursor.toList(transformer: (Cursor) -> Result): List { val out = mutableListOf() while (moveToNext()) out.add(transformer(this)) return out } fun ApplicationInfo.getLabel(pm: PackageManager): String { runCatching { if (labelRes > 0) { val res = pm.getResourcesForApplication(this) val config = Configuration() config.setLocale(currentLocale) res.updateConfiguration(config, res.displayMetrics) return res.getString(labelRes) } } return loadLabel(pm).toString() } fun Intent.exists(packageManager: PackageManager) = resolveActivity(packageManager) != null fun Context.colorCompat(@ColorRes id: Int) = try { ContextCompat.getColor(this, id) } catch (e: Resources.NotFoundException) { null } fun Context.colorStateListCompat(@ColorRes id: Int) = try { ContextCompat.getColorStateList(this, id) } catch (e: Resources.NotFoundException) { null } fun Context.drawableCompat(@DrawableRes id: Int) = ContextCompat.getDrawable(this, id) /** * Pass [start] and [end] dimensions, function will return left and right * with respect to RTL layout direction */ fun Context.startEndToLeftRight(start: Int, end: Int): Pair { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL ) { return end to start } return start to end }