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
This commit is contained in:
agnostic-apollo
2021-09-23 16:46:59 +05:00
parent 0bf4b1eca4
commit 075a080f00
2 changed files with 113 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
@@ -249,6 +250,8 @@ public class PackageUtils {
return null; return null;
} }
/** /**
* Get the process id of the main app process of a package. This will work for sharedUserId. Note * 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"` * that some apps have multiple processes for the app like with `android:process=":background"`
@@ -275,6 +278,8 @@ public class PackageUtils {
return null; return null;
} }
/** /**
* Check if app is installed and enabled. This can be used by external apps that don't * Check if app is installed and enabled. This can be used by external apps that don't
* share `sharedUserId` with the an app. * share `sharedUserId` with the an app.
@@ -318,4 +323,97 @@ public class PackageUtils {
return errmsg; 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;
}
} }

View File

@@ -24,6 +24,10 @@
<string name="error_get_package_context_failed_message">Failed to get package context for the \"%1$s\" package. <string name="error_get_package_context_failed_message">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. 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.</string> Check install instruction at %2$s for more details.</string>
<string name="error_get_component_state_failed">Failed to get %1$s/%2$s component state"</string>
<string name="error_enable_component_failed">Failed to enable %1$s/%2$s component"</string>
<string name="error_disable_component_failed">Failed to enable %1$s/%2$s component"</string>
@@ -91,6 +95,17 @@
<!-- Launcher Icons -->
<string name="action_enable_launcher_icon">Enable Launcher Icon</string>
<string name="action_disable_launcher_icon">Disable Launcher Icon</string>
<string name="msg_enabling_launcher_icon">Enabling %1$s app launcher icon"</string>
<string name="msg_disabling_launcher_icon">Disabling %1$s app launcher icon"</string>
<string name="setting_launcher_icon_title">Launcher Icon Enabled</string>
<string name="setting_launcher_icon_enabled_off">Launcher Icon will be disabled.</string>
<string name="setting_launcher_icon_enabled_on">Launcher Icon will be enabled. (Default)</string>
<!-- Log Level --> <!-- Log Level -->
<string name="log_level_title">Log Level</string> <string name="log_level_title">Log Level</string>
<string name="log_level_off">"Off"</string> <string name="log_level_off">"Off"</string>