diff --git a/app/src/main/java/com/termux/app/TermuxActivity.java b/app/src/main/java/com/termux/app/TermuxActivity.java
index e586540289..5d872ee5b0 100644
--- a/app/src/main/java/com/termux/app/TermuxActivity.java
+++ b/app/src/main/java/com/termux/app/TermuxActivity.java
@@ -34,6 +34,7 @@
import com.termux.app.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY;
import com.termux.app.activities.HelpActivity;
import com.termux.app.activities.SettingsActivity;
+import com.termux.app.crash.CrashUtils;
import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
import com.termux.app.terminal.TermuxSessionsListViewController;
import com.termux.app.terminal.io.TerminalToolbarViewPager;
@@ -155,6 +156,10 @@ public void onCreate(Bundle savedInstanceState) {
Logger.logDebug(LOG_TAG, "onCreate");
+ // Check if a crash happened on last run of the app and show a
+ // notification with the crash details if it did
+ CrashUtils.notifyCrash(this, LOG_TAG);
+
// Load termux shared preferences and properties
mPreferences = new TermuxAppSharedPreferences(this);
mProperties = new TermuxSharedProperties(this);
diff --git a/app/src/main/java/com/termux/app/TermuxApplication.java b/app/src/main/java/com/termux/app/TermuxApplication.java
index 53d129eb2f..62713ac20f 100644
--- a/app/src/main/java/com/termux/app/TermuxApplication.java
+++ b/app/src/main/java/com/termux/app/TermuxApplication.java
@@ -2,6 +2,7 @@
import android.app.Application;
+import com.termux.app.crash.CrashHandler;
import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
import com.termux.app.utils.Logger;
@@ -10,10 +11,14 @@ public class TermuxApplication extends Application {
public void onCreate() {
super.onCreate();
- updateLogLevel();
+ // Set crash handler for the app
+ CrashHandler.setCrashHandler(this);
+
+ // Set log level for the app
+ setLogLevel();
}
- private void updateLogLevel() {
+ private void setLogLevel() {
// Load the log level from shared preferences and set it to the {@link Loggger.CURRENT_LOG_LEVEL}
TermuxAppSharedPreferences preferences = new TermuxAppSharedPreferences(getApplicationContext());
preferences.setLogLevel(null, preferences.getLogLevel());
diff --git a/app/src/main/java/com/termux/app/activities/ReportActivity.java b/app/src/main/java/com/termux/app/activities/ReportActivity.java
index ae3b5db03a..57a4ae3c03 100644
--- a/app/src/main/java/com/termux/app/activities/ReportActivity.java
+++ b/app/src/main/java/com/termux/app/activities/ReportActivity.java
@@ -18,7 +18,6 @@
import com.termux.app.TermuxConstants;
import com.termux.app.utils.MarkdownUtils;
import com.termux.app.utils.ShareUtils;
-import com.termux.app.utils.TermuxUtils;
import com.termux.app.models.ReportInfo;
import org.commonmark.node.FencedCodeBlock;
@@ -32,6 +31,7 @@ public class ReportActivity extends AppCompatActivity {
private static final String EXTRA_REPORT_INFO = "report_info";
ReportInfo mReportInfo;
+ String mReportMarkdownString;
String mReportActivityMarkdownString;
@Override
@@ -131,11 +131,11 @@ public void onBackPressed() {
public boolean onOptionsItemSelected(final MenuItem item) {
int id = item.getItemId();
if (id == R.id.menu_item_share_report) {
- if (mReportInfo != null)
- ShareUtils.shareText(this, getString(R.string.title_report_text), mReportActivityMarkdownString);
+ if (mReportMarkdownString != null)
+ ShareUtils.shareText(this, getString(R.string.title_report_text), mReportMarkdownString);
} else if (id == R.id.menu_item_copy_report) {
- if (mReportInfo != null)
- ShareUtils.copyTextToClipboard(this, mReportActivityMarkdownString, null);
+ if (mReportMarkdownString != null)
+ ShareUtils.copyTextToClipboard(this, mReportMarkdownString, null);
}
return false;
@@ -145,7 +145,16 @@ public boolean onOptionsItemSelected(final MenuItem item) {
* Generate the markdown {@link String} to be shown in {@link ReportActivity}.
*/
private void generateReportActivityMarkdownString() {
- mReportActivityMarkdownString = ReportInfo.getReportInfoMarkdownString(this, mReportInfo);
+ mReportMarkdownString = ReportInfo.getReportInfoMarkdownString(mReportInfo);
+
+ mReportActivityMarkdownString = "";
+ if(mReportInfo.reportStringPrefix != null)
+ mReportActivityMarkdownString += mReportInfo.reportStringPrefix;
+
+ mReportActivityMarkdownString += mReportMarkdownString;
+
+ if(mReportInfo.reportStringSuffix != null)
+ mReportActivityMarkdownString += mReportInfo.reportStringSuffix;
}
diff --git a/app/src/main/java/com/termux/app/crash/CrashHandler.java b/app/src/main/java/com/termux/app/crash/CrashHandler.java
new file mode 100644
index 0000000000..7de2f1aa35
--- /dev/null
+++ b/app/src/main/java/com/termux/app/crash/CrashHandler.java
@@ -0,0 +1,34 @@
+package com.termux.app.crash;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Catches uncaught exceptions and logs them.
+ */
+public class CrashHandler implements Thread.UncaughtExceptionHandler {
+
+ private final Context context;
+ private final Thread.UncaughtExceptionHandler defaultUEH;
+
+ private CrashHandler(final Context context) {
+ this.context = context;
+ this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
+ }
+
+ public void uncaughtException(@NonNull Thread thread, @NonNull Throwable throwable) {
+ CrashUtils.logCrash(context,thread, throwable);
+ defaultUEH.uncaughtException(thread, throwable);
+ }
+
+ /**
+ * Set default uncaught crash handler of current thread to {@link CrashHandler}.
+ */
+ public static void setCrashHandler(final Context context) {
+ if(!(Thread.getDefaultUncaughtExceptionHandler() instanceof CrashHandler)) {
+ Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(context));
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/termux/app/crash/CrashUtils.java b/app/src/main/java/com/termux/app/crash/CrashUtils.java
new file mode 100644
index 0000000000..c4d900d857
--- /dev/null
+++ b/app/src/main/java/com/termux/app/crash/CrashUtils.java
@@ -0,0 +1,189 @@
+package com.termux.app.crash;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.annotation.Nullable;
+
+import com.termux.R;
+import com.termux.app.activities.ReportActivity;
+import com.termux.app.file.FileUtils;
+import com.termux.app.models.ReportInfo;
+import com.termux.app.models.UserAction;
+import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
+import com.termux.app.settings.preferences.TermuxPreferenceConstants;
+import com.termux.app.utils.DataUtils;
+import com.termux.app.utils.Logger;
+import com.termux.app.utils.MarkdownUtils;
+import com.termux.app.utils.NotificationUtils;
+import com.termux.app.utils.TermuxUtils;
+
+import com.termux.app.TermuxConstants;
+
+import java.nio.charset.Charset;
+
+public class CrashUtils {
+
+ private static final String NOTIFICATION_CHANNEL_ID_CRASH_REPORT_ERRORS = "termux_crash_reports_notification_channel";
+ private static final String NOTIFICATION_CHANNEL_NAME_CRASH_REPORT_ERRORS = TermuxConstants.TERMUX_APP_NAME + " Crash Reports";
+
+ private static final String LOG_TAG = "CrashUtils";
+
+ /**
+ * Log a crash in the crash log file at
+ * {@link TermuxConstants#TERMUX_CRASH_LOG_FILE_PATH}.
+ *
+ * @param context The {@link Context} for operations.
+ * @param thread The {@link Thread} in which the crash happened.
+ * @param thread The {@link Throwable} thrown for the crash.
+ */
+ public static void logCrash(final Context context, final Thread thread, final Throwable throwable) {
+
+ StringBuilder reportString = new StringBuilder();
+
+ reportString.append("## Crash Details\n");
+ reportString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Crash Thread", thread.toString(), "-"));
+ reportString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Crash Timestamp", TermuxUtils.getCurrentTimeStamp(), "-"));
+
+ reportString.append("\n\n").append(Logger.getStackTracesMarkdownString("Stacktrace", Logger.getStackTraceStringArray(throwable)));
+ reportString.append("\n\n").append(TermuxUtils.getAppInfoMarkdownString(context, true));
+ reportString.append("\n\n").append(TermuxUtils.getDeviceInfoMarkdownString(context));
+
+ // Log report string to logcat
+ Logger.logError(reportString.toString());
+
+ // Write report string to crash log file
+ String errmsg = FileUtils.writeStringToFile(context, "crash log", TermuxConstants.TERMUX_CRASH_LOG_FILE_PATH, Charset.defaultCharset(), reportString.toString(), false);
+ if(errmsg != null) {
+ Logger.logError(LOG_TAG, errmsg);
+ }
+ }
+
+ /**
+ * Notify the user of a previous app crash by reading the crash info from the crash log file at
+ * {@link TermuxConstants#TERMUX_CRASH_LOG_FILE_PATH}.
+ *
+ * If the crash log file exists and is not empty and
+ * {@link TermuxPreferenceConstants.TERMUX_APP#KEY_CRASH_REPORT_NOTIFICATIONS_ENABLED} is
+ * enabled, then a notification will be shown for the crash on the
+ * {@link #NOTIFICATION_CHANNEL_NAME_CRASH_REPORT_ERRORS} channel, otherwise nothing will be done.
+ *
+ * After reading from the crash log file, it will be moved to {@link TermuxConstants#TERMUX_CRASH_LOG_BACKUP_FILE_PATH}.
+ *
+ * @param context The {@link Context} for operations.
+ * @param logTagParam The log tag to use for logging.
+ */
+ public static void notifyCrash(final Context context, final String logTagParam) {
+ if(context == null) return;
+
+
+ TermuxAppSharedPreferences preferences = new TermuxAppSharedPreferences(context);
+ // If user has disabled notifications for crashes
+ if (!preferences.getCrashReportNotificationsEnabled())
+ return;
+
+ new Thread() {
+ @Override
+ public void run() {
+ String logTag = DataUtils.getDefaultIfNull(logTagParam, LOG_TAG);
+
+ if(!FileUtils.regularFileExists(TermuxConstants.TERMUX_CRASH_LOG_FILE_PATH, false))
+ return;
+
+ String errmsg;
+ StringBuilder reportStringBuilder = new StringBuilder();
+
+ // Read report string from crash log file
+ errmsg = FileUtils.readStringFromFile(context, "crash log", TermuxConstants.TERMUX_CRASH_LOG_FILE_PATH, Charset.defaultCharset(), reportStringBuilder, false);
+ if(errmsg != null) {
+ Logger.logError(logTag, errmsg);
+ return;
+ }
+
+ // Move crash log file to backup location if it exists
+ FileUtils.moveRegularFile(context, "crash log", TermuxConstants.TERMUX_CRASH_LOG_FILE_PATH, TermuxConstants.TERMUX_CRASH_LOG_BACKUP_FILE_PATH, true);
+ if(errmsg != null) {
+ Logger.logError(logTag, errmsg);
+ }
+
+ String reportString = reportStringBuilder.toString();
+
+ if(reportString == null || reportString.isEmpty())
+ return;
+
+ // Send a notification to show the crash log which when clicked will open the {@link ReportActivity}
+ // to show the details of the crash
+ String title = TermuxConstants.TERMUX_APP_NAME + " Crash Report";
+
+ Logger.logDebug(logTag, "The crash log file at \"" + TermuxConstants.TERMUX_CRASH_LOG_FILE_PATH + "\" found. Sending \"" + title + "\" notification.");
+
+ Intent notificationIntent = ReportActivity.newInstance(context, new ReportInfo(UserAction.CRASH_REPORT, logTag, title, null, reportString, "\n\n" + TermuxUtils.getReportIssueMarkdownString(context), true));
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ // Setup the notification channel if not already set up
+ setupCrashReportsNotificationChannel(context);
+
+ // Build the notification
+ Notification.Builder builder = getCrashReportsNotificationBuilder(context, title, null, null, pendingIntent, NotificationUtils.NOTIFICATION_MODE_VIBRATE);
+ if(builder == null) return;
+
+ // Send the notification
+ int nextNotificationId = NotificationUtils.getNextNotificationId(context);
+ NotificationManager notificationManager = NotificationUtils.getNotificationManager(context);
+ if(notificationManager != null)
+ notificationManager.notify(nextNotificationId, builder.build());
+ }
+ }.start();
+ }
+
+ /**
+ * Get {@link Notification.Builder} for {@link #NOTIFICATION_CHANNEL_ID_CRASH_REPORT_ERRORS}
+ * and {@link #NOTIFICATION_CHANNEL_NAME_CRASH_REPORT_ERRORS}.
+ *
+ * @param context The {@link Context} for operations.
+ * @param title The title for the notification.
+ * @param notifiationText The second line text of the notification.
+ * @param notificationBigText The full text of the notification that may optionally be styled.
+ * @param pendingIntent The {@link PendingIntent} which should be sent when notification is clicked.
+ * @param notificationMode The notification mode. It must be one of {@code NotificationUtils.NOTIFICATION_MODE_*}.
+ * @return Returns the {@link Notification.Builder}.
+ */
+ @Nullable
+ public static Notification.Builder getCrashReportsNotificationBuilder(final Context context, final CharSequence title, final CharSequence notifiationText, final CharSequence notificationBigText, final PendingIntent pendingIntent, final int notificationMode) {
+
+ Notification.Builder builder = NotificationUtils.geNotificationBuilder(context,
+ NOTIFICATION_CHANNEL_ID_CRASH_REPORT_ERRORS, Notification.PRIORITY_HIGH,
+ title, notifiationText, notificationBigText, pendingIntent, notificationMode);
+
+ if(builder == null) return null;
+
+ // Enable timestamp
+ builder.setShowWhen(true);
+
+ // Set notification icon
+ builder.setSmallIcon(R.drawable.ic_error_notification);
+
+ // Set background color for small notification icon
+ builder.setColor(0xFF607D8B);
+
+ // Dismiss on click
+ builder.setAutoCancel(true);
+
+ return builder;
+ }
+
+ /**
+ * Setup the notification channel for {@link #NOTIFICATION_CHANNEL_ID_CRASH_REPORT_ERRORS} and
+ * {@link #NOTIFICATION_CHANNEL_NAME_CRASH_REPORT_ERRORS}.
+ *
+ * @param context The {@link Context} for operations.
+ */
+ public static void setupCrashReportsNotificationChannel(final Context context) {
+ NotificationUtils.setupNotificationChannel(context, NOTIFICATION_CHANNEL_ID_CRASH_REPORT_ERRORS,
+ NOTIFICATION_CHANNEL_NAME_CRASH_REPORT_ERRORS, NotificationManager.IMPORTANCE_HIGH);
+ }
+
+}
diff --git a/app/src/main/java/com/termux/app/models/ExecutionCommand.java b/app/src/main/java/com/termux/app/models/ExecutionCommand.java
index 2de23ffc9b..aa83d74722 100644
--- a/app/src/main/java/com/termux/app/models/ExecutionCommand.java
+++ b/app/src/main/java/com/termux/app/models/ExecutionCommand.java
@@ -415,7 +415,7 @@ public String geStackTracesLogString() {
}
public String geStackTracesMarkdownString() {
- return Logger.getStackTracesMarkdownString("StackTraces:", Logger.getStackTraceStringArray(throwableList));
+ return Logger.getStackTracesMarkdownString("StackTraces", Logger.getStackTraceStringArray(throwableList));
}
diff --git a/app/src/main/java/com/termux/app/models/ReportInfo.java b/app/src/main/java/com/termux/app/models/ReportInfo.java
index 7832d64602..cd12e5ed55 100644
--- a/app/src/main/java/com/termux/app/models/ReportInfo.java
+++ b/app/src/main/java/com/termux/app/models/ReportInfo.java
@@ -1,7 +1,5 @@
package com.termux.app.models;
-import android.content.Context;
-
import com.termux.app.utils.MarkdownUtils;
import com.termux.app.utils.TermuxUtils;
@@ -15,49 +13,51 @@ public class ReportInfo implements Serializable {
public String sender;
/** The report title. */
public String reportTitle;
- /** The markdown text for the report. */
+ /** The markdown report text prefix. Will not be part of copy and share operations, etc. */
+ public String reportStringPrefix;
+ /** The markdown report text. */
public String reportString;
+ /** The markdown report text suffix. Will not be part of copy and share operations, etc. */
+ public String reportStringSuffix;
/** If set to {@code true}, then report, app and device info will be added to the report when
* markdown is generated.
*/
public boolean addReportInfoToMarkdown;
/** The timestamp for the report. */
- public String creationTimestammp;
+ public String reportTimestammp;
- public ReportInfo(UserAction userAction, String sender, String reportTitle, String reportString, boolean addReportInfoToMarkdown) {
+ public ReportInfo(UserAction userAction, String sender, String reportTitle, String reportStringPrefix, String reportString, String reportStringSuffix, boolean addReportInfoToMarkdown) {
this.userAction = userAction;
this.sender = sender;
this.reportTitle = reportTitle;
+ this.reportStringPrefix = reportStringPrefix;
this.reportString = reportString;
+ this.reportStringSuffix = reportStringSuffix;
this.addReportInfoToMarkdown = addReportInfoToMarkdown;
- this.creationTimestammp = TermuxUtils.getCurrentTimeStamp();
+ this.reportTimestammp = TermuxUtils.getCurrentTimeStamp();
}
/**
* Get a markdown {@link String} for {@link ReportInfo}.
*
- * @param currentPackageContext The context of current package.
* @param reportInfo The {@link ReportInfo} to convert.
* @return Returns the markdown {@link String}.
*/
- public static String getReportInfoMarkdownString(final Context currentPackageContext, final ReportInfo reportInfo) {
+ public static String getReportInfoMarkdownString(final ReportInfo reportInfo) {
if (reportInfo == null) return "null";
StringBuilder markdownString = new StringBuilder();
- markdownString.append(reportInfo.reportString);
-
if(reportInfo.addReportInfoToMarkdown) {
markdownString.append("## Report Info\n\n");
markdownString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("User Action", reportInfo.userAction, "-"));
markdownString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Sender", reportInfo.sender, "-"));
- markdownString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Creation Timestamp", reportInfo.creationTimestammp, "-"));
- markdownString.append("\n##\n");
-
- markdownString.append("\n\n").append(TermuxUtils.getAppInfoMarkdownString(currentPackageContext, true));
- markdownString.append("\n\n").append(TermuxUtils.getDeviceInfoMarkdownString(currentPackageContext));
+ markdownString.append("\n").append(MarkdownUtils.getSingleLineMarkdownStringEntry("Report Timestamp", reportInfo.reportTimestammp, "-"));
+ markdownString.append("\n##\n\n");
}
+ markdownString.append(reportInfo.reportString);
+
return markdownString.toString();
}
diff --git a/app/src/main/java/com/termux/app/models/UserAction.java b/app/src/main/java/com/termux/app/models/UserAction.java
index 611304ea2f..9a27992fc4 100644
--- a/app/src/main/java/com/termux/app/models/UserAction.java
+++ b/app/src/main/java/com/termux/app/models/UserAction.java
@@ -2,7 +2,8 @@
public enum UserAction {
- PLUGIN_EXECUTION_COMMAND("plugin execution command");
+ PLUGIN_EXECUTION_COMMAND("plugin execution command"),
+ CRASH_REPORT("crash report");
private final String name;
diff --git a/app/src/main/java/com/termux/app/utils/MarkdownUtils.java b/app/src/main/java/com/termux/app/utils/MarkdownUtils.java
index 712b01b232..5d40a20393 100644
--- a/app/src/main/java/com/termux/app/utils/MarkdownUtils.java
+++ b/app/src/main/java/com/termux/app/utils/MarkdownUtils.java
@@ -117,6 +117,13 @@ public static String getMultiLineMarkdownStringEntry(String label, Object object
return "**" + label + "**: " + def + "\n";
}
+ public static String getLinkMarkdownString(String label, Object object) {
+ if (object != null)
+ return "[" + label + "](" + object + ")";
+ else
+ return label;
+ }
+
/** Check following for more info:
* https://github.com/noties/Markwon/tree/v4.6.2/app-sample
diff --git a/app/src/main/java/com/termux/app/utils/PluginUtils.java b/app/src/main/java/com/termux/app/utils/PluginUtils.java
index 4c9bc136a4..f95dd35a30 100644
--- a/app/src/main/java/com/termux/app/utils/PluginUtils.java
+++ b/app/src/main/java/com/termux/app/utils/PluginUtils.java
@@ -149,7 +149,13 @@ public static void processPluginExecutionCommandError(final Context context, Str
// to show the details of the error
String title = TermuxConstants.TERMUX_APP_NAME + " Plugin Execution Command Error";
- Intent notificationIntent = ReportActivity.newInstance(context, new ReportInfo(UserAction.PLUGIN_EXECUTION_COMMAND, logTag, title, ExecutionCommand.getExecutionCommandMarkdownString(executionCommand), true));
+ StringBuilder reportString = new StringBuilder();
+
+ reportString.append(ExecutionCommand.getExecutionCommandMarkdownString(executionCommand));
+ reportString.append("\n\n").append(TermuxUtils.getAppInfoMarkdownString(context, true));
+ reportString.append("\n\n").append(TermuxUtils.getDeviceInfoMarkdownString(context));
+
+ Intent notificationIntent = ReportActivity.newInstance(context, new ReportInfo(UserAction.PLUGIN_EXECUTION_COMMAND, logTag, title, null, reportString.toString(), null,true));
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
// Setup the notification channel if not already set up
diff --git a/app/src/main/java/com/termux/app/utils/TermuxUtils.java b/app/src/main/java/com/termux/app/utils/TermuxUtils.java
index 9640b63fed..79ead17aea 100644
--- a/app/src/main/java/com/termux/app/utils/TermuxUtils.java
+++ b/app/src/main/java/com/termux/app/utils/TermuxUtils.java
@@ -11,6 +11,7 @@
import com.google.common.base.Joiner;
+import com.termux.R;
import com.termux.app.TermuxConstants;
import java.io.BufferedReader;
@@ -238,6 +239,49 @@ public static String getDeviceInfoMarkdownString(@NonNull final Context context)
return markdownString.toString();
}
+ /**
+ * Get a markdown {@link String} for reporting an issue.
+ *
+ * @param context The context for operations.
+ * @return Returns the markdown {@link String}.
+ */
+ public static String getReportIssueMarkdownString(@NonNull final Context context) {
+ if (context == null) return "null";
+
+ StringBuilder markdownString = new StringBuilder();
+
+ markdownString.append("## Report Issue");
+
+ markdownString.append("\n\n").append(context.getString(R.string.msg_report_issue)).append("\n");
+
+ //markdownString.append("\n\n### Email\n");
+ //markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_SUPPORT_EMAIL, TermuxConstants.TERMUX_SUPPORT_EMAIL_MAILTO_URL)).append(" ");
+
+ markdownString.append("\n\n### Reddit\n");
+ markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_REDDIT_SUBREDDIT, TermuxConstants.TERMUX_REDDIT_SUBREDDIT_URL)).append(" ");
+
+ markdownString.append("\n\n### Github Issues for Termux apps\n");
+ markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_APP_NAME, TermuxConstants.TERMUX_GITHUB_ISSUES_REPO_URL)).append(" ");
+ markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_API_APP_NAME, TermuxConstants.TERMUX_API_GITHUB_ISSUES_REPO_URL)).append(" ");
+ markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_BOOT_APP_NAME, TermuxConstants.TERMUX_BOOT_GITHUB_ISSUES_REPO_URL)).append(" ");
+ markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_FLOAT_APP_NAME, TermuxConstants.TERMUX_FLOAT_GITHUB_ISSUES_REPO_URL)).append(" ");
+ markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_STYLING_APP_NAME, TermuxConstants.TERMUX_STYLING_GITHUB_ISSUES_REPO_URL)).append(" ");
+ markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_TASKER_APP_NAME, TermuxConstants.TERMUX_TASKER_GITHUB_ISSUES_REPO_URL)).append(" ");
+ markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_WIDGET_APP_NAME, TermuxConstants.TERMUX_WIDGET_GITHUB_ISSUES_REPO_URL)).append(" ");
+
+ markdownString.append("\n\n### Github Issues for Termux packages\n");
+ markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_PACKAGES_GITHUB_REPO_NAME, TermuxConstants.TERMUX_PACKAGES_GITHUB_ISSUES_REPO_URL)).append(" ");
+ markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_GAME_PACKAGES_GITHUB_REPO_NAME, TermuxConstants.TERMUX_GAME_PACKAGES_GITHUB_ISSUES_REPO_URL)).append(" ");
+ markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_SCIENCE_PACKAGES_GITHUB_REPO_NAME, TermuxConstants.TERMUX_SCIENCE_PACKAGES_GITHUB_ISSUES_REPO_URL)).append(" ");
+ markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_ROOT_PACKAGES_GITHUB_REPO_NAME, TermuxConstants.TERMUX_ROOT_PACKAGES_GITHUB_ISSUES_REPO_URL)).append(" ");
+ markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_UNSTABLE_PACKAGES_GITHUB_REPO_NAME, TermuxConstants.TERMUX_UNSTABLE_PACKAGES_GITHUB_ISSUES_REPO_URL)).append(" ");
+ markdownString.append("\n").append(MarkdownUtils.getLinkMarkdownString(TermuxConstants.TERMUX_X11_PACKAGES_GITHUB_REPO_NAME, TermuxConstants.TERMUX_X11_PACKAGES_GITHUB_ISSUES_REPO_URL)).append(" ");
+
+ markdownString.append("\n##\n");
+
+ return markdownString.toString();
+ }
+
public static Properties getSystemProperties() {
Properties systemProperties = new Properties();
@@ -311,7 +355,7 @@ private static String getPropertyMarkdown(String label, Object value) {
public static String getCurrentTimeStamp() {
@SuppressLint("SimpleDateFormat")
- final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+ final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
return df.format(new Date());
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c3a127581c..ca6a00ae73 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -158,6 +158,8 @@
Share With
Report Text
+ If you think this report should be reported, then copy its text from the options menu (3-dots on top right) and post an issue on one of the following links at which the report belongs at.
+