这是indexloc提供的服务,不要输入任何密码
Skip to content

Commit 351934a

Browse files
Added|Fixed!: Added support to save reports to files and fixed large reports generating TransactionTooLargeException
If `ReportActivity` was started with a large report, i.e a few hundred `KB`, like for terminal transcript or other command output, the activity start would fail. To solve the issue, if the serialized size of the ReportInfo info object is above `DataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES` (`100KB`), it will be saved to a file in a cache directory `/data/data/com.termux/cache/report_activity` as a serialized object and loaded when activity is started. The file will be automatically deleted when activity is destroyed (`Activity.onDetroy()`) or when notification that would have started the activity is deleted (`Notification.deleteIntent`). In case, these two didn't happen, then on `TermuxActivity` startup, a thread will be started to delete files older than `14` days so that unneeded left over files are deleted. If user tries to open plugin error or crash report notifications after 14 days, they will get `ReportInfo` file not found errors, assuming `TermuxActivity` was started to run the cleanup routine. Now these large reports can't be copied or shared with other apps since that would again result in `TransactionTooLargeException` exceptions and `ShareUtils` automatically truncates the data (now from end) to `100KB` length so that the exception doesn't occur. So now a `Save To File` option has been added in context menu (3 dots on top right) of `ReportActivity` so that large or small reports can be saved to a file if needed. They will be save in root of `/storage/emulated/0` or whatever is the default public external storage directory. The filename would depend on type of report. The storage permissions will be asked if missing. On android `11`, if you get permission denied errors even after granting permission, disable permission and grant it again. To solve privacy issues of report being saved to public storage since it may contain private info, an option for custom path will be added in future. The default directory is public storage instead of termux home since its easily accessible via all file managers or from pc. Instructing amateur users to get files via `SAF` from termux home is not something I wanna take on. Another issue is that `ReportActivity` itself may not be able to show the entire report since Android may throw `OutOfMemoryError` exceptions if device memory is low. To solve this issue, `ReportActivity` will truncate the report to `1MB` from end that's shown to the user. It will add a header showing that report was truncated. To view the full report, the user will have to use the `Save To File` option and view the file in an external app or on pc that supports opening large files. The `QuickEdit` app on Android has been a reliable one in my experience that supports large files, although it has max row/column limits too at a few hundred thousand, depending on android version. Despite all this, `OutOfMemoryError` exceptions could still be thrown if you try to view too large a report, like a few MB, since original report + the truncated report is still held in memory by the app and will consume `2-3` times memory when saving. It's fun coding for android, right? The terminal transcript will not be truncated anymore that's generated via `Report Issue` option in terminal. The `ShareUtils.copyTextToClipboard()` will truncate data now automatically, apparently all phones don't do it automatically and exception is raised. The `ShareUtils.saveTextToFile()` has been added that will automatically ask for storage permissions if missing. The `ReportInfo` now expects a `reportSaveFileLabel` and `reportSaveFilePath` arguments so that `ReportActivity` can use them to know where to save the file if users selects `Save To File` option. The `ReportActivityBroadcastReceiver` must now be registered in `AndroidManifest.xml` if you are using `ReportActivity` in your app. Check `ReportActivity` javadoc for details. Moreover, an incremental call to `ReportActivity.deleteReportInfoFilesOlderThanXDays()` must also be made.
1 parent e7fc60a commit 351934a

File tree

12 files changed

+470
-59
lines changed

12 files changed

+470
-59
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@
168168

169169
<receiver android:name=".app.TermuxOpenReceiver" />
170170

