diff options
Diffstat (limited to 'app/src/main/java/moe/yuuta/workmode/access/AccessLayer.kt')
-rw-r--r-- | app/src/main/java/moe/yuuta/workmode/access/AccessLayer.kt | 63 |
1 files changed, 34 insertions, 29 deletions
diff --git a/app/src/main/java/moe/yuuta/workmode/access/AccessLayer.kt b/app/src/main/java/moe/yuuta/workmode/access/AccessLayer.kt index 31e4622..d9eb12d 100644 --- a/app/src/main/java/moe/yuuta/workmode/access/AccessLayer.kt +++ b/app/src/main/java/moe/yuuta/workmode/access/AccessLayer.kt @@ -2,11 +2,13 @@ package moe.yuuta.workmode.access import android.annotation.SuppressLint import android.content.Context +import android.content.pm.ApplicationInfo +import android.content.pm.IPackageManager import android.content.pm.LauncherApps import android.content.pm.PackageManager import android.os.Bundle +import android.os.Parcel import android.os.PersistableBundle -import android.os.Process import android.os.UserHandle import android.system.Os import androidx.content.pm.PackageOZ @@ -23,16 +25,14 @@ import java.util.concurrent.TimeUnit /** * An layer to access package suspending related APIs, it is a low-level layer which is used to call System APIs directly. - * - * TODO: Multi-user support */ -internal class AccessLayer(private val mContext: Context) { +internal class AccessLayer(internal val mContext: Context) { private val mPM: PackageManager = mContext.packageManager @SuppressLint("PrivateApi") fun setPackagesSuspended(packageNames: Array<String>, suspended: Boolean, appExtras: PersistableBundle, launcherExtras: PersistableBundle, - dialogMessage: String): Array<String> { + dialogMessage: String, userId: Int): Array<String> { val countDownLatch = CountDownLatch(1) Thread { // Check installation source and write the result @@ -71,42 +71,31 @@ internal class AccessLayer(private val mContext: Context) { countDownLatch.await(2, TimeUnit.SECONDS) - // ApplicationPackageManager ALWAYS uses context.getOpPackageName() as the argument "callingPackage" + // ApplicationPackageManager ALWAYS uses hostContext.getOpPackageName() as the argument "callingPackage" // My callingPackage MUSTN'T equals to 'android' // If we are using packageName of 'android', system will show disabled // by admin dialog instead of suspended dialog // F**k Google - val func: Method = Class.forName("android.content.pm.IPackageManager") - .getDeclaredMethod("setPackagesSuspendedAsUser", - Array<String>::class.java, - Boolean::class.java, - PersistableBundle::class.java, - PersistableBundle::class.java, - String::class.java, - String::class.java, - Int::class.java) - // It's an unstable design val iPM: Field = mPM::class.java.getDeclaredField("mPM") iPM.isAccessible = true - - return func.invoke(iPM.get(mPM), - packageNames, + val pm = iPM.get(mPM) as IPackageManager + return pm.setPackagesSuspendedAsUser(packageNames, suspended, appExtras, launcherExtras, dialogMessage, BuildConfig.APPLICATION_ID, - UserHandle.getUserHandleForUid(mPM.getPackageUid(mContext.packageName, 0)).hashCode()) as Array<String> + userId) as Array<String> } /** * This method will SET your UID and you WON'T BE ABLE TO GO BACK. * Create a new process and access it. */ - fun getSuspendedPackageAppExtras(packageName: String): PersistableBundle? { + fun getSuspendedPackageAppExtras(packageName: String, userId: Int): PersistableBundle? { Os.setuid(mPM.getPackageUid(packageName, 0)) - // ApplicationPackageManager ALWAYS uses context.getOpPackageName() as the package name + // ApplicationPackageManager ALWAYS uses hostContext.getOpPackageName() as the package name // F**k Google val func: Method = Class.forName("android.content.pm.IPackageManager") .getDeclaredMethod("getSuspendedPackageAppExtras", @@ -119,16 +108,32 @@ internal class AccessLayer(private val mContext: Context) { return func.invoke(iPM.get(mPM), packageName, - UserHandle.getUserHandleForUid(mPM.getPackageUid(packageName, 0)).hashCode()) as PersistableBundle? + userId) as PersistableBundle? } @Throws(PackageManager.NameNotFoundException::class) - fun isPackageSuspended(packageName: String): Boolean { - val func: Method = PackageManager::class.java.getDeclaredMethod("isPackageSuspended", - String::class.java) - return func.invoke(mPM, packageName) as Boolean + fun isPackageSuspended(packageName: String, userId: Int): Boolean { + val func: Method = PackageManager::class.java.getDeclaredMethod("isPackageSuspendedForUser", + String::class.java, + Int::class.java) + return func.invoke(mPM, packageName, userId) as Boolean } - fun getSuspendedPackageLauncherExtras(packageName: String): Bundle? = - mContext.getSystemService(LauncherApps::class.java).getSuspendedPackageLauncherExtras(packageName, Process.myUserHandle()) + fun getSuspendedPackageLauncherExtras(packageName: String, userId: Int): Bundle? = + mContext.getSystemService(LauncherApps::class.java).getSuspendedPackageLauncherExtras(packageName, + createUserHandleWithUserID(userId)) + + fun getInstalledApplicationsAsUser(flags: Int, userId: Int): List<ApplicationInfo> = + mPM.getInstalledApplicationsAsUser(flags, userId) + + companion object { + fun createUserHandleWithUserID(userId: Int): UserHandle { + val parcel = Parcel.obtain() + parcel.writeInt(userId) + // I bet that it won't change a lot + val userHandle = UserHandle(parcel) + parcel.recycle() + return userHandle + } + } }
\ No newline at end of file |