Skip to content

Commit e5c0548

Browse files
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.
1 parent 4e5f2c7 commit e5c0548

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

termux-shared/src/main/java/com/termux/shared/termux/TermuxUtils.java

+87
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
import android.content.ComponentName;
44
import android.content.Context;
55
import android.content.Intent;
6+
import android.content.pm.ApplicationInfo;
7+
import android.content.pm.PackageManager;
68
import android.content.pm.ResolveInfo;
79

810
import androidx.annotation.NonNull;
911

1012
import com.termux.shared.R;
13+
import com.termux.shared.file.FileUtils;
1114
import com.termux.shared.file.TermuxFileUtils;
1215
import com.termux.shared.logger.Logger;
1316
import com.termux.shared.markdown.MarkdownUtils;
@@ -101,6 +104,90 @@ public static Context getTermuxWidgetPackageContext(@NonNull Context context) {
101104

102105

103106

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+
104191
/**
105192
* Send the {@link TermuxConstants#BROADCAST_TERMUX_OPENED} broadcast to notify apps that Termux
106193
* app has been opened.

termux-shared/src/main/res/values/strings.xml

+10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<!ENTITY TERMUX_STYLING_APP_NAME "Termux:Styling">
1010
<!ENTITY TERMUX_TASKER_APP_NAME "Termux:Tasker">
1111
<!ENTITY TERMUX_WIDGET_APP_NAME "Termux:Widget">
12+
<!ENTITY TERMUX_PREFIX_DIR_PATH "/data/data/com.termux/files/usr">
1213
]>
1314

1415
<resources>
@@ -71,6 +72,15 @@
7172
on github or other official termux community forums **will likely be automatically closed/deleted** and may
7273
even result in **temporary or permanent** ban. Check %1$s/wiki/Hacking for details.</string>
7374

75+
<string name="msg_termux_app_required_by_app">The &TERMUX_APP_NAME; is required by the %1$s app to run termux commands."</string>
76+
<string name="error_termux_app_not_installed_or_disabled_warning">The &TERMUX_APP_NAME; app is not installed or is disabled."</string>
77+
<string name="error_termux_app_package_context_not_accessible">The &TERMUX_APP_NAME; app (package context) is not accessible."</string>
78+
<string name="error_termux_prefix_dir_path_not_accessible">The &TERMUX_APP_NAME; app $PREFIX directory is not accessible by the %1$s app.
79+
This may be because you have not installed or setup &TERMUX_APP_NAME; app or
80+
&TERMUX_APP_NAME; app and %1$s app both have different APK signatures because you have managed to install both apps from different sources.
81+
It may also be because &TERMUX_APP_NAME; $PREFIX directory \"&TERMUX_PREFIX_DIR_PATH;\" does not exist or does not have read,
82+
write and execute permissions."</string>
83+
7484

7585

7686
<!-- Miscellaneous -->

0 commit comments

Comments
 (0)