171+
<receiver android:name=".shared.activities.ReportActivity$ReportActivityBroadcastReceiver" android:exported="false" />
172+
171173
<provider
172174
android:name=".app.TermuxOpenReceiver$ContentProvider"
173175
android:authorities="${TERMUX_PACKAGE_NAME}.files"

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
import com.termux.R;
3535
import com.termux.app.terminal.TermuxActivityRootView;
36+
import com.termux.shared.activities.ReportActivity;
3637
import com.termux.shared.packages.PermissionUtils;
3738
import com.termux.shared.termux.TermuxConstants;
3839
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY;
@@ -182,6 +183,9 @@ public void onCreate(Bundle savedInstanceState) {
182183
// notification with the crash details if it did
183184
CrashUtils.notifyAppCrashOnLastRun(this, LOG_TAG);
184185

186+
// Delete ReportInfo serialized object files from cache older than 14 days
187+
ReportActivity.deleteReportInfoFilesOlderThanXDays(this, 14, false);
188+
185189
// Load termux shared properties
186190
mProperties = new TermuxAppSharedProperties(this);
187191

app/src/main/java/com/termux/app/activities/SettingsActivity.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import android.content.Context;
44
import android.os.Bundle;
5+
import android.os.Environment;
56

67
import androidx.annotation.NonNull;
78
import androidx.appcompat.app.ActionBar;
@@ -11,6 +12,7 @@
1112

1213
import com.termux.R;
1314
import com.termux.shared.activities.ReportActivity;
15+
import com.termux.shared.file.FileUtils;
1416
import com.termux.shared.models.ReportInfo;
1517
import com.termux.app.models.UserAction;
1618
import com.termux.shared.interact.ShareUtils;
@@ -86,7 +88,13 @@ public void run() {
8688
aboutString.append("\n\n").append(AndroidUtils.getDeviceInfoMarkdownString(context));
8789
aboutString.append("\n\n").append(TermuxUtils.getImportantLinksMarkdownString(context));
8890

89-
ReportActivity.startReportActivity(context, new ReportInfo(UserAction.ABOUT.getName(), TermuxConstants.TERMUX_APP.TERMUX_SETTINGS_ACTIVITY_NAME, title, null, aboutString.toString(), null, false));
91+
String userActionName = UserAction.ABOUT.getName();
92+
ReportActivity.startReportActivity(context, new ReportInfo(userActionName,
93+
TermuxConstants.TERMUX_APP.TERMUX_SETTINGS_ACTIVITY_NAME, title, null,
94+
aboutString.toString(), null, false,
95+
userActionName,
96+
Environment.getExternalStorageDirectory() + "/" +
97+
FileUtils.sanitizeFileName(TermuxConstants.TERMUX_APP_NAME + "-" + userActionName + ".log", true, true)));
9098
}
9199
}.start();
92100

