From bedce81f29d1d0e378725836b014e0ce0a521f69 Mon Sep 17 00:00:00 2001 From: YuutaW <17158086+trumeet@users.noreply.github.com> Date: Sat, 18 May 2019 09:17:52 -0700 Subject: fix(app): shrink & add MATCH_DISABLED_COMPONENTS flag & mark uninstalled apps as "unsafe" while loading the list Signed-off-by: YuutaW <17158086+Trumeet@users.noreply.github.com> --- app/src/debug/AndroidManifest.xml | 12 -- .../java/moe/yuuta/workmode/debug/DebugActivity.kt | 139 --------------------- .../java/moe/yuuta/ext/HandlerThreadExecutor.java | 26 ---- .../yuuta/workmode/ApplicationPickerActivity.kt | 4 +- .../main/java/moe/yuuta/workmode/MainActivity.kt | 17 +-- .../java/moe/yuuta/workmode/access/AccessLayer.kt | 4 +- .../moe/yuuta/workmode/access/AccessLayerUtil.kt | 5 +- .../moe/yuuta/workmode/access/WorkModeAccessor.kt | 7 +- .../suspend/data/TransferableSuspendedApp.kt | 2 +- .../yuuta/workmode/utils/ByteArraySerializer.kt | 26 ---- .../main/java/moe/yuuta/workmode/utils/Utils.kt | 18 +-- 11 files changed, 30 insertions(+), 230 deletions(-) delete mode 100644 app/src/debug/AndroidManifest.xml delete mode 100644 app/src/debug/java/moe/yuuta/workmode/debug/DebugActivity.kt delete mode 100644 app/src/main/java/moe/yuuta/ext/HandlerThreadExecutor.java delete mode 100644 app/src/main/java/moe/yuuta/workmode/utils/ByteArraySerializer.kt diff --git a/app/src/debug/AndroidManifest.xml b/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 92efdb0..0000000 --- a/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/debug/java/moe/yuuta/workmode/debug/DebugActivity.kt b/app/src/debug/java/moe/yuuta/workmode/debug/DebugActivity.kt deleted file mode 100644 index b8b5af8..0000000 --- a/app/src/debug/java/moe/yuuta/workmode/debug/DebugActivity.kt +++ /dev/null @@ -1,139 +0,0 @@ -package moe.yuuta.workmode.debug - -import android.graphics.Typeface -import android.os.Bundle -import android.os.Handler -import android.os.Looper -import android.text.method.ScrollingMovementMethod -import android.util.Log -import android.view.ViewGroup -import android.widget.Button -import android.widget.LinearLayout -import android.widget.TextView -import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity -import moe.yuuta.ext.HandlerThreadExecutor -import moe.yuuta.workmode.access.DumpResult -import moe.yuuta.workmode.suspend.AsyncSuspender -import moe.yuuta.workmode.suspend.data.TransferableSuspendedApp -import moe.yuuta.workmode.utils.Utils -import java.util.concurrent.CompletableFuture - -class DebugActivity : AppCompatActivity() { - companion object { - private const val TAG = "Debug" - } - - private var mCurrentFuture: CompletableFuture<*>? = null - private lateinit var mLogText: TextView - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - Log.i(TAG, "Starting") - val rootView = LinearLayout(this) - rootView.orientation = LinearLayout.VERTICAL - - mLogText = TextView(this) - mLogText.typeface = Typeface.MONOSPACE - mLogText.movementMethod = ScrollingMovementMethod() - rootView.addView(mLogText) - - registerTestingFunction(rootView, "isSuspended", object : Callback { - override fun call(): CompletableFuture<*> { - return AsyncSuspender(this@DebugActivity).isSuspended(listOf(TransferableSuspendedApp.of("kh.android.dir"), - TransferableSuspendedApp.of("com.android.chrome"))) - } - }) - - registerTestingFunction(rootView, "getSuspendedPackageAppExtras", object : Callback { - override fun call(): CompletableFuture<*> { - return AsyncSuspender(this@DebugActivity).getSuspendedPackageAppExtras(TransferableSuspendedApp.of("com.android.chrome")) - } - }) - - registerTestingFunction(rootView, "getSuspendedPackageLauncherExtras", object : Callback { - override fun call(): CompletableFuture<*> { - return AsyncSuspender(this@DebugActivity).getSuspendedPackageLauncherExtras(TransferableSuspendedApp.of("com.android.chrome")) - } - }) - - registerTestingFunction(rootView, "dump", object : Callback { - override fun call(): CompletableFuture<*> { - return AsyncSuspender(this@DebugActivity).dump(TransferableSuspendedApp.of("com.google.android.dialer", 11)) - } - }) - - registerTestingFunction(rootView, "suspend (true)", object : Callback { - override fun call(): CompletableFuture<*> { - return AsyncSuspender(this@DebugActivity).suspend(listOf(TransferableSuspendedApp.of("kh.android.dir"), - TransferableSuspendedApp.of("com.android.chrome")), true) - } - }) - - registerTestingFunction(rootView, "suspend (false)", object : Callback { - override fun call(): CompletableFuture<*> { - return AsyncSuspender(this@DebugActivity).suspend(listOf(TransferableSuspendedApp.of("kh.android.dir"), - TransferableSuspendedApp.of("com.android.chrome")), false) - } - }) - - registerTestingFunction(rootView, "apply", object : Callback { - override fun call(): CompletableFuture<*> { - return AsyncSuspender(this@DebugActivity).applyFromSettings() - } - }) - - registerTestingFunction(rootView, "getInstalledApplicationsAcrossUser", object : Callback { - override fun call(): CompletableFuture<*> { - return AsyncSuspender(this@DebugActivity).getInstalledApplicationsAcrossUser(0) - } - }) - - Log.d(TAG, "Done, children amount: ${rootView.childCount}") - setContentView(rootView) - } - - private fun registerTestingFunction(rootView: ViewGroup, tag: String, onClickListener: Callback) { - val btn = Button(this) - btn.text = tag - btn.setOnClickListener { - if (mCurrentFuture != null && !(mCurrentFuture as CompletableFuture<*>).isDone) { - Toast.makeText(this, "Current running task is not done yet.", Toast.LENGTH_SHORT).show() - return@setOnClickListener - } - mLogText.text = "" - mLogText.append("Started task.\n") - mCurrentFuture = onClickListener - .call() - /* .exceptionally { - runOnUiThread { - Log.e(TAG, "Exceptionally ${Thread.currentThread().name}", it) - mLogText.append("\n") - mLogText.append("Exceptionally: $it\n") - } - return@exceptionally null - } */ - .handle { result, e -> - // handleAsync() doesn't work - runOnUiThread { - if (result != null && result is DumpResult) { - mLogText.append("DumpResult - Launcher Extras: ${Utils.dumpExtras(result.launcherExtras)}\n") - } - mLogText.append("Done!\n") - mLogText.append("Result: $result\n") - mLogText.append("Error: $e") - } - } - .thenRunAsync(Runnable { - Log.e(TAG, "Then run ${Thread.currentThread().name}") - mLogText.append("\n") - mLogText.append("Run.") - }, HandlerThreadExecutor(Handler(Looper.getMainLooper()))) - } - rootView.addView(btn) - } - - private interface Callback { - fun call(): CompletableFuture<*> - } -} \ No newline at end of file diff --git a/app/src/main/java/moe/yuuta/ext/HandlerThreadExecutor.java b/app/src/main/java/moe/yuuta/ext/HandlerThreadExecutor.java deleted file mode 100644 index d6c51bc..0000000 --- a/app/src/main/java/moe/yuuta/ext/HandlerThreadExecutor.java +++ /dev/null @@ -1,26 +0,0 @@ -package moe.yuuta.ext; - -import android.os.Handler; -import android.os.Looper; -import android.util.Log; -import androidx.annotation.Nullable; - -import java.util.concurrent.Executor; - -/** - * https://stackoverflow.com/a/21256419/6792243 - */ -public class HandlerThreadExecutor implements Executor { - private final Handler mHandler; - public HandlerThreadExecutor(@Nullable Handler optionalHandler) { - mHandler = optionalHandler != null ? optionalHandler : new Handler(Looper.getMainLooper()); - } - - @Override - public void execute(Runnable command) { - Log.d("Debug", "execute: " + command.toString()); - mHandler.post(command); - Log.d("Debug", "done executing"); - // - } -} \ No newline at end of file diff --git a/app/src/main/java/moe/yuuta/workmode/ApplicationPickerActivity.kt b/app/src/main/java/moe/yuuta/workmode/ApplicationPickerActivity.kt index 736fb0a..5723ab1 100644 --- a/app/src/main/java/moe/yuuta/workmode/ApplicationPickerActivity.kt +++ b/app/src/main/java/moe/yuuta/workmode/ApplicationPickerActivity.kt @@ -91,7 +91,7 @@ class ApplicationPickerActivity : AppCompatActivity() { if (::mLoadAppsFuture.isInitialized && !mLoadAppsFuture.isDone) { mLoadAppsFuture.cancel(true) } - mLoadAppsFuture = AsyncSuspender(this).getInstalledApplicationsAcrossUser(0) + mLoadAppsFuture = AsyncSuspender(this).getInstalledApplicationsAcrossUser(PackageManager.MATCH_DISABLED_COMPONENTS) mProgressBar.visibility = View.VISIBLE fab.visibility = View.GONE mLoadAppsFuture @@ -176,7 +176,7 @@ class ApplicationPickerActivity : AppCompatActivity() { else context .packageManager .getApplicationLabel( - context.packageManager.getApplicationInfo(packageInfo.packageInfo.packageName, 0) + context.packageManager.getApplicationInfo(packageInfo.packageInfo.packageName, PackageManager.MATCH_DISABLED_COMPONENTS) ) holder.summary.text = context.getString(R.string.app_list_user_template, packageInfo.packageInfo.userId) holder.checkBox.isChecked = packageInfo.selected diff --git a/app/src/main/java/moe/yuuta/workmode/MainActivity.kt b/app/src/main/java/moe/yuuta/workmode/MainActivity.kt index de913c3..b3f4882 100644 --- a/app/src/main/java/moe/yuuta/workmode/MainActivity.kt +++ b/app/src/main/java/moe/yuuta/workmode/MainActivity.kt @@ -171,6 +171,12 @@ class MainActivity : AppCompatActivity(), SwitchBar.OnSwitchChangeListener, View // TODO val canSafelyLoadAppInfoForO1 = Utils.canSafelyLoadAppInfo(o1, this@MainActivity) val canSafelyLoadAppInfoForO2 = Utils.canSafelyLoadAppInfo(o2, this@MainActivity) + if ((canSafelyLoadAppInfoForO1 && !canSafelyLoadAppInfoForO2) || + (!canSafelyLoadAppInfoForO1 && canSafelyLoadAppInfoForO2)) { + // A unsafe app is comparing to a safe app, just put the unsafe one in under the safe one. + return@sorted 1 + } + // They are both unsafe requests. if (!canSafelyLoadAppInfoForO1 || !canSafelyLoadAppInfoForO2) { if (o1.userId > o2.userId) { @@ -181,13 +187,8 @@ class MainActivity : AppCompatActivity(), SwitchBar.OnSwitchChangeListener, View return@sorted 0 } } - if ((canSafelyLoadAppInfoForO1 && !canSafelyLoadAppInfoForO2) || - (!canSafelyLoadAppInfoForO1 && canSafelyLoadAppInfoForO2)) { - // A unsafe app is comparing to a safe app, just put the unsafe one in under the safe one. - return@sorted 1 - } - return@sorted sCollator.compare(packageManager.getApplicationLabel(packageManager.getApplicationInfo(o1.packageName, 0)).toString() - , packageManager.getApplicationLabel(packageManager.getApplicationInfo(o2.packageName, 0))) + return@sorted sCollator.compare(packageManager.getApplicationLabel(packageManager.getApplicationInfo(o1.packageName, PackageManager.MATCH_DISABLED_COMPONENTS)).toString() + , packageManager.getApplicationLabel(packageManager.getApplicationInfo(o2.packageName, PackageManager.MATCH_DISABLED_COMPONENTS))) } .collect(Collectors.toList()) } @@ -397,7 +398,7 @@ private class Adapter : RecyclerView.Adapter() { context .packageManager .getApplicationLabel( - context.packageManager.getApplicationInfo(packageInfo.packageName, 0) + context.packageManager.getApplicationInfo(packageInfo.packageName, PackageManager.MATCH_DISABLED_COMPONENTS) ) else packageInfo.packageName 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 d3fccb6..ed6e75b 100644 --- a/app/src/main/java/moe/yuuta/workmode/access/AccessLayer.kt +++ b/app/src/main/java/moe/yuuta/workmode/access/AccessLayer.kt @@ -49,7 +49,7 @@ internal class AccessLayer(internal val mContext: Context) { * Create a new process and access it. */ fun getSuspendedPackageAppExtras(packageName: String, userId: Int): PersistableBundle? { - Os.setuid(mPM.getPackageUid(packageName, 0)) + Os.setuid(mPM.getPackageUid(packageName, PackageManager.MATCH_DISABLED_COMPONENTS)) // ApplicationPackageManager ALWAYS uses hostContext.getOpPackageName() as the package name // F**k Google val func: Method = Class.forName("android.content.pm.IPackageManager") @@ -78,7 +78,7 @@ internal class AccessLayer(internal val mContext: Context) { mContext.getSystemService(LauncherApps::class.java).getSuspendedPackageLauncherExtras(packageName, createUserHandleWithUserID(userId)) - fun getInstalledApplicationsAsUser(flags: Int, userId: Int): List = + fun getInstalledApplicationsAsUser(@PackageManager.ApplicationInfoFlags flags: Int, userId: Int): List = mPM.getInstalledApplicationsAsUser(flags, userId) companion object { diff --git a/app/src/main/java/moe/yuuta/workmode/access/AccessLayerUtil.kt b/app/src/main/java/moe/yuuta/workmode/access/AccessLayerUtil.kt index 7248198..08aed19 100644 --- a/app/src/main/java/moe/yuuta/workmode/access/AccessLayerUtil.kt +++ b/app/src/main/java/moe/yuuta/workmode/access/AccessLayerUtil.kt @@ -1,6 +1,7 @@ package moe.yuuta.workmode.access import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager import android.os.* import com.elvishew.xlog.XLog import moe.yuuta.workmode.R @@ -80,10 +81,10 @@ internal class AccessLayerUtil(private val accessLayer: AccessLayer) { accessLayer.getSuspendedPackageLauncherExtras(packageName = packageInfo.packageName, userId = packageInfo.userId) - fun getInstalledApplicationsAsUser(flags: Int, userId: Int): List = + fun getInstalledApplicationsAsUser(@PackageManager.ApplicationInfoFlags flags: Int, userId: Int): List = accessLayer.getInstalledApplicationsAsUser(flags, userId) - fun getInstalledApplicationsAnyUser(flags: Int): List { + fun getInstalledApplicationsAnyUser(@PackageManager.ApplicationInfoFlags flags: Int): List { val userManager = accessLayer.mContext.getSystemService(UserManager::class.java) val finalResult = mutableListOf() val ids = userManager.getUsers(false) 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 af60701..7bfe2f4 100644 --- a/app/src/main/java/moe/yuuta/workmode/access/WorkModeAccessor.kt +++ b/app/src/main/java/moe/yuuta/workmode/access/WorkModeAccessor.kt @@ -5,6 +5,7 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager import android.os.Bundle import android.os.PersistableBundle import android.os.UserHandle @@ -87,7 +88,7 @@ class WorkModeAccessor { return result } - private fun _getInstalledApplicationsAcrossUser(pmAccess: AccessLayerUtil, hostInfo: HostInfo, flags: Int): MutableList { + private fun _getInstalledApplicationsAcrossUser(pmAccess: AccessLayerUtil, hostInfo: HostInfo, @PackageManager.ApplicationInfoFlags flags: Int): MutableList { val originalApplicationInfo = mutableMapOf() val packages = if (hostInfo.userId == UserHandle.USER_OWNER) { @@ -110,7 +111,7 @@ class WorkModeAccessor { 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 appsInUser = pmAccess.getInstalledApplicationsAsUser(flags, userId) val firstApp = appsInUser[0] val targetContext = mSystemContext.createPackageContextAsUser(firstApp.packageName, 0, @@ -230,7 +231,7 @@ class WorkModeAccessor { // 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 systemAllAppList = _getInstalledApplicationsAcrossUser(pmAccess, hostInfo, PackageManager.MATCH_DISABLED_COMPONENTS) val systemSuspendedList = _getPackagesSuspendedByWorkMode(pmAccess, systemAllAppList) val listMode = when (rawListMode) { 1 -> ListMode.BLACKLIST diff --git a/app/src/main/java/moe/yuuta/workmode/suspend/data/TransferableSuspendedApp.kt b/app/src/main/java/moe/yuuta/workmode/suspend/data/TransferableSuspendedApp.kt index 03bf842..498a400 100644 --- a/app/src/main/java/moe/yuuta/workmode/suspend/data/TransferableSuspendedApp.kt +++ b/app/src/main/java/moe/yuuta/workmode/suspend/data/TransferableSuspendedApp.kt @@ -40,7 +40,7 @@ data class TransferableSuspendedApp( @SystemApi fun fillData(pm: PackageManager, ignoreLargeData: Boolean) { val info = pm.getApplicationInfoAsUser(packageName, - 0, + PackageManager.MATCH_DISABLED_COMPONENTS, userId) label = if (ignoreLargeData) null else pm.getApplicationLabel(info) diff --git a/app/src/main/java/moe/yuuta/workmode/utils/ByteArraySerializer.kt b/app/src/main/java/moe/yuuta/workmode/utils/ByteArraySerializer.kt deleted file mode 100644 index 8792e04..0000000 --- a/app/src/main/java/moe/yuuta/workmode/utils/ByteArraySerializer.kt +++ /dev/null @@ -1,26 +0,0 @@ -package moe.yuuta.workmode.utils - -object ByteArraySerializer { - fun serialize(array: ByteArray): String { - val builder = StringBuilder() - array.toList().stream() - .forEachOrdered { - builder.append(it) - builder.append(',') - } - var result = builder.toString() - result = result.substring(0, result.length - 1) - return result - } - - fun deserialize(value: String): ByteArray { - val list = value.split(',').toList() - var array = ByteArray(0) - - list.stream() - .forEachOrdered { - array = array.plus(it.toByte()) - } - return array - } -} \ No newline at end of file diff --git a/app/src/main/java/moe/yuuta/workmode/utils/Utils.kt b/app/src/main/java/moe/yuuta/workmode/utils/Utils.kt index 75a98e9..10bef07 100644 --- a/app/src/main/java/moe/yuuta/workmode/utils/Utils.kt +++ b/app/src/main/java/moe/yuuta/workmode/utils/Utils.kt @@ -61,7 +61,7 @@ object Utils { fun buildGeneralApplicationInfoFilter(context: Context): Predicate { val i = Intent(Intent.ACTION_MAIN) i.addCategory(Intent.CATEGORY_HOME) - val launchers = context.packageManager.queryIntentActivities(i, 0) + val launchers = context.packageManager.queryIntentActivities(i, PackageManager.MATCH_DISABLED_COMPONENTS) .stream() .map { return@map it.resolvePackageName @@ -99,7 +99,7 @@ object Utils { fun buildGeneralSuspendedAppInfoFilter(context: Context): Predicate { val i = Intent(Intent.ACTION_MAIN) i.addCategory(Intent.CATEGORY_HOME) - val launchers = context.packageManager.queryIntentActivitiesAsUser(i, 0, context.userId) + val launchers = context.packageManager.queryIntentActivitiesAsUser(i, PackageManager.MATCH_DISABLED_COMPONENTS, context.userId) .stream() .map { return@map it.resolvePackageName @@ -144,7 +144,7 @@ object Utils { val intentToResolve = Intent(Intent.ACTION_MAIN) intentToResolve.addCategory(Intent.CATEGORY_INFO) intentToResolve.setPackage(packageName) - var ris: List? = pm.queryIntentActivitiesAsUser(intentToResolve, 0, userId) + var ris: List? = pm.queryIntentActivitiesAsUser(intentToResolve, PackageManager.MATCH_DISABLED_COMPONENTS, userId) // Otherwise, try to find a main launcher activity. if (ris == null || ris.size <= 0) { @@ -152,7 +152,7 @@ object Utils { intentToResolve.removeCategory(Intent.CATEGORY_INFO) intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER) intentToResolve.setPackage(packageName) - ris = pm.queryIntentActivitiesAsUser(intentToResolve, 0, userId) + ris = pm.queryIntentActivitiesAsUser(intentToResolve, PackageManager.MATCH_DISABLED_COMPONENTS, userId) } if (ris == null || ris.size <= 0) { return null @@ -206,12 +206,12 @@ object Utils { } fun canSafelyLoadAppInfo(packageInfo: PersistableSuspendedApp, context: Context): Boolean { - return packageInfo.userId == Process.myUserHandle().hashCode() || + return packageInfo.userId == Process.myUserHandle().hashCode() && isAppInstalledInCurrentUser(packageInfo.packageName, context) } fun canSafelyLoadAppInfo(packageInfo: TransferableSuspendedApp, userId: Int, context: Context): Boolean { - return packageInfo.userId == userId || + return packageInfo.userId == userId && isAppInstalledInUser(packageInfo.packageName, context, userId) } @@ -221,11 +221,11 @@ object Utils { @SystemApi fun isAppInstalledInUser(packageName: String, context: Context, userId: Int): Boolean { - try { + return try { context.packageManager.getPackageInfoAsUser(packageName, PackageManager.GET_DISABLED_COMPONENTS, userId) - return true + true } catch (e: PackageManager.NameNotFoundException) { - return false + false } } } \ No newline at end of file -- cgit v1.2.3