From 075a080f00e7ec637e69cc714c49239718bfda3d Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Thu, 23 Sep 2021 16:46:59 +0500 Subject: [PATCH] Added: Add functions to PackageUtils to check/modify app Component states These can be used by Termux app and its plugin to disable launcher icons/activities if they are enabled at install time --- .../termux/shared/packages/PackageUtils.java | 98 +++++++++++++++++++ termux-shared/src/main/res/values/strings.xml | 15 +++ 2 files changed, 113 insertions(+) diff --git a/termux-shared/src/main/java/com/termux/shared/packages/PackageUtils.java b/termux-shared/src/main/java/com/termux/shared/packages/PackageUtils.java index cb6bc401..60997b27 100644 --- a/termux-shared/src/main/java/com/termux/shared/packages/PackageUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/packages/PackageUtils.java @@ -4,6 +4,7 @@ import android.app.ActivityManager; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -249,6 +250,8 @@ public class PackageUtils { return null; } + + /** * Get the process id of the main app process of a package. This will work for sharedUserId. Note * that some apps have multiple processes for the app like with `android:process=":background"` @@ -275,6 +278,8 @@ public class PackageUtils { return null; } + + /** * Check if app is installed and enabled. This can be used by external apps that don't * share `sharedUserId` with the an app. @@ -318,4 +323,97 @@ public class PackageUtils { return errmsg; } + + + /** + * Enable or disable a {@link ComponentName} with a call to + * {@link PackageManager#setComponentEnabledSetting(ComponentName, int, int)}. + * + * @param context The {@link Context} for operations. + * @param packageName The package name of the component. + * @param className The {@link Class} name of the component. + * @param state If component should be enabled or disabled. + * @param toastString If this is not {@code null} or empty, then a toast before setting state. + * @param showErrorMessage If an error message toast should be shown. + * @return Returns the errmsg if failed to set state, otherwise {@code null}. + */ + @Nullable + public static String setComponentState(@NonNull final Context context, @NonNull String packageName, + @NonNull String className, boolean state, String toastString, + boolean showErrorMessage) { + try { + PackageManager packageManager = context.getPackageManager(); + if (packageManager != null) { + ComponentName componentName = new ComponentName(packageName, className); + if (toastString != null) Logger.showToast(context, toastString, true); + packageManager.setComponentEnabledSetting(componentName, + state ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + } + return null; + } catch (final Exception e) { + String errmsg = context.getString( + state ? R.string.error_enable_component_failed : R.string.error_disable_component_failed, + packageName, className) + ": " + e.getMessage(); + if (showErrorMessage) + Logger.showToast(context, errmsg, true); + return errmsg; + } + } + + /** + * Check if state of a {@link ComponentName} is {@link PackageManager#COMPONENT_ENABLED_STATE_DISABLED} + * with a call to {@link PackageManager#getComponentEnabledSetting(ComponentName)}. + * + * @param context The {@link Context} for operations. + * @param packageName The package name of the component. + * @param className The {@link Class} name of the component. + * @param logErrorMessage If an error message should be logged. + * @return Returns {@code true} if disabled, {@code false} if not and {@code null} if failed to + * get the state. + */ + public static Boolean isComponentDisabled(@NonNull final Context context, @NonNull String packageName, + @NonNull String className, boolean logErrorMessage) { + try { + PackageManager packageManager = context.getPackageManager(); + if (packageManager != null) { + ComponentName componentName = new ComponentName(packageName, className); + // Will throw IllegalArgumentException: Unknown component: ComponentInfo{} if app + // for context is not installed or component does not exist. + return packageManager.getComponentEnabledSetting(componentName) == PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + } + } catch (final Exception e) { + if (logErrorMessage) + Logger.logStackTraceWithMessage(LOG_TAG, context.getString(R.string.error_get_component_state_failed, packageName, className), e); + } + + return null; + } + + /** + * Check if an {@link android.app.Activity} {@link ComponentName} can be called by calling + * {@link PackageManager#queryIntentActivities(Intent, int)}. + * + * @param context The {@link Context} for operations. + * @param packageName The package name of the component. + * @param className The {@link Class} name of the component. + * @param flags The flags to filter results. + * @return Returns {@code true} if it exists, otherwise {@code false}. + */ + public static boolean doesActivityComponentExist(@NonNull final Context context, @NonNull String packageName, + @NonNull String className, int flags) { + try { + PackageManager packageManager = context.getPackageManager(); + if (packageManager != null) { + Intent intent = new Intent(); + intent.setClassName(packageName, className); + return packageManager.queryIntentActivities(intent, flags).size() > 0; + } + } catch (final Exception e) { + // ignore + } + + return false; + } + } diff --git a/termux-shared/src/main/res/values/strings.xml b/termux-shared/src/main/res/values/strings.xml index 070b1870..06433ecb 100644 --- a/termux-shared/src/main/res/values/strings.xml +++ b/termux-shared/src/main/res/values/strings.xml @@ -24,6 +24,10 @@ Failed to get package context for the \"%1$s\" package. This may be because the app package is not installed or it has different APK signature from the current app. Check install instruction at %2$s for more details. + Failed to get %1$s/%2$s component state" + Failed to enable %1$s/%2$s component" + Failed to enable %1$s/%2$s component" + @@ -91,6 +95,17 @@ + + Enable Launcher Icon + Disable Launcher Icon + Enabling %1$s app launcher icon" + Disabling %1$s app launcher icon" + Launcher Icon Enabled + Launcher Icon will be disabled. + Launcher Icon will be enabled. (Default) + + + Log Level "Off"