Skip to content

Commit d3ddb21

Browse files
Warn users if Draw over other apps permission is missing
For android version >= 10(Q), a flash will be shown to users requesting them to grant the permission if they attempt to start a foreground terminal session command from background, like with the RUN_COMMAND intent. The flash will only be shown if "Plugin Error Notifications" toggle is enabled in settings.
1 parent 8e80e88 commit d3ddb21

File tree

3 files changed

+99
-1
lines changed

3 files changed

+99
-1
lines changed

app/src/main/java/com/termux/app/TermuxService.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.termux.app.terminal.TermuxSessionClientBase;
2929
import com.termux.app.utils.Logger;
3030
import com.termux.app.utils.NotificationUtils;
31+
import com.termux.app.utils.PermissionUtils;
3132
import com.termux.app.utils.ShellUtils;
3233
import com.termux.app.utils.TextDataUtils;
3334
import com.termux.models.ExecutionCommand;
@@ -513,7 +514,12 @@ private void handleSessionAction(int sessionAction, TerminalSession newTerminalS
513514

514515
/** Launch the {@link }TermuxActivity} to bring it to foreground. */
515516
private void startTermuxActivity() {
516-
TermuxActivity.startTermuxActivity(this);
517+
// For android >= 10, apps require Display over other apps permission to start foreground activities
518+
// from background (services). If it is not granted, then termux sessions that are started will
519+
// show in Termux notification but will not run until user manually clicks the notification.
520+
if(PermissionUtils.validateDisplayOverOtherAppsPermissionForPostAndroid10(this)) {
521+
TermuxActivity.startTermuxActivity(this);
522+
}
517523
}
518524

519525

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.termux.app.utils;
2+
3+
import android.app.Activity;
4+
import android.content.Context;
5+
import android.content.Intent;
6+
import android.content.pm.PackageManager;
7+
import android.net.Uri;
8+
import android.os.Build;
9+
import android.provider.Settings;
10+
11+
import androidx.core.content.ContextCompat;
12+
13+
import com.termux.R;
14+
import com.termux.app.TermuxConstants;
15+
import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
16+
17+
import java.util.Arrays;
18+
19+
public class PermissionUtils {
20+
21+
public static final int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE = 0;
22+
23+
private static final String LOG_TAG = "PluginUtils";
24+
25+
public static boolean checkPermissions(Context context, String[] permissions) {
26+
int result;
27+
28+
for (String p:permissions) {
29+
result = ContextCompat.checkSelfPermission(context,p);
30+
if (result != PackageManager.PERMISSION_GRANTED) {
31+
return false;
32+
}
33+
}
34+
return true;
35+
}
36+
37+
public static void askPermissions(Activity context, String[] permissions) {
38+
if(context == null || permissions == null) return;
39+
40+
int result;
41+
Logger.showToast(context, context.getString(R.string.message_sudo_please_grant_permissions), true);
42+
try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
43+
44+
for (String permission:permissions) {
45+
result = ContextCompat.checkSelfPermission(context, permission);
46+
if (result != PackageManager.PERMISSION_GRANTED) {
47+
Logger.logDebug(LOG_TAG, "Requesting Permissions: " + Arrays.toString(permissions));
48+
context.requestPermissions(new String[]{permission}, 0);
49+
}
50+
}
51+
}
52+
53+
54+
55+
public static boolean checkDisplayOverOtherAppsPermission(Context context) {
56+
boolean permissionGranted;
57+
58+
permissionGranted = Settings.canDrawOverlays(context);
59+
if (!permissionGranted) {
60+
Logger.logWarn(LOG_TAG, TermuxConstants.TERMUX_APP_NAME + " App does not have Display over other apps (SYSTEM_ALERT_WINDOW) permission");
61+
return false;
62+
} else {
63+
Logger.logDebug(LOG_TAG, TermuxConstants.TERMUX_APP_NAME + " App already has Display over other apps (SYSTEM_ALERT_WINDOW) permission");
64+
return true;
65+
}
66+
}
67+
68+
public static void askDisplayOverOtherAppsPermission(Activity context) {
69+
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context.getPackageName()));
70+
context.startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
71+
}
72+
73+
public static boolean validateDisplayOverOtherAppsPermissionForPostAndroid10(Context context) {
74+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return true;
75+
76+
if(!PermissionUtils.checkDisplayOverOtherAppsPermission(context)) {
77+
TermuxAppSharedPreferences preferences = new TermuxAppSharedPreferences(context);
78+
if(preferences.getPluginErrorNotificationsEnabled())
79+
Logger.showToast(context, context.getString(R.string.error_display_over_other_apps_permission_not_granted), true);
80+
return false;
81+
} else {
82+
return true;
83+
}
84+
}
85+
86+
}

app/src/main/res/values/strings.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@
128128

129129

130130

131+
<!-- Termux PermissionUtils -->
132+
<string name="message_sudo_please_grant_permissions">Please grant permissions on next screen</string>
133+
<string name="error_display_over_other_apps_permission_not_granted">&TERMUX_APP_NAME; requires \"Display over other apps\" permission to start terminal sessions from background on Android >= 10. Grants it from Settings -> Apps -> &TERMUX_APP_NAME; -> Advanced</string>
134+
135+
136+
131137
<!-- Termux File Receiver -->
132138
<string name="title_file_received">Save file in ~/downloads/</string>
133139
<string name="action_file_received_edit">Edit</string>

0 commit comments

Comments
 (0)