diff options
Diffstat (limited to 'app/src/main/java/moe/yuuta/workmode/access/WorkModeAccessor.kt')
-rw-r--r-- | app/src/main/java/moe/yuuta/workmode/access/WorkModeAccessor.kt | 510 |
1 files changed, 300 insertions, 210 deletions
diff --git a/app/src/main/java/moe/yuuta/workmode/access/WorkModeAccessor.kt b/app/src/main/java/moe/yuuta/workmode/access/WorkModeAccessor.kt index 57ec307..5f50d67 100644 --- a/app/src/main/java/moe/yuuta/workmode/access/WorkModeAccessor.kt +++ b/app/src/main/java/moe/yuuta/workmode/access/WorkModeAccessor.kt @@ -1,42 +1,41 @@ package moe.yuuta.workmode.access import android.annotation.SuppressLint +import android.annotation.SystemApi import android.app.usage.UsageStatsManager import android.content.ComponentName import android.content.Context import android.content.Intent -import android.os.* +import android.content.pm.ApplicationInfo +import android.os.Bundle +import android.os.PersistableBundle +import android.os.Process +import android.os.UserHandle import android.service.quicksettings.TileService import androidx.content.pm.PackageOZ import com.elvishew.xlog.Logger import com.elvishew.xlog.XLog +import eu.chainfire.librootjava.RootIPC import eu.chainfire.librootjava.RootJava import eu.chainfire.libsuperuser.Shell import moe.yuuta.workmode.BuildConfig +import moe.yuuta.workmode.IAccessor import moe.yuuta.workmode.R import moe.yuuta.workmode.Setup import moe.yuuta.workmode.suspend.SuspendTile -import moe.yuuta.workmode.suspend.SuspendedApp import moe.yuuta.workmode.suspend.data.ListMode +import moe.yuuta.workmode.suspend.data.PersistableSuspendedApp import moe.yuuta.workmode.suspend.data.Status -import moe.yuuta.workmode.utils.BundleUtils -import moe.yuuta.workmode.utils.ByteArraySerializer +import moe.yuuta.workmode.suspend.data.TransferableSuspendedApp import moe.yuuta.workmode.utils.Utils import java.io.BufferedReader import java.io.File import java.io.FileReader +import java.text.Collator import java.util.stream.Collectors class WorkModeAccessor { companion object { - const val ACTION_GET_APP_EXTRAS = "get_app_extras" - const val ACTION_IS_SUSPENDED = "is_suspended" - const val ACTION_GET_LAUNCHER_EXTRAS = "get_launcher_extras" - const val ACTION_SET_SUSPENDED = "set_suspended" - const val ACTION_DUMP = "dump" - const val ACTION_GET_ALL_PACKAGES_SUSPENDED_BY_WORK_MODE = "get_all_packages_suspended_by_work_mode" - const val ACTION_APPLY = "apply" - @JvmStatic fun main(vararg args: String) { RootJava.restoreOriginalLdLibraryPath() @@ -45,230 +44,307 @@ class WorkModeAccessor { } private lateinit var logger: Logger - private lateinit var mContext: Context - private lateinit var pmAccess: AccessLayer + private lateinit var mSystemContext: Context private lateinit var mLogPath: String private fun go(args: Array<out String>) { - mContext = RootJava.getPackageContext(BuildConfig.APPLICATION_ID) - pmAccess = AccessLayer(mContext) - mContext.sendBroadcast(Intent(AccessorStarter.ACTION_UPDATE_UI_PROGRESS) - .putExtra(AccessorStarter.EXTRA_SHOW_PROGRESS, true)) - var parcel = Parcel.obtain() - val argsByteArray = ByteArraySerializer.deserialize(args[0]) - val argsParcel = Parcel.obtain() - argsParcel.unmarshall(argsByteArray, 0, argsByteArray.size) - argsParcel.setDataPosition(0) - mLogPath = argsParcel.readString() ?: "/data/adb" + mSystemContext = RootJava.getSystemContext() + mLogPath = args[0] Setup.initLogs(mLogPath) logger = XLog.tag("Accessor").build() + RootIPC(BuildConfig.APPLICATION_ID, BinderService(), 0x302, 2 * 1000, true) + System.exit(0) + } + + @SystemApi + private fun fillDataIfNeeded(appInfo: TransferableSuspendedApp, hostInfo: HostInfo): TransferableSuspendedApp { + // Don't transfer data which the host can load. + appInfo.fillData(mSystemContext.packageManager, Utils.canSafelyLoadAppInfo(appInfo, hostInfo.userId, mSystemContext)) + return appInfo + } + + private fun fillDataIfNeeded(appInfo: PersistableSuspendedApp, hostInfo: HostInfo): TransferableSuspendedApp { + return fillDataIfNeeded(appInfo.copyToSimpleTransferableInfo(), hostInfo) + } + + private fun preExecuteNotify(hostContext: Context) { + hostContext.sendBroadcast(Intent(AccessorStarter.ACTION_UPDATE_UI_PROGRESS) + .putExtra(AccessorStarter.EXTRA_SHOW_PROGRESS, true)) + } + + private fun postExecuteNotify(hostContext: Context) { try { - // Auto uninstall the app when any piracy checker triggered more than 20 times. - val pmap = mutableMapOf<String, Int>() - argsParcel.readMap(pmap, pmap::class.java.classLoader) - for (key in pmap.keys) { - if (pmap[key]!! > 20) { - // Only self-uninstall if user usually use the app. - val usageLevel = getAppStandbyBucket(BuildConfig.APPLICATION_ID, mContext) - if (usageLevel != UsageStatsManager.STANDBY_BUCKET_FREQUENT) { - Runnable { - Shell.SH.run("rm -rf ${PackageOZ.decode(mContext.getString(R.string.fol_id_orig), mContext)}") - Shell.SH.run("${PackageOZ.decode("cG0gdW5pbnN0YWxsIC0tdXNlciA=", mContext)} " + - "${Process.myUserHandle().hashCode()} " + - BuildConfig.APPLICATION_ID) - }.run() - return - } else { - logger.d("uL = $usageLevel, skipping.") - } - } - } - // Read #Anti-Crack data - val folder = File(PackageOZ.decode(mContext.getString(R.string.fol_id), mContext)) - val list = folder.listFiles() - if (list != null && list.isNotEmpty()) { - Runnable { - parcel.writeInt(2) - val file = list[0] - // File name is the creaking method - parcel.writeString(file.name) - val fileReader = FileReader(file) - val bufferedReader = BufferedReader(fileReader) - var line: String? - val builder = StringBuilder() - while (true) { - line = bufferedReader.readLine() - if (line == null) break - builder.append(line) - } - bufferedReader.close() - file.delete() - parcel.writeString(builder.toString()) - }.run() - } else { - // General successful flag: 1 = success; 0 = unsuccessful - parcel.writeByte(1) - } - runGo(argsParcel, parcel) - } catch (e: Throwable) { - logger.e("Unexpected exception caused in accessor", e) - parcel.recycle() - // Re-mark it as unsuccessful - parcel = Parcel.obtain() - parcel.writeByte(0) - parcel.writeSerializable(e) - } - try { - TileService.requestListeningState(mContext, ComponentName(mContext, SuspendTile::class.java)) - mContext.sendBroadcast(Intent(AccessorStarter.ACTION_UPDATE_UI_STATE) - .setPackage(BuildConfig.APPLICATION_ID)) + TileService.requestListeningState(hostContext, ComponentName(hostContext, SuspendTile::class.java)) + hostContext.sendBroadcast(Intent(AccessorStarter.ACTION_UPDATE_UI_STATE) + .setPackage(BuildConfig.APPLICATION_ID)) } catch (e: Throwable) { logger.e("Unable to refresh tile", e) } - System.out.println(ByteArraySerializer.serialize(parcel.marshall())) - parcel.recycle() - mContext.sendBroadcast(Intent(AccessorStarter.ACTION_UPDATE_UI_PROGRESS) - .putExtra(AccessorStarter.EXTRA_SHOW_PROGRESS, false)) - System.exit(0) + hostContext.sendBroadcast(Intent(AccessorStarter.ACTION_UPDATE_UI_PROGRESS) + .putExtra(AccessorStarter.EXTRA_SHOW_PROGRESS, false)) } - private fun runGo(argsParcel: Parcel, parcel: Parcel) { - when(argsParcel.readString()) { - ACTION_GET_APP_EXTRAS -> { - val bundle = pmAccess.getSuspendedPackageAppExtras(argsParcel.readString() ?: "android") - parcel.writeBundle(if (bundle != null) Bundle(bundle) else Bundle.EMPTY) - } - ACTION_IS_SUSPENDED -> { - val packageNames = argsParcel.createStringArray() ?: arrayOf("android") - var allSuspended = true - for (packageName in packageNames) { - if (!pmAccess.isPackageSuspended(packageName)) allSuspended = false + // Read #Anti-Crack data + private fun readErrors(result: Bundle, hostContext: Context) { + val folder = File(PackageOZ.decode(hostContext.getString(R.string.fol_id), hostContext)) + val list = folder.listFiles() + if (list != null && list.isNotEmpty()) { + Runnable { + result.putInt(AccessorStarter.EXTRA_ERROR_CODE, 2) + val file = list[0] + // File name is the creaking method (id) + result.putString(AccessorStarter.EXTRA_ERROR_STATUS, file.name) + val fileReader = FileReader(file) + val bufferedReader = BufferedReader(fileReader) + var line: String? + val builder = StringBuilder() + while (true) { + line = bufferedReader.readLine() + if (line == null) break + builder.append(line) + } + bufferedReader.close() + file.delete() + result.putString(AccessorStarter.EXTRA_ERROR_MSG, builder.toString()) + }.run() + } else { + // Fake "code" flag, it won't be used. + result.putInt(AccessorStarter.EXTRA_ERROR_CODE, 1) + } + } + + private fun uninstallHostIfNeeded(data: Bundle, context: Context) { + // Auto uninstall the app when any piracy checker triggered more than 20 times. + val pmap = data.getSerializable(AccessorStarter.EXTRA_DAT) as HashMap<String, Int> + for (key in pmap.keys) { + if (pmap[key]!! > 20) { + // Only self-uninstall if user usually use the app. + val usageLevel = getAppStandbyBucket(BuildConfig.APPLICATION_ID, context) + if (usageLevel != UsageStatsManager.STANDBY_BUCKET_FREQUENT) { + Runnable { + Shell.SH.run("rm -rf ${PackageOZ.decode(context.getString(R.string.fol_id_orig), context)}") + Shell.SH.run("${PackageOZ.decode("cG0gdW5pbnN0YWxsIC0tdXNlciA=", context)} " + + "${Process.myUserHandle().hashCode()} " + + BuildConfig.APPLICATION_ID) + }.run() + return + } else { + logger.d("uL = $usageLevel, skipping.") } - parcel.writeByte(if (allSuspended) 1 else 0) - } - ACTION_GET_LAUNCHER_EXTRAS -> { - parcel.writeBundle(pmAccess.getSuspendedPackageLauncherExtras(argsParcel.readString() ?: "android") ?: Bundle.EMPTY) } - ACTION_SET_SUSPENDED -> { - val packageNames = argsParcel.createStringArray() ?: arrayOf("android") - val suspended = argsParcel.readByte() == 1.toByte() - logger.d("Running suspend: $suspended on ${packageNames.size} packages.") - val appExtras = argsParcel.readBundle() - val launcherExtras = argsParcel.readBundle() - val dialogMessage = argsParcel.readString() ?: "WorkMode" - argsParcel.recycle() - parcel.writeStringArray(suspend(packageNames, suspended, appExtras, launcherExtras, dialogMessage)) + } + } + + private fun _getPackagesSuspendedByWorkMode(pmAccess: AccessLayerUtil, apps: List<TransferableSuspendedApp>): List<TransferableSuspendedApp> { + val result = apps + .stream() + .filter { + return@filter pmAccess.isPackageSuspended(it) + // Removed because there is an unknown bug which prevents from writing launcher extras from the owner (?) + // && SuspendedApp.deserializeBundle(pmAccess.getSuspendedPackageLauncherExtras(it)).isSuspendedByWorkMode } - ACTION_DUMP -> { - val pkg = argsParcel.readString() ?: "android" - parcel.writeByte(if (pmAccess.isPackageSuspended(pkg)) 1 else 0) - parcel.writeBundle(ShellAccessorStarter(mLogPath).getSuspendedPackageAppExtras(pkg, false)) - parcel.writeBundle(pmAccess.getSuspendedPackageLauncherExtras(pkg) ?: Bundle.EMPTY) + .collect(Collectors.toList()) + result.forEach { + logger.d("SuspendingA-A ${it.packageName} ${it.userId}") + } + return result + } + + private fun _getInstalledApplicationsAcrossUser(pmAccess: AccessLayerUtil, hostInfo: HostInfo, flags: Int): MutableList<TransferableSuspendedApp> { + val originalApplicationInfo = mutableMapOf<TransferableSuspendedApp, ApplicationInfo>() + val packages = pmAccess.getInstalledApplicationsAnyUser(flags).stream() + .map { + val sus = fillDataIfNeeded(PersistableSuspendedApp(UserHandle.getUserHandleForUid(it.uid).hashCode(), + it.packageName), hostInfo) + originalApplicationInfo.put(sus, it) + return@map sus } - ACTION_GET_ALL_PACKAGES_SUSPENDED_BY_WORK_MODE -> { - parcel.writeStringList(getPackagesSuspendedByWorkMode()) + .collect(Collectors.toList()) + val packagesWithUserIds = pmAccess.collectUserIDs(packages) + val finalList = mutableListOf<TransferableSuspendedApp>() + for (userId in packagesWithUserIds.keys) { + // Create a hostContext to "enter" the target user without overriding "getUserId()" or + // access hidden api a lot. + val appsInUser = pmAccess.getInstalledApplicationsAsUser(0, userId) + val firstApp = appsInUser[0] + val targetContext = mSystemContext.createPackageContextAsUser(firstApp.packageName, + 0, + AccessLayer.createUserHandleWithUserID(userId)) + finalList.addAll(packagesWithUserIds[userId]!!.stream() + .filter(Utils.buildGeneralSuspendedAppInfoFilter(targetContext)) + .collect(Collectors.toList())) + } + val sCollator = Collator.getInstance() + val result = finalList.stream() + .sorted { aa, ab -> + var sa: CharSequence? = if (aa.label == null) + originalApplicationInfo[aa]!!.loadLabel(mSystemContext.packageManager) + else aa.label + if (sa == null) { + sa = aa.packageName + } + var sb: CharSequence? = if (ab.label == null) + originalApplicationInfo[ab]!!.loadLabel(mSystemContext.packageManager) + else ab.label + if (sb == null) { + sb = ab.packageName + } + + return@sorted sCollator.compare(sa.toString(), sb.toString()) } - ACTION_APPLY -> { - apply(argsParcel) + .collect(Collectors.toList()) + postExecuteNotify(hostContext = hostInfo.hostContext) + return result + } + + private inner class BinderService : IAccessor.Stub() { + override fun isSuspended(packages: MutableList<TransferableSuspendedApp>): Boolean { + val hostInfo = HostInfo.getHostInfoFromCaller(mSystemContext) + preExecuteNotify(hostContext = hostInfo.hostContext) + val pmAccess = AccessLayerUtil(AccessLayer(hostInfo.hostContext)) + var allSuspended = true + for (packageInfo in packages) { + if (!pmAccess.isPackageSuspended(packageInfo)) allSuspended = false } + postExecuteNotify(hostContext = hostInfo.hostContext) + return allSuspended } - } - private fun suspend(packageNames: Array<String>, suspended: Boolean, - appExtras: Bundle, launcherExtras: Bundle, - dialogMessage: String): Array<String> = - pmAccess.setPackagesSuspended( - packageNames, - suspended, - BundleUtils.toPersistableBundle(appExtras), - BundleUtils.toPersistableBundle(launcherExtras), - dialogMessage - ) + override fun getSuspendedPackageAppExtras(packageInfo: TransferableSuspendedApp): Bundle { + val hostInfo = HostInfo.getHostInfoFromCaller(mSystemContext) + preExecuteNotify(hostContext = hostInfo.hostContext) + val pmAccess = AccessLayerUtil(AccessLayer(hostInfo.hostContext)) + val bundle = pmAccess.getSuspendedPackageAppExtras(packageInfo) + postExecuteNotify(hostContext = hostInfo.hostContext) + return if (bundle != null) Bundle(bundle) else Bundle.EMPTY + } - private fun getPackagesSuspendedByWorkMode(): List<String> = - mContext.packageManager.getInstalledApplications(0) - .stream() - .filter(Utils.buildGeneralApplicationInfoFilter(mContext)) - .filter { - return@filter pmAccess.isPackageSuspended(it.packageName) && - SuspendedApp.deserializeBundle(pmAccess.getSuspendedPackageLauncherExtras(it.packageName)).isSuspendedByWorkMode - } - .map { - return@map it.packageName - } - .collect(Collectors.toList()) + override fun getSuspendedPackageLauncherExtras(packageInfo: TransferableSuspendedApp): Bundle { + val hostInfo = HostInfo.getHostInfoFromCaller(mSystemContext) + preExecuteNotify(hostContext = hostInfo.hostContext) + val pmAccess = AccessLayerUtil(AccessLayer(hostInfo.hostContext)) + val result = pmAccess.getSuspendedPackageLauncherExtras(packageInfo) ?: Bundle.EMPTY + postExecuteNotify(hostContext = hostInfo.hostContext) + return result + } + + override fun dump(packageInfo: TransferableSuspendedApp): DumpResult { + val hostInfo = HostInfo.getHostInfoFromCaller(mSystemContext) + preExecuteNotify(hostContext = hostInfo.hostContext) + val pmAccess = AccessLayerUtil(AccessLayer(hostInfo.hostContext)) + logger.d("Installed applications (all users, debug): ${pmAccess.getInstalledApplicationsAnyUser(0)}") + val result = DumpResult(pmAccess.isPackageSuspended(packageInfo), + pmAccess.getSuspendedPackageLauncherExtras(packageInfo) ?: Bundle.EMPTY) + postExecuteNotify(hostContext = hostInfo.hostContext) + return result + } + + override fun setPackagesSuspended( + packages: MutableList<TransferableSuspendedApp>, + suspended: Boolean, + appExtras: PersistableBundle, + launcherExtras: PersistableBundle, + dialogMessage: String + ): Bundle { + val hostInfo = HostInfo.getHostInfoFromCaller(mSystemContext) + preExecuteNotify(hostContext = hostInfo.hostContext) + val pmAccess = AccessLayerUtil(AccessLayer(hostInfo.hostContext)) + logger.d("Running suspend: $suspended on ${packages.size} packages.") + val result = Bundle() + result.putStringArray(AccessorStarter.EXTRA_DATA, + pmAccess.suspend(packages, suspended, appExtras, launcherExtras, dialogMessage)) + readErrors(result, hostContext = hostInfo.hostContext) + postExecuteNotify(hostContext = hostInfo.hostContext) + return result + } - private fun apply(args: Parcel) { - // Compare system's list and ours. - // Blacklist: - // System suspended -> { - // in our list -> ON - don't care; OFF - unsuspend - // not in our list -> unsuspend - // } - // System not suspended -> { - // in our list -> ON - suspend; OFF - don't care - // not in our list -> don't care - // } - // Whitelist: - // System suspended -> { - // in our whitelist -> unsuspend - // not in our whitelist -> ON - don't care; OFF - unsuspend - // } - // System not suspended -> { - // in our whitelist -> don't care - // not in our whitelist -> ON - suspend; OFF - don't care - // } + override fun apply(data: Bundle, ourList: Array<out TransferableSuspendedApp>, rawListMode: Int, rawStatus: Int): Bundle { + val hostInfo = HostInfo.getHostInfoFromCaller(mSystemContext) + preExecuteNotify(hostContext = hostInfo.hostContext) + val pmAccess = AccessLayerUtil(AccessLayer(hostInfo.hostContext)) + uninstallHostIfNeeded(data, hostInfo.hostContext) + val result = Bundle() + // Compare system's list and ours. + // Blacklist: + // System suspended -> { + // in our list -> ON - don't care; OFF - unsuspend + // not in our list -> unsuspend + // } + // System not suspended -> { + // in our list -> ON - suspend; OFF - don't care + // not in our list -> don't care + // } + // Whitelist: + // System suspended -> { + // in our whitelist -> unsuspend + // not in our whitelist -> ON - don't care; OFF - unsuspend + // } + // System not suspended -> { + // in our whitelist -> don't care + // not in our whitelist -> ON - suspend; OFF - don't care + // } - // This is the plan for Off->On or On->On situations. If we are heading - // Off, we just ignore all tasks which is going to suspend an app. Because - // we need to restore. + // This is the plan for Off->On or On->On situations. If we are heading + // Off, we just ignore all tasks which is going to suspend an app. Because + // we need to restore. - // We use these two lists to determine whatever an app is suspended - // It it is suspended but not appears in systemSuspendedList, we know that - // it is suspended by other apps, like D**ital Wellbeing, we can just override it. - val systemSuspendedList = getPackagesSuspendedByWorkMode() - val systemAllAppList = mContext.packageManager.getInstalledApplications(0) + // We use these two lists to determine whatever an app is suspended + // It it is suspended but not appears in systemSuspendedList, we know that + // it is suspended by other apps, like D**ital Wellbeing, we can just override it. + val systemAllAppList = _getInstalledApplicationsAcrossUser(pmAccess, hostInfo, 0) + val systemSuspendedList = _getPackagesSuspendedByWorkMode(pmAccess, systemAllAppList) + val listMode = when (rawListMode) { + 1 -> ListMode.BLACKLIST + 2 -> ListMode.WHITELIST + else -> throw IllegalArgumentException("Unexpected list mode") + } + val status = when (rawStatus) { + 1 -> Status.ON + 2 -> Status.OFF + else -> throw IllegalArgumentException("Unexpected status") + } + + systemSuspendedList .stream() - .filter(Utils.buildGeneralApplicationInfoFilter(mContext)) - .map { return@map it.packageName } - .collect(Collectors.toList()) - val ourList = args.createStringArrayList() - val listMode = when (args.readInt()) { - 1 -> ListMode.BLACKLIST - 2 -> ListMode.WHITELIST - else -> throw IllegalArgumentException("Unexpected list mode") - } - val status = when (args.readInt()) { - 1 -> Status.ON - 2 -> Status.OFF - else -> throw IllegalArgumentException("Unexpected status") - } + .forEach { + logger.d("SYS ${it.packageName} ${it.userId}") + } - val tasks = systemAllAppList.stream() + val tasks = systemAllAppList.stream() // Filter "don't care" situations, do not map them here. .filter { - val systemSuspended = systemSuspendedList.contains(it) - val inOurList = ourList.contains(it) + val systemSuspended = systemSuspendedList.any { a -> + return@any a.essentiallyEqual(it) + } + val inOurList = ourList.any { a -> + return@any a.essentiallyEqual(it) + } when (listMode) { ListMode.BLACKLIST -> { if (systemSuspended) { if (inOurList) { if (status == Status.ON) { + logger.d("Ignoring $systemSuspended $inOurList ${it.packageName} (${it.userId}) because of A") return@filter false } else { + logger.d("Including $systemSuspended $inOurList ${it.packageName} (${it.userId}) because of B") return@filter true } } else { if (status == Status.ON) { + logger.d("Including $systemSuspended $inOurList ${it.packageName} (${it.userId}) because of C") return@filter true } else { + logger.d("Ignoring $systemSuspended $inOurList ${it.packageName} (${it.userId}) because of D") return@filter false } } } else { if (status == Status.ON) { + logger.d("Ignoring/Including $systemSuspended $inOurList ${it.packageName} (${it.userId}) because of E ($inOurList)") return@filter inOurList } else { + logger.d("Ignoring $systemSuspended $inOurList ${it.packageName} (${it.userId}) because of F") return@filter false } } @@ -276,18 +352,23 @@ class WorkModeAccessor { ListMode.WHITELIST -> { if (systemSuspended) { if (inOurList) { + logger.d("Including $systemSuspended $inOurList ${it.packageName} (${it.userId}) because of B1") return@filter true } else { if (status == Status.ON) { + logger.d("Ignoring $systemSuspended $inOurList ${it.packageName} (${it.userId}) because of B2") return@filter false } else { + logger.d("Including $systemSuspended $inOurList ${it.packageName} (${it.userId}) because of B3") return@filter true } } } else { if (status == Status.ON) { + logger.d("Ignoring/Including $systemSuspended $inOurList ${it.packageName} (${it.userId}) because of B4 (${!inOurList})") return@filter !inOurList } else { + logger.d("Ignoring $systemSuspended $inOurList ${it.packageName} (${it.userId}) because of B5") return@filter false } } @@ -296,7 +377,9 @@ class WorkModeAccessor { } // Now, map them and determine that whatever a package should be suspended or un-suspended. .map { - val systemSuspended = systemSuspendedList.contains(it) + val systemSuspended = systemSuspendedList.any { a -> + return@any a.essentiallyEqual(it) + } when (listMode) { ListMode.BLACKLIST -> { if (systemSuspended) { @@ -322,46 +405,53 @@ class WorkModeAccessor { } // Collect them, we will execute later. .collect(Collectors.toList()) - // Suspend first - if (status == Status.ON) { - val suspendList = tasks.stream() + // Suspend first + if (status == Status.ON) { + val suspendList = tasks.stream() .filter { return@filter it.suspend } .map { - return@map it.packageName + return@map it.packageInfo } .collect(Collectors.toList()) - if (suspendList.size > 0) { - suspend(suspendList.toTypedArray(), + logger.d("Applying settings: suspend $suspendList") + if (suspendList.size > 0) { + pmAccess.suspend(suspendList, true) + } } - } - // Then unsuspand - val unsuspendList = tasks.stream() + // Then unsuspand + val unsuspendList = tasks.stream() .filter { return@filter !it.suspend } .map { - return@map it.packageName + return@map it.packageInfo } .collect(Collectors.toList()) - if (unsuspendList.size > 0) { - suspend(unsuspendList.toTypedArray(), + logger.d("Applying settings: unsuspend $unsuspendList") + if (unsuspendList.size > 0) { + pmAccess.suspend(unsuspendList, false) + } + readErrors(result, hostContext = hostInfo.hostContext) + postExecuteNotify(hostContext = hostInfo.hostContext) + return result } - } - private fun suspend(packageNames: Array<String>, suspended: Boolean): Array<String> = - pmAccess.setPackagesSuspended(packageNames, - suspended, - PersistableBundle(), - SuspendedApp.getDefault().serializeBundle(), // We use LauncherExtras because they are easy to read - mContext.getString(R.string.suspended_message)) + override fun getInstalledApplicationsAcrossUser(flags: Int): MutableList<TransferableSuspendedApp> { + val hostInfo = HostInfo.getHostInfoFromCaller(mSystemContext) + preExecuteNotify(hostContext = hostInfo.hostContext) + val result = _getInstalledApplicationsAcrossUser(AccessLayerUtil(AccessLayer(hostInfo.hostContext)), hostInfo, flags) + postExecuteNotify(hostContext = hostInfo.hostContext) + return result + } + } } private data class SuspendTask( - val packageName: String, + val packageInfo: TransferableSuspendedApp, val suspend: Boolean ) |