diff --git a/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java index 20724c02b34..9cba2fa6f9f 100644 --- a/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java +++ b/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java @@ -2,6 +2,8 @@ import android.app.Activity; import android.app.AlertDialog; +import android.content.ClipData; +import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.graphics.Color; @@ -11,7 +13,6 @@ import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; -import android.preference.PreferenceManager; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; @@ -20,6 +21,7 @@ import android.widget.Button; import android.widget.EditText; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.Nullable; import androidx.annotation.StringRes; @@ -37,6 +39,8 @@ import org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; +import org.schabi.newpipe.util.Localization; +import org.schabi.newpipe.util.ShareUtils; import org.schabi.newpipe.util.ThemeHelper; import java.io.PrintWriter; @@ -45,7 +49,6 @@ import java.util.Arrays; import java.util.Date; import java.util.List; -import java.util.Locale; import java.util.TimeZone; import java.util.Vector; @@ -81,6 +84,10 @@ public class ErrorActivity extends AppCompatActivity { public static final String ERROR_EMAIL_ADDRESS = "crashreport@newpipe.schabi.org"; public static final String ERROR_EMAIL_SUBJECT = "Exception in NewPipe " + BuildConfig.VERSION_NAME; + + public static final String ERROR_GITHUB_ISSUE_URL + = "https://github.com/TeamNewPipe/NewPipe/issues"; + private String[] errorList; private ErrorInfo errorInfo; private Class returnActivity; @@ -193,7 +200,10 @@ protected void onCreate(final Bundle savedInstanceState) { actionBar.setDisplayShowTitleEnabled(true); } - Button reportButton = findViewById(R.id.errorReportButton); + Button reportEmailButton = findViewById(R.id.errorReportEmailButton); + Button copyButton = findViewById(R.id.errorReportCopyButton); + Button reportGithubButton = findViewById(R.id.errorReportGitHubButton); + userCommentBox = findViewById(R.id.errorCommentBox); TextView errorView = findViewById(R.id.errorView); TextView infoView = findViewById(R.id.errorInfosView); @@ -205,40 +215,28 @@ protected void onCreate(final Bundle savedInstanceState) { errorList = intent.getStringArrayExtra(ERROR_LIST); // important add guru meditation - addGuruMeditaion(); + addGuruMeditation(); currentTimeStamp = getCurrentTimeStamp(); - reportButton.setOnClickListener((View v) -> { - Context context = this; - new AlertDialog.Builder(context) - .setIcon(android.R.drawable.ic_dialog_alert) - .setTitle(R.string.privacy_policy_title) - .setMessage(R.string.start_accept_privacy_policy) - .setCancelable(false) - .setNeutralButton(R.string.read_privacy_policy, (dialog, which) -> { - Intent webIntent = new Intent(Intent.ACTION_VIEW, - Uri.parse(context.getString(R.string.privacy_policy_url)) - ); - context.startActivity(webIntent); - }) - .setPositiveButton(R.string.accept, (dialog, which) -> { - final Intent i = new Intent(Intent.ACTION_SENDTO) - .setData(Uri.parse("mailto:")) // only email apps should handle this - .putExtra(Intent.EXTRA_EMAIL, new String[]{ERROR_EMAIL_ADDRESS}) - .putExtra(Intent.EXTRA_SUBJECT, ERROR_EMAIL_SUBJECT) - .putExtra(Intent.EXTRA_TEXT, buildJson()); - if (i.resolveActivity(getPackageManager()) != null) { - startActivity(i); - } + reportEmailButton.setOnClickListener((View v) -> { + openPrivacyPolicyDialog(this, "EMAIL"); + }); - }) - .setNegativeButton(R.string.decline, (dialog, which) -> { - // do nothing - }) - .show(); + copyButton.setOnClickListener((View v) -> { + ClipboardManager clipboard = + (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText( + "NewPipe error report", + buildMarkdown()); + clipboard.setPrimaryClip(clip); + Toast.makeText(this, R.string.msg_copied, Toast.LENGTH_SHORT).show(); + }); + reportGithubButton.setOnClickListener((View v) -> { + openPrivacyPolicyDialog(this, "GITHUB"); }); + // normal bugreport buildInfo(errorInfo); if (errorInfo.message != 0) { @@ -281,6 +279,39 @@ public boolean onOptionsItemSelected(final MenuItem item) { return false; } + private void openPrivacyPolicyDialog(final Context context, final String action) { + new AlertDialog.Builder(context) + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(R.string.privacy_policy_title) + .setMessage(R.string.start_accept_privacy_policy) + .setCancelable(false) + .setNeutralButton(R.string.read_privacy_policy, (dialog, which) -> { + Intent webIntent = new Intent(Intent.ACTION_VIEW, + Uri.parse(context.getString(R.string.privacy_policy_url)) + ); + context.startActivity(webIntent); + }) + .setPositiveButton(R.string.accept, (dialog, which) -> { + if (action.equals("EMAIL")) { // send on email + final Intent i = new Intent(Intent.ACTION_SENDTO) + .setData(Uri.parse("mailto:")) // only email apps should handle this + .putExtra(Intent.EXTRA_EMAIL, new String[]{ERROR_EMAIL_ADDRESS}) + .putExtra(Intent.EXTRA_SUBJECT, ERROR_EMAIL_SUBJECT) + .putExtra(Intent.EXTRA_TEXT, buildJson()); + if (i.resolveActivity(getPackageManager()) != null) { + startActivity(i); + } + } else if (action.equals("GITHUB")) { // open the NewPipe issue page on GitHub + ShareUtils.openUrlInBrowser(this, ERROR_GITHUB_ISSUE_URL); + } + + }) + .setNegativeButton(R.string.decline, (dialog, which) -> { + // do nothing + }) + .show(); + } + private String formErrorText(final String[] el) { StringBuilder text = new StringBuilder(); if (el != null) { @@ -331,7 +362,9 @@ private void buildInfo(final ErrorInfo info) { text += getUserActionString(info.userAction) + "\n" + info.request + "\n" - + getContentLangString() + "\n" + + getContentLanguageString() + "\n" + + getContentCountryString() + "\n" + + getAppLanguage() + "\n" + info.serviceName + "\n" + currentTimeStamp + "\n" + getPackageName() + "\n" @@ -347,7 +380,10 @@ private String buildJson() { .object() .value("user_action", getUserActionString(errorInfo.userAction)) .value("request", errorInfo.request) - .value("content_language", getContentLangString()) + .value("content_language", getContentLanguageString()) + .value("content_country", getContentCountryString()) + .value("app_langauge", getAppLanguage()) + .value("app_language", getAppLanguage()) .value("service", errorInfo.serviceName) .value("package", getPackageName()) .value("version", BuildConfig.VERSION_NAME) @@ -365,6 +401,63 @@ private String buildJson() { return ""; } + private String buildMarkdown() { + try { + StringBuilder htmlErrorReport = new StringBuilder(); + + final String userComment = userCommentBox.getText().toString(); + if (!userComment.isEmpty()) { + htmlErrorReport.append(userComment).append("\n"); + } + + // basic error info + htmlErrorReport + .append("## Exception") + .append("\n* __User Action:__ ") + .append(getUserActionString(errorInfo.userAction)) + .append("\n* __Request:__ ").append(errorInfo.request) + .append("\n* __Content Country:__ ").append(getContentCountryString()) + .append("\n* __Content Language:__ ").append(getContentLanguageString()) + .append("\n* __App Language:__ ").append(getAppLanguage()) + .append("\n* __Service:__ ").append(errorInfo.serviceName) + .append("\n* __Version:__ ").append(BuildConfig.VERSION_NAME) + .append("\n* __OS:__ ").append(getOsString()).append("\n"); + + + // Collapse all logs to a single paragraph when there are more than one + // to keep the GitHub issue clean. + if (errorList.length > 1) { + htmlErrorReport + .append("
Exceptions (") + .append(errorList.length) + .append(")

\n"); + } + + // add the logs + for (int i = 0; i < errorList.length; i++) { + htmlErrorReport.append("

Crash log "); + if (errorList.length > 1) { + htmlErrorReport.append(i + 1); + } + htmlErrorReport.append("") + .append("

\n") + .append("\n```\n").append(errorList[i]).append("\n```\n") + .append("

\n"); + } + + // make sure to close everything + if (errorList.length > 1) { + htmlErrorReport.append("

\n"); + } + htmlErrorReport.append("
\n"); + return htmlErrorReport.toString(); + } catch (Throwable e) { + Log.e(TAG, "Error while erroring: Could not build markdown"); + e.printStackTrace(); + return ""; + } + } + private String getUserActionString(final UserAction userAction) { if (userAction == null) { return "Your description is in another castle."; @@ -373,13 +466,16 @@ private String getUserActionString(final UserAction userAction) { } } - private String getContentLangString() { - String contentLanguage = PreferenceManager.getDefaultSharedPreferences(this) - .getString(this.getString(R.string.content_country_key), "none"); - if (contentLanguage.equals(getString(R.string.default_localization_key))) { - contentLanguage = Locale.getDefault().toString(); - } - return contentLanguage; + private String getContentCountryString() { + return Localization.getPreferredContentCountry(this).getCountryCode(); + } + + private String getContentLanguageString() { + return Localization.getPreferredLocalization(this).getLocalizationCode(); + } + + private String getAppLanguage() { + return Localization.getAppLocale(getApplicationContext()).toString(); } private String getOsString() { @@ -390,7 +486,7 @@ private String getOsString() { + " - " + Build.VERSION.SDK_INT; } - private void addGuruMeditaion() { + private void addGuruMeditation() { //just an easter egg TextView sorryView = findViewById(R.id.errorSorryView); String text = sorryView.getText().toString(); diff --git a/app/src/main/res/layout/activity_error.xml b/app/src/main/res/layout/activity_error.xml index c47077c73de..12237f918ae 100644 --- a/app/src/main/res/layout/activity_error.xml +++ b/app/src/main/res/layout/activity_error.xml @@ -118,11 +118,31 @@ android:inputType="" />