app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import android.content.Intent;
1010
import android.media.AudioManager;
1111
import android.net.Uri;
12+
import android.os.Environment;
1213
import android.text.TextUtils;
1314
import android.view.Gravity;
1415
import android.view.InputDevice;
@@ -22,6 +23,7 @@
2223
import com.termux.R;
2324
import com.termux.app.TermuxActivity;
2425
import com.termux.shared.data.UrlUtils;
26+
import com.termux.shared.file.FileUtils;
2527
import com.termux.shared.shell.ShellUtils;
2628
import com.termux.shared.terminal.TermuxTerminalViewClientBase;
2729
import com.termux.shared.termux.AndroidUtils;
@@ -668,15 +670,13 @@ public void reportIssueFromTranscript() {
668670
new Thread() {
669671
@Override
670672
public void run() {
671-
672-
String transcriptTextTruncated = DataUtils.getTruncatedCommandOutput(transcriptText, DataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES, false, true, false).trim();
673-
674673
StringBuilder reportString = new StringBuilder();
675674

676675
String title = TermuxConstants.TERMUX_APP_NAME + " Report Issue";
677676

678677
reportString.append("## Transcript\n");
679-
reportString.append("\n").append(MarkdownUtils.getMarkdownCodeForString(transcriptTextTruncated, true));
678+
reportString.append("\n").append(MarkdownUtils.getMarkdownCodeForString(transcriptText, true));
679+
reportString.append("\n##\n");
680680

681681
reportString.append("\n\n").append(TermuxUtils.getAppInfoMarkdownString(mActivity, true));
682682
reportString.append("\n\n").append(AndroidUtils.getDeviceInfoMarkdownString(mActivity));
@@ -685,7 +685,15 @@ public void run() {
685685
if (termuxAptInfo != null)
686686
reportString.append("\n\n").append(termuxAptInfo);
687687

688-
ReportActivity.startReportActivity(mActivity, new ReportInfo(UserAction.REPORT_ISSUE_FROM_TRANSCRIPT.getName(), TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY_NAME, title, null, reportString.toString(), "\n\n" + TermuxUtils.getReportIssueMarkdownString(mActivity), false));
688+
String userActionName = UserAction.REPORT_ISSUE_FROM_TRANSCRIPT.getName();
689+
ReportActivity.startReportActivity(mActivity,
690+
new ReportInfo(userActionName,
691+
TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY_NAME, title, null,
692+
reportString.toString(), "\n\n" + TermuxUtils.getReportIssueMarkdownString(mActivity),
693+
false,
694+
userActionName,
695+
Environment.getExternalStorageDirectory() + "/" +
696+
FileUtils.sanitizeFileName(TermuxConstants.TERMUX_APP_NAME + "-" + userActionName + ".log", true, true)));
689697
}
690698
}.start();
691699
}

app/src/main/java/com/termux/app/utils/CrashUtils.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import android.app.NotificationManager;
55
import android.app.PendingIntent;
66
import android.content.Context;
7-
import android.content.Intent;
7+
import android.os.Environment;
88

99
import androidx.annotation.Nullable;
1010

@@ -131,12 +131,23 @@ public static void sendCrashReportNotification(final Context context, String log
131131
reportString.append("\n\n").append(AndroidUtils.getDeviceInfoMarkdownString(context));
132132
}
133133

134-
Intent notificationIntent = ReportActivity.newInstance(context, new ReportInfo(UserAction.CRASH_REPORT.getName(), logTag, title, null, reportString.toString(), "\n\n" + TermuxUtils.getReportIssueMarkdownString(context), true));
134+
String userActionName = UserAction.CRASH_REPORT.getName();
135+
ReportActivity.NewInstanceResult result = ReportActivity.newInstance(context, new ReportInfo(userActionName,
136+
logTag, title, null, reportString.toString(),
137+
"\n\n" + TermuxUtils.getReportIssueMarkdownString(context), true,
138+
userActionName,
139+
Environment.getExternalStorageDirectory() + "/" +
140+
FileUtils.sanitizeFileName(TermuxConstants.TERMUX_APP_NAME + "-" + userActionName + ".log", true, true)));
141+
if (result.contentIntent == null) return;
135142

136143
// Must ensure result code for PendingIntents and id for notification are unique otherwise will override previous
137144
int nextNotificationId = TermuxNotificationUtils.getNextNotificationId(context);
138-
PendingIntent contentIntent = PendingIntent.getActivity(context, nextNotificationId, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
145+
146+
PendingIntent contentIntent = PendingIntent.getActivity(context, nextNotificationId, result.contentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
147+
139148
PendingIntent deleteIntent = null;
149+
if (result.deleteIntent != null)
150+
deleteIntent = PendingIntent.getBroadcast(context, nextNotificationId, result.deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT);
140151

141152
// Setup the notification channel if not already set up
142153
setupCrashReportsNotificationChannel(context);

app/src/main/java/com/termux/app/utils/PluginUtils.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
import android.app.NotificationManager;
55
import android.app.PendingIntent;
66
import android.content.Context;
7-
import android.content.Intent;
7+
import android.os.Environment;
88

99
import androidx.annotation.Nullable;
1010

1111
import com.termux.R;
1212
import com.termux.shared.activities.ReportActivity;
13+
import com.termux.shared.file.FileUtils;
1314
import com.termux.shared.file.TermuxFileUtils;
1415
import com.termux.shared.models.ResultConfig;
1516
import com.termux.shared.models.ResultData;
@@ -219,12 +220,23 @@ public static void sendPluginCommandErrorNotification(Context context, String lo
219220
reportString.append("\n\n").append(TermuxUtils.getAppInfoMarkdownString(context, true));
220221
reportString.append("\n\n").append(AndroidUtils.getDeviceInfoMarkdownString(context));
221222

222-
Intent notificationIntent = ReportActivity.newInstance(context, new ReportInfo(UserAction.PLUGIN_EXECUTION_COMMAND.getName(), logTag, title, null, reportString.toString(), null,true));
223+
String userActionName = UserAction.PLUGIN_EXECUTION_COMMAND.getName();
224+
ReportActivity.NewInstanceResult result = ReportActivity.newInstance(context,
225+
new ReportInfo(userActionName, logTag, title, null,
226+
reportString.toString(), null,true,
227+
userActionName,
228+
Environment.getExternalStorageDirectory() + "/" +
229+
FileUtils.sanitizeFileName(TermuxConstants.TERMUX_APP_NAME + "-" + userActionName + ".log", true, true)));
230+
if (result.contentIntent == null) return;
223231

224232
// Must ensure result code for PendingIntents and id for notification are unique otherwise will override previous
225233
int nextNotificationId = TermuxNotificationUtils.getNextNotificationId(context);
226-
PendingIntent contentIntent = PendingIntent.getActivity(context, nextNotificationId, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
234+
235+
PendingIntent contentIntent = PendingIntent.getActivity(context, nextNotificationId, result.contentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
236+
227237
PendingIntent deleteIntent = null;
238+
if (result.deleteIntent != null)
239+
deleteIntent = PendingIntent.getBroadcast(context, nextNotificationId, result.deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT);
228240

229241
// Setup the notification channel if not already set up
230242
setupPluginCommandErrorsNotificationChannel(context);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878

7979
<string name="action_report_issue">Report Issue</string>
8080
<string name="msg_generating_report">Generating Report</string>
81+
<string name="msg_add_termux_debug_info">Add termux debug info to report?</string>
8182

8283
<string name="error_styling_not_installed">The &TERMUX_STYLING_APP_NAME; Plugin App is not installed.</string>
8384
<string name="action_styling_install">Install</string>

0 commit comments

Comments
 (0)