From e5c05489429849d67f3fe6e4a37ef3d09eeb4e49 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Sat, 4 Sep 2021 08:06:54 +0500 Subject: [PATCH] Added: Add isTermuxAppInstalled() and isTermuxAppAccessible() functions to TermuxUtils The `TermuxUtils.isTermuxAppInstalled()` function can be used by external apps to check if termux app is installed and enabled. The `TermuxUtils.isTermuxAppAccessible()` function can be used by termux plugin apps to check if termux app is installed, enabled, accessible as per `sharedUserId` and `TERMUX_PREFIX_DIR_PATH` is accessible and has read, write and execute permission. --- .../com/termux/shared/termux/TermuxUtils.java | 87 +++++++++++++++++++ termux-shared/src/main/res/values/strings.xml | 10 +++ 2 files changed, 97 insertions(+) diff --git a/termux-shared/src/main/java/com/termux/shared/termux/TermuxUtils.java b/termux-shared/src/main/java/com/termux/shared/termux/TermuxUtils.java index 62fa7864f7..df45a5e9a7 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/TermuxUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/TermuxUtils.java @@ -3,11 +3,14 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import androidx.annotation.NonNull; import com.termux.shared.R; +import com.termux.shared.file.FileUtils; import com.termux.shared.file.TermuxFileUtils; import com.termux.shared.logger.Logger; import com.termux.shared.markdown.MarkdownUtils; @@ -101,6 +104,90 @@ public static Context getTermuxWidgetPackageContext(@NonNull Context context) { + /** + * Check if Termux app is installed and enabled. This can be used by external apps that don't + * share `sharedUserId` with the Termux app. + * + * If your third-party app is targeting sdk `30` (android `11`), then it needs to add `com.termux` + * package to the `queries` element or request `QUERY_ALL_PACKAGES` permission in its + * `AndroidManifest.xml`. Otherwise it will get `PackageSetting{...... com.termux/......} BLOCKED` + * errors in `logcat` and `RUN_COMMAND` won't work. + * Check [package-visibility](https://developer.android.com/training/basics/intents/package-visibility#package-name), + * `QUERY_ALL_PACKAGES` [googleplay policy](https://support.google.com/googleplay/android-developer/answer/10158779 + * and this [article](https://medium.com/androiddevelopers/working-with-package-visibility-dc252829de2d) for more info. + * + * {@code + * + * + * + * + * } + * + * @param currentPackageContext The context of current package. + * @return Returns {@code errmsg} if termux package is not installed or disabled, otherwise {@code null}. + */ + public static String isTermuxAppInstalled(@NonNull final Context currentPackageContext) { + String errmsg = null; + + PackageManager packageManager = currentPackageContext.getPackageManager(); + + ApplicationInfo applicationInfo; + try { + applicationInfo = packageManager.getApplicationInfo(TermuxConstants.TERMUX_PACKAGE_NAME, 0); + } catch (final PackageManager.NameNotFoundException e) { + applicationInfo = null; + } + boolean termuxAppEnabled = (applicationInfo != null && applicationInfo.enabled); + + // If Termux app is not installed or is disabled + if (!termuxAppEnabled) + errmsg = currentPackageContext.getString(R.string.error_termux_app_not_installed_or_disabled_warning); + + return errmsg; + } + + /** + * Check if Termux app is installed and accessible. This can only be used by apps that share + * `sharedUserId` with the Termux app. + * + * This is done by checking if first checking if app is installed and enabled and then if + * {@code currentPackageContext} can be used to get the {@link Context} of the app with + * {@link TermuxConstants#TERMUX_PACKAGE_NAME} and then if + * {@link TermuxConstants#TERMUX_PREFIX_DIR_PATH} exists and has + * {@link FileUtils#APP_WORKING_DIRECTORY_PERMISSIONS} permissions. The directory will not + * be automatically created and neither the missing permissions automatically set. + * + * @param currentPackageContext The context of current package. + * @return Returns {@code errmsg} if failed to get termux package {@link Context} or + * {@link TermuxConstants#TERMUX_PREFIX_DIR_PATH} is accessible, otherwise {@code null}. + */ + public static String isTermuxAppAccessible(@NonNull final Context currentPackageContext) { + String errmsg = isTermuxAppInstalled(currentPackageContext); + if (errmsg == null) { + Context termuxPackageContext = TermuxUtils.getTermuxPackageContext(currentPackageContext); + // If failed to get Termux app package context + if (termuxPackageContext == null) + errmsg = currentPackageContext.getString(R.string.error_termux_app_package_context_not_accessible); + + if (errmsg == null) { + // If TermuxConstants.TERMUX_PREFIX_DIR_PATH is not a directory or does not have required permissions + Error error = TermuxFileUtils.isTermuxPrefixDirectoryAccessible(false, false); + if (error != null) + errmsg = currentPackageContext.getString(R.string.error_termux_prefix_dir_path_not_accessible, + PackageUtils.getAppNameForPackage(currentPackageContext)); + } + } + + if (errmsg != null) + return errmsg + " " + currentPackageContext.getString(R.string.msg_termux_app_required_by_app, + PackageUtils.getAppNameForPackage(currentPackageContext)); + else + return null; + } + + + /** * Send the {@link TermuxConstants#BROADCAST_TERMUX_OPENED} broadcast to notify apps that Termux * app has been opened. diff --git a/termux-shared/src/main/res/values/strings.xml b/termux-shared/src/main/res/values/strings.xml index 65e3667c86..c79d04c19a 100644 --- a/termux-shared/src/main/res/values/strings.xml +++ b/termux-shared/src/main/res/values/strings.xml @@ -9,6 +9,7 @@ + ]> @@ -71,6 +72,15 @@ on github or other official termux community forums **will likely be automatically closed/deleted** and may even result in **temporary or permanent** ban. Check %1$s/wiki/Hacking for details. + The &TERMUX_APP_NAME; is required by the %1$s app to run termux commands." + The &TERMUX_APP_NAME; app is not installed or is disabled." + The &TERMUX_APP_NAME; app (package context) is not accessible." + The &TERMUX_APP_NAME; app $PREFIX directory is not accessible by the %1$s app. + This may be because you have not installed or setup &TERMUX_APP_NAME; app or + &TERMUX_APP_NAME; app and %1$s app both have different APK signatures because you have managed to install both apps from different sources. + It may also be because &TERMUX_APP_NAME; $PREFIX directory \"&TERMUX_PREFIX_DIR_PATH;\" does not exist or does not have read, + write and execute permissions." +