|
3 | 3 | import android.content.ComponentName;
|
4 | 4 | import android.content.Context;
|
5 | 5 | import android.content.Intent;
|
| 6 | +import android.content.pm.ApplicationInfo; |
| 7 | +import android.content.pm.PackageManager; |
6 | 8 | import android.content.pm.ResolveInfo;
|
7 | 9 |
|
8 | 10 | import androidx.annotation.NonNull;
|
9 | 11 |
|
10 | 12 | import com.termux.shared.R;
|
| 13 | +import com.termux.shared.file.FileUtils; |
11 | 14 | import com.termux.shared.file.TermuxFileUtils;
|
12 | 15 | import com.termux.shared.logger.Logger;
|
13 | 16 | import com.termux.shared.markdown.MarkdownUtils;
|
@@ -101,6 +104,90 @@ public static Context getTermuxWidgetPackageContext(@NonNull Context context) {
|
101 | 104 |
|
102 | 105 |
|
103 | 106 |
|
| 107 | + /** |
| 108 | + * Check if Termux app is installed and enabled. This can be used by external apps that don't |
| 109 | + * share `sharedUserId` with the Termux app. |
| 110 | + * |
| 111 | + * If your third-party app is targeting sdk `30` (android `11`), then it needs to add `com.termux` |
| 112 | + * package to the `queries` element or request `QUERY_ALL_PACKAGES` permission in its |
| 113 | + * `AndroidManifest.xml`. Otherwise it will get `PackageSetting{...... com.termux/......} BLOCKED` |
| 114 | + * errors in `logcat` and `RUN_COMMAND` won't work. |
| 115 | + * Check [package-visibility](https://developer.android.com/training/basics/intents/package-visibility#package-name), |
| 116 | + * `QUERY_ALL_PACKAGES` [googleplay policy](https://support.google.com/googleplay/android-developer/answer/10158779 |
| 117 | + * and this [article](https://medium.com/androiddevelopers/working-with-package-visibility-dc252829de2d) for more info. |
| 118 | + * |
| 119 | + * {@code |
| 120 | + * <manifest |
| 121 | + * <queries> |
| 122 | + * <package android:name="com.termux" /> |
| 123 | + * </queries> |
| 124 | + * </manifest> |
| 125 | + * } |
| 126 | + * |
| 127 | + * @param currentPackageContext The context of current package. |
| 128 | + * @return Returns {@code errmsg} if termux package is not installed or disabled, otherwise {@code null}. |
| 129 | + */ |
| 130 | + public static String isTermuxAppInstalled(@NonNull final Context currentPackageContext) { |
| 131 | + String errmsg = null; |
| 132 | + |
| 133 | + PackageManager packageManager = currentPackageContext.getPackageManager(); |
| 134 | + |
| 135 | + ApplicationInfo applicationInfo; |
| 136 | + try { |
| 137 | + applicationInfo = packageManager.getApplicationInfo(TermuxConstants.TERMUX_PACKAGE_NAME, 0); |
| 138 | + } catch (final PackageManager.NameNotFoundException e) { |
| 139 | + applicationInfo = null; |
| 140 | + } |
| 141 | + boolean termuxAppEnabled = (applicationInfo != null && applicationInfo.enabled); |
| 142 | + |
| 143 | + // If Termux app is not installed or is disabled |
| 144 | + if (!termuxAppEnabled) |
| 145 | + errmsg = currentPackageContext.getString(R.string.error_termux_app_not_installed_or_disabled_warning); |
| 146 | + |
| 147 | + return errmsg; |
| 148 | + } |
| 149 | + |
| 150 | + /** |
| 151 | + * Check if Termux app is installed and accessible. This can only be used by apps that share |
| 152 | + * `sharedUserId` with the Termux app. |
| 153 | + * |
| 154 | + * This is done by checking if first checking if app is installed and enabled and then if |
| 155 | + * {@code currentPackageContext} can be used to get the {@link Context} of the app with |
| 156 | + * {@link TermuxConstants#TERMUX_PACKAGE_NAME} and then if |
| 157 | + * {@link TermuxConstants#TERMUX_PREFIX_DIR_PATH} exists and has |
| 158 | + * {@link FileUtils#APP_WORKING_DIRECTORY_PERMISSIONS} permissions. The directory will not |
| 159 | + * be automatically created and neither the missing permissions automatically set. |
| 160 | + * |
| 161 | + * @param currentPackageContext The context of current package. |
| 162 | + * @return Returns {@code errmsg} if failed to get termux package {@link Context} or |
| 163 | + * {@link TermuxConstants#TERMUX_PREFIX_DIR_PATH} is accessible, otherwise {@code null}. |
| 164 | + */ |
| 165 | + public static String isTermuxAppAccessible(@NonNull final Context currentPackageContext) { |
| 166 | + String errmsg = isTermuxAppInstalled(currentPackageContext); |
| 167 | + if (errmsg == null) { |
| 168 | + Context termuxPackageContext = TermuxUtils.getTermuxPackageContext(currentPackageContext); |
| 169 | + // If failed to get Termux app package context |
| 170 | + if (termuxPackageContext == null) |
| 171 | + errmsg = currentPackageContext.getString(R.string.error_termux_app_package_context_not_accessible); |
| 172 | + |
| 173 | + if (errmsg == null) { |
| 174 | + // If TermuxConstants.TERMUX_PREFIX_DIR_PATH is not a directory or does not have required permissions |
| 175 | + Error error = TermuxFileUtils.isTermuxPrefixDirectoryAccessible(false, false); |
| 176 | + if (error != null) |
| 177 | + errmsg = currentPackageContext.getString(R.string.error_termux_prefix_dir_path_not_accessible, |
| 178 | + PackageUtils.getAppNameForPackage(currentPackageContext)); |
| 179 | + } |
| 180 | + } |
| 181 | + |
| 182 | + if (errmsg != null) |
| 183 | + return errmsg + " " + currentPackageContext.getString(R.string.msg_termux_app_required_by_app, |
| 184 | + PackageUtils.getAppNameForPackage(currentPackageContext)); |
| 185 | + else |
| 186 | + return null; |
| 187 | + } |
| 188 | + |
| 189 | + |
| 190 | + |
104 | 191 | /**
|
105 | 192 | * Send the {@link TermuxConstants#BROADCAST_TERMUX_OPENED} broadcast to notify apps that Termux
|
106 | 193 | * app has been opened.
|
|
0 commit comments