From 1d2642f1e333089d52876907536b30aaa1a88750 Mon Sep 17 00:00:00 2001 From: Stypox Date: Wed, 1 Dec 2021 09:10:59 +0100 Subject: [PATCH 1/8] Create ErrorUtil class with three ways to report errors Activity, snackbar and notification --- app/src/main/java/org/schabi/newpipe/App.java | 15 ++- .../schabi/newpipe/error/ErrorActivity.java | 73 +------------- .../org/schabi/newpipe/error/ErrorUtil.kt | 96 +++++++++++++++++++ app/src/main/res/values/strings.xml | 13 ++- 4 files changed, 119 insertions(+), 78 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index 3785249b4..7ae2b42bd 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -227,28 +227,35 @@ public class App extends MultiDexApplication { // the main and update channels final NotificationChannelCompat mainChannel = new NotificationChannelCompat .Builder(getString(R.string.notification_channel_id), - NotificationManagerCompat.IMPORTANCE_LOW) + NotificationManagerCompat.IMPORTANCE_LOW) .setName(getString(R.string.notification_channel_name)) .setDescription(getString(R.string.notification_channel_description)) .build(); final NotificationChannelCompat appUpdateChannel = new NotificationChannelCompat .Builder(getString(R.string.app_update_notification_channel_id), - NotificationManagerCompat.IMPORTANCE_LOW) + NotificationManagerCompat.IMPORTANCE_LOW) .setName(getString(R.string.app_update_notification_channel_name)) .setDescription(getString(R.string.app_update_notification_channel_description)) .build(); final NotificationChannelCompat hashChannel = new NotificationChannelCompat .Builder(getString(R.string.hash_channel_id), - NotificationManagerCompat.IMPORTANCE_HIGH) + NotificationManagerCompat.IMPORTANCE_HIGH) .setName(getString(R.string.hash_channel_name)) .setDescription(getString(R.string.hash_channel_description)) .build(); + final NotificationChannelCompat errorReportChannel = new NotificationChannelCompat + .Builder(getString(R.string.error_report_channel_id), + NotificationManagerCompat.IMPORTANCE_LOW) + .setName(getString(R.string.error_report_channel_name)) + .setDescription(getString(R.string.error_report_channel_description)) + .build(); + final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.createNotificationChannelsCompat(Arrays.asList(mainChannel, - appUpdateChannel, hashChannel)); + appUpdateChannel, hashChannel, errorReportChannel)); } protected boolean isDisposedRxExceptionsReported() { diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java index db3a92d4f..257048e0e 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java @@ -1,9 +1,10 @@ package org.schabi.newpipe.error; +import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; + import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.graphics.Color; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -11,15 +12,12 @@ import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; -import android.view.View; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; -import androidx.fragment.app.Fragment; -import com.google.android.material.snackbar.Snackbar; import com.grack.nanojson.JsonWriter; import org.schabi.newpipe.BuildConfig; @@ -27,15 +25,13 @@ import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; import org.schabi.newpipe.databinding.ActivityErrorBinding; import org.schabi.newpipe.util.Localization; -import org.schabi.newpipe.util.external_communication.ShareUtils; import org.schabi.newpipe.util.ThemeHelper; +import org.schabi.newpipe.util.external_communication.ShareUtils; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Arrays; -import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; - /* * Created by Christian Schabesberger on 24.10.15. * @@ -56,7 +52,7 @@ import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; * along with NewPipe. If not, see . */ -public class ErrorActivity extends AppCompatActivity { +class ErrorActivity extends AppCompatActivity { // LOG TAGS public static final String TAG = ErrorActivity.class.toString(); // BUNDLE TAGS @@ -77,67 +73,6 @@ public class ErrorActivity extends AppCompatActivity { private ActivityErrorBinding activityErrorBinding; - /** - * Reports a new error by starting a new activity. - *
- * Ensure that the data within errorInfo is serializable otherwise - * an exception will be thrown!
- * {@link EnsureExceptionSerializable} might help. - * - * @param context - * @param errorInfo - */ - public static void reportError(final Context context, final ErrorInfo errorInfo) { - final Intent intent = new Intent(context, ErrorActivity.class); - intent.putExtra(ERROR_INFO, errorInfo); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - } - - public static void reportErrorInSnackbar(final Context context, final ErrorInfo errorInfo) { - final View rootView = context instanceof Activity - ? ((Activity) context).findViewById(android.R.id.content) : null; - reportErrorInSnackbar(context, rootView, errorInfo); - } - - public static void reportErrorInSnackbar(final Fragment fragment, final ErrorInfo errorInfo) { - View rootView = fragment.getView(); - if (rootView == null && fragment.getActivity() != null) { - rootView = fragment.getActivity().findViewById(android.R.id.content); - } - reportErrorInSnackbar(fragment.requireContext(), rootView, errorInfo); - } - - public static void reportUiErrorInSnackbar(final Context context, - final String request, - final Throwable throwable) { - reportErrorInSnackbar(context, new ErrorInfo(throwable, UserAction.UI_ERROR, request)); - } - - public static void reportUiErrorInSnackbar(final Fragment fragment, - final String request, - final Throwable throwable) { - reportErrorInSnackbar(fragment, new ErrorInfo(throwable, UserAction.UI_ERROR, request)); - } - - - //////////////////////////////////////////////////////////////////////// - // Utils - //////////////////////////////////////////////////////////////////////// - - private static void reportErrorInSnackbar(final Context context, - @Nullable final View rootView, - final ErrorInfo errorInfo) { - if (rootView != null) { - Snackbar.make(rootView, R.string.error_snackbar_message, Snackbar.LENGTH_LONG) - .setActionTextColor(Color.YELLOW) - .setAction(context.getString(R.string.error_snackbar_action).toUpperCase(), v -> - reportError(context, errorInfo)).show(); - } else { - reportError(context, errorInfo); - } - } - //////////////////////////////////////////////////////////////////////// // Activity lifecycle diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt new file mode 100644 index 000000000..66ddee9d8 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt @@ -0,0 +1,96 @@ +package org.schabi.newpipe.error + +import android.app.Activity +import android.app.NotificationManager +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.view.View +import androidx.core.app.NotificationCompat +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import com.google.android.material.snackbar.Snackbar +import org.schabi.newpipe.R + +class ErrorUtil { + companion object { + private const val ERROR_REPORT_NOTIFICATION_ID = 5340681; + + /** + * Reports a new error by starting a new activity. + *

+ * Ensure that the data within errorInfo is serializable otherwise + * an exception will be thrown!

+ * [EnsureExceptionSerializable] might help. + * + * @param context + * @param errorInfo + */ + @JvmStatic + fun openActivity(context: Context, errorInfo: ErrorInfo) { + val intent = Intent(context, ErrorActivity::class.java) + intent.putExtra(ErrorActivity.ERROR_INFO, errorInfo) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + context.startActivity(intent) + } + + @JvmStatic + fun showSnackbar(context: Context, errorInfo: ErrorInfo) { + val rootView = if (context is Activity) context.findViewById(R.id.content) else null + showSnackbar(context, rootView, errorInfo) + } + + @JvmStatic + fun showSnackbar(fragment: Fragment, errorInfo: ErrorInfo) { + var rootView = fragment.view + if (rootView == null && fragment.activity != null) { + rootView = fragment.requireActivity().findViewById(R.id.content) + } + showSnackbar(fragment.requireContext(), rootView, errorInfo) + } + + @JvmStatic + fun showUiErrorSnackbar(context: Context, request: String, throwable: Throwable) { + showSnackbar(context, ErrorInfo(throwable, UserAction.UI_ERROR, request)) + } + + @JvmStatic + fun showUiErrorSnackbar(fragment: Fragment, request: String, throwable: Throwable) { + showSnackbar(fragment, ErrorInfo(throwable, UserAction.UI_ERROR, request)) + } + + @JvmStatic + fun createNotification(context: Context, errorInfo: ErrorInfo) { + val notificationManager = + ContextCompat.getSystemService(context, NotificationManager::class.java) + if (notificationManager == null) { + // this should never happen, but just in case open error activity + openActivity(context, errorInfo) + } + + val notificationBuilder: NotificationCompat.Builder = + NotificationCompat.Builder(context, + context.getString(R.string.error_report_channel_id)) + .setSmallIcon(R.drawable.ic_bug_report) + .setContentTitle(context.getString(R.string.error_report_title)) + .setContentText(context.getString(errorInfo.messageStringId)) + + notificationManager!!.notify(ERROR_REPORT_NOTIFICATION_ID, notificationBuilder.build()) + } + + + private fun showSnackbar(context: Context, rootView: View?, errorInfo: ErrorInfo) { + if (rootView == null) { + // fallback to showing a notification if no root view is available + createNotification(context, errorInfo) + + } else { + Snackbar.make(rootView, R.string.error_snackbar_message, Snackbar.LENGTH_LONG) + .setActionTextColor(Color.YELLOW) + .setAction(context.getString(R.string.error_snackbar_action).uppercase()) { + openActivity(context, errorInfo) + }.show() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a8bb4c788..2824c9efb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -182,14 +182,17 @@ Just Once File newpipe - NewPipe Notification - Notifications for NewPipe background and popup players + NewPipe notification + Notifications for NewPipe\'s player newpipeAppUpdate - App Update Notification - Notifications for new NewPipe version + App update notification + Notifications for new NewPipe versions newpipeHash - Video Hash Notification + Video hash notification Notifications for video hashing progress + newpipeErrorReport + Error report notification + Notifications to report errors [Unknown] Switch to Background Switch to Popup From 81f740d409054b3846d9246c41a19e2f076472fe Mon Sep 17 00:00:00 2001 From: Stypox Date: Wed, 1 Dec 2021 09:43:24 +0100 Subject: [PATCH 2/8] Replace ErrorActivity with ErrorUtil --- app/src/main/java/org/schabi/newpipe/App.java | 4 +-- .../schabi/newpipe/CheckForNewAppVersion.java | 8 +++--- .../java/org/schabi/newpipe/MainActivity.java | 14 +++++----- .../org/schabi/newpipe/RouterActivity.java | 4 +-- .../newpipe/download/DownloadDialog.java | 10 +++---- .../newpipe/error/AcraReportSender.java | 2 +- .../schabi/newpipe/error/ErrorActivity.java | 2 +- .../schabi/newpipe/error/ErrorPanelHelper.kt | 4 +-- .../org/schabi/newpipe/error/ErrorUtil.kt | 28 +++++++++---------- .../newpipe/fragments/BaseStateFragment.java | 10 +++---- .../newpipe/fragments/MainFragment.java | 13 +++------ .../fragments/detail/VideoDetailFragment.java | 9 +++--- .../fragments/list/BaseListFragment.java | 6 ++-- .../list/channel/ChannelFragment.java | 4 +-- .../list/playlist/PlaylistFragment.java | 4 +-- .../fragments/list/search/SearchFragment.java | 5 ++-- .../holder/CommentsMiniInfoItemHolder.java | 4 +-- .../SubscriptionsImportFragment.java | 4 +-- .../services/BaseImportExportService.java | 4 +-- .../playererror/PlayerErrorHandler.java | 4 +-- .../settings/ContentSettingsFragment.java | 6 ++-- .../settings/HistorySettingsFragment.java | 10 +++---- .../settings/SelectChannelFragment.java | 4 +-- .../newpipe/settings/SelectKioskFragment.java | 7 ++--- .../settings/SelectPlaylistFragment.java | 6 ++-- .../newpipe/settings/SettingMigrations.java | 4 +-- .../settings/tabs/ChooseTabsFragment.java | 4 +-- .../org/schabi/newpipe/settings/tabs/Tab.java | 4 +-- .../giga/ui/adapter/MissionAdapter.java | 4 +-- 29 files changed, 91 insertions(+), 101 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index 7ae2b42bd..6c02b6f57 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -16,8 +16,8 @@ import org.acra.ACRA; import org.acra.config.ACRAConfigurationException; import org.acra.config.CoreConfiguration; import org.acra.config.CoreConfigurationBuilder; -import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.ReCaptchaActivity; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.NewPipe; @@ -217,7 +217,7 @@ public class App extends MultiDexApplication { ACRA.init(this, acraConfig); } catch (final ACRAConfigurationException exception) { exception.printStackTrace(); - ErrorActivity.reportError(this, new ErrorInfo(exception, + ErrorUtil.openActivity(this, new ErrorInfo(exception, UserAction.SOMETHING_ELSE, "Could not initialize ACRA crash report")); } } diff --git a/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersion.java b/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersion.java index 9e43394ac..122660d64 100644 --- a/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersion.java +++ b/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersion.java @@ -21,8 +21,8 @@ import com.grack.nanojson.JsonObject; import com.grack.nanojson.JsonParser; import com.grack.nanojson.JsonParserException; -import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.downloader.Response; import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; @@ -64,7 +64,7 @@ public final class CheckForNewAppVersion extends IntentService { signatures = PackageInfoCompat.getSignatures(application.getPackageManager(), application.getPackageName()); } catch (final PackageManager.NameNotFoundException e) { - ErrorActivity.reportError(application, new ErrorInfo(e, + ErrorUtil.createNotification(application, new ErrorInfo(e, UserAction.CHECK_FOR_NEW_APP_VERSION, "Could not find package info")); return ""; } @@ -79,7 +79,7 @@ public final class CheckForNewAppVersion extends IntentService { final CertificateFactory cf = CertificateFactory.getInstance("X509"); c = (X509Certificate) cf.generateCertificate(input); } catch (final CertificateException e) { - ErrorActivity.reportError(application, new ErrorInfo(e, + ErrorUtil.createNotification(application, new ErrorInfo(e, UserAction.CHECK_FOR_NEW_APP_VERSION, "Certificate error")); return ""; } @@ -89,7 +89,7 @@ public final class CheckForNewAppVersion extends IntentService { final byte[] publicKey = md.digest(c.getEncoded()); return byte2HexFormatted(publicKey); } catch (NoSuchAlgorithmException | CertificateEncodingException e) { - ErrorActivity.reportError(application, new ErrorInfo(e, + ErrorUtil.createNotification(application, new ErrorInfo(e, UserAction.CHECK_FOR_NEW_APP_VERSION, "Could not retrieve SHA1 key")); return ""; } diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index 0a49e00e4..95663ea0a 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -63,7 +63,7 @@ import org.schabi.newpipe.databinding.DrawerHeaderBinding; import org.schabi.newpipe.databinding.DrawerLayoutBinding; import org.schabi.newpipe.databinding.InstanceSpinnerLayoutBinding; import org.schabi.newpipe.databinding.ToolbarLayoutBinding; -import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.exceptions.ExtractionException; @@ -157,7 +157,7 @@ public class MainActivity extends AppCompatActivity { try { setupDrawer(); } catch (final Exception e) { - ErrorActivity.reportUiErrorInSnackbar(this, "Setting up drawer", e); + ErrorUtil.showUiErrorSnackbar(this, "Setting up drawer", e); } if (DeviceUtils.isTv(this)) { @@ -214,7 +214,7 @@ public class MainActivity extends AppCompatActivity { /** * Builds the drawer menu for the current service. * - * @throws ExtractionException + * @throws ExtractionException if the service didn't provide available kiosks */ private void addDrawerMenuForCurrentService() throws ExtractionException { //Tabs @@ -266,7 +266,7 @@ public class MainActivity extends AppCompatActivity { try { tabSelected(item); } catch (final Exception e) { - ErrorActivity.reportUiErrorInSnackbar(this, "Selecting main page tab", e); + ErrorUtil.showUiErrorSnackbar(this, "Selecting main page tab", e); } break; case R.id.menu_options_about_group: @@ -372,7 +372,7 @@ public class MainActivity extends AppCompatActivity { try { addDrawerMenuForCurrentService(); } catch (final Exception e) { - ErrorActivity.reportUiErrorInSnackbar(this, "Showing main page tabs", e); + ErrorUtil.showUiErrorSnackbar(this, "Showing main page tabs", e); } } } @@ -475,7 +475,7 @@ public class MainActivity extends AppCompatActivity { drawerHeaderBinding.drawerHeaderActionButton.setContentDescription( getString(R.string.drawer_header_description) + selectedServiceName); } catch (final Exception e) { - ErrorActivity.reportUiErrorInSnackbar(this, "Setting up service toggle", e); + ErrorUtil.showUiErrorSnackbar(this, "Setting up service toggle", e); } final SharedPreferences sharedPreferences @@ -785,7 +785,7 @@ public class MainActivity extends AppCompatActivity { NavigationHelper.gotoMainFragment(getSupportFragmentManager()); } } catch (final Exception e) { - ErrorActivity.reportUiErrorInSnackbar(this, "Handling intent", e); + ErrorUtil.showUiErrorSnackbar(this, "Handling intent", e); } } diff --git a/app/src/main/java/org/schabi/newpipe/RouterActivity.java b/app/src/main/java/org/schabi/newpipe/RouterActivity.java index 4e96f3bb6..9d6e44f04 100644 --- a/app/src/main/java/org/schabi/newpipe/RouterActivity.java +++ b/app/src/main/java/org/schabi/newpipe/RouterActivity.java @@ -37,8 +37,8 @@ import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.databinding.ListRadioIconItemBinding; import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding; import org.schabi.newpipe.download.DownloadDialog; -import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.ReCaptchaActivity; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.Info; @@ -231,7 +231,7 @@ public class RouterActivity extends AppCompatActivity { } else if (errorInfo.getThrowable() instanceof ContentNotSupportedException) { Toast.makeText(context, R.string.content_not_supported, Toast.LENGTH_LONG).show(); } else { - ErrorActivity.reportError(context, errorInfo); + ErrorUtil.createNotification(context, errorInfo); } if (context instanceof RouterActivity) { diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java index a7f5b938f..69e975a49 100644 --- a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java @@ -41,8 +41,8 @@ import com.nononsenseapps.filepicker.Utils; import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; import org.schabi.newpipe.databinding.DownloadDialogBinding; -import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.NewPipe; @@ -402,7 +402,7 @@ public class DownloadDialog extends DialogFragment == R.id.video_button) { setupVideoSpinner(); } - }, throwable -> ErrorActivity.reportErrorInSnackbar(context, + }, throwable -> ErrorUtil.showSnackbar(context, new ErrorInfo(throwable, UserAction.DOWNLOAD_OPEN_DIALOG, "Downloading video stream size", currentInfo.getServiceId())))); @@ -412,7 +412,7 @@ public class DownloadDialog extends DialogFragment == R.id.audio_button) { setupAudioSpinner(); } - }, throwable -> ErrorActivity.reportErrorInSnackbar(context, + }, throwable -> ErrorUtil.showSnackbar(context, new ErrorInfo(throwable, UserAction.DOWNLOAD_OPEN_DIALOG, "Downloading audio stream size", currentInfo.getServiceId())))); @@ -422,7 +422,7 @@ public class DownloadDialog extends DialogFragment == R.id.subtitle_button) { setupSubtitleSpinner(); } - }, throwable -> ErrorActivity.reportErrorInSnackbar(context, + }, throwable -> ErrorUtil.showSnackbar(context, new ErrorInfo(throwable, UserAction.DOWNLOAD_OPEN_DIALOG, "Downloading subtitle stream size", currentInfo.getServiceId())))); @@ -799,7 +799,7 @@ public class DownloadDialog extends DialogFragment mainStorage.getTag()); } } catch (final Exception e) { - ErrorActivity.reportErrorInSnackbar(this, + ErrorUtil.createNotification(requireContext(), new ErrorInfo(e, UserAction.DOWNLOAD_FAILED, "Getting storage")); return; } diff --git a/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java b/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java index 60d4908eb..bf9030509 100644 --- a/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java +++ b/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java @@ -33,7 +33,7 @@ public class AcraReportSender implements ReportSender { @Override public void send(@NonNull final Context context, @NonNull final CrashReportData report) { - ErrorActivity.reportError(context, new ErrorInfo( + ErrorUtil.openActivity(context, new ErrorInfo( new String[]{report.getString(ReportField.STACK_TRACE)}, UserAction.UI_ERROR, ErrorInfo.SERVICE_NONE, diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java index 257048e0e..07f736af3 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java @@ -52,7 +52,7 @@ import java.util.Arrays; * along with NewPipe. If not, see . */ -class ErrorActivity extends AppCompatActivity { +public class ErrorActivity extends AppCompatActivity { // LOG TAGS public static final String TAG = ErrorActivity.class.toString(); // BUNDLE TAGS diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt index 228c17f8c..692cb427a 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt @@ -118,7 +118,7 @@ class ErrorPanelHelper( showAndSetErrorButtonAction( R.string.error_snackbar_action ) { - ErrorActivity.reportError(context, errorInfo) + ErrorUtil.openActivity(context, errorInfo) } errorTextView.setText(getExceptionDescription(errorInfo.throwable)) @@ -178,7 +178,7 @@ class ErrorPanelHelper( val DEBUG: Boolean = MainActivity.DEBUG @StringRes - public fun getExceptionDescription(throwable: Throwable?): Int { + fun getExceptionDescription(throwable: Throwable?): Int { return when (throwable) { is AgeRestrictedContentException -> R.string.restricted_video_no_stream is GeographicRestrictionException -> R.string.georestricted_content diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt index 66ddee9d8..7e10d5608 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt @@ -14,7 +14,7 @@ import org.schabi.newpipe.R class ErrorUtil { companion object { - private const val ERROR_REPORT_NOTIFICATION_ID = 5340681; + private const val ERROR_REPORT_NOTIFICATION_ID = 5340681 /** * Reports a new error by starting a new activity. @@ -62,35 +62,35 @@ class ErrorUtil { @JvmStatic fun createNotification(context: Context, errorInfo: ErrorInfo) { val notificationManager = - ContextCompat.getSystemService(context, NotificationManager::class.java) + ContextCompat.getSystemService(context, NotificationManager::class.java) if (notificationManager == null) { // this should never happen, but just in case open error activity openActivity(context, errorInfo) } val notificationBuilder: NotificationCompat.Builder = - NotificationCompat.Builder(context, - context.getString(R.string.error_report_channel_id)) - .setSmallIcon(R.drawable.ic_bug_report) - .setContentTitle(context.getString(R.string.error_report_title)) - .setContentText(context.getString(errorInfo.messageStringId)) + NotificationCompat.Builder( + context, + context.getString(R.string.error_report_channel_id) + ) + .setSmallIcon(R.drawable.ic_bug_report) + .setContentTitle(context.getString(R.string.error_report_title)) + .setContentText(context.getString(errorInfo.messageStringId)) notificationManager!!.notify(ERROR_REPORT_NOTIFICATION_ID, notificationBuilder.build()) } - private fun showSnackbar(context: Context, rootView: View?, errorInfo: ErrorInfo) { if (rootView == null) { // fallback to showing a notification if no root view is available createNotification(context, errorInfo) - } else { Snackbar.make(rootView, R.string.error_snackbar_message, Snackbar.LENGTH_LONG) - .setActionTextColor(Color.YELLOW) - .setAction(context.getString(R.string.error_snackbar_action).uppercase()) { - openActivity(context, errorInfo) - }.show() + .setActionTextColor(Color.YELLOW) + .setAction(context.getString(R.string.error_snackbar_action).uppercase()) { + openActivity(context, errorInfo) + }.show() } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java index db91755df..9b4bf8377 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java @@ -7,12 +7,13 @@ import android.widget.ProgressBar; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; import org.schabi.newpipe.BaseFragment; import org.schabi.newpipe.R; -import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; import org.schabi.newpipe.error.ErrorPanelHelper; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.util.InfoCache; import java.util.concurrent.atomic.AtomicBoolean; @@ -198,9 +199,8 @@ public abstract class BaseStateFragment extends BaseFragment implements ViewC } /** - * Show a SnackBar and only call - * {@link ErrorActivity#reportErrorInSnackbar(androidx.fragment.app.Fragment, ErrorInfo)} - * IF we a find a valid view (otherwise the error screen appears). + * Directly calls {@link ErrorUtil#showSnackbar(Fragment, ErrorInfo)}, that shows a snackbar if + * a valid view can be found, otherwise creates an error report notification. * * @param errorInfo The error information */ @@ -208,6 +208,6 @@ public abstract class BaseStateFragment extends BaseFragment implements ViewC if (DEBUG) { Log.d(TAG, "showSnackBarError() called with: errorInfo = [" + errorInfo + "]"); } - ErrorActivity.reportErrorInSnackbar(this, errorInfo); + ErrorUtil.showSnackbar(this, errorInfo); } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java index 7e0186e1c..de68269e9 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java @@ -23,7 +23,7 @@ import com.google.android.material.tabs.TabLayout; import org.schabi.newpipe.BaseFragment; import org.schabi.newpipe.R; import org.schabi.newpipe.databinding.FragmentMainBinding; -import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.settings.tabs.Tab; import org.schabi.newpipe.settings.tabs.TabsManager; @@ -145,7 +145,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte NavigationHelper.openSearchFragment(getFM(), ServiceHelper.getSelectedServiceId(activity), ""); } catch (final Exception e) { - ErrorActivity.reportUiErrorInSnackbar(this, "Opening search fragment", e); + ErrorUtil.showUiErrorSnackbar(this, "Opening search fragment", e); } return true; } @@ -227,16 +227,11 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte public Fragment getItem(final int position) { final Tab tab = internalTabsList.get(position); - Throwable throwable = null; - Fragment fragment = null; + final Fragment fragment; try { fragment = tab.getFragment(context); } catch (final ExtractionException e) { - throwable = e; - } - - if (throwable != null) { - ErrorActivity.reportUiErrorInSnackbar(context, "Getting fragment item", throwable); + ErrorUtil.showUiErrorSnackbar(context, "Getting fragment item", e); return new BlankFragment(); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 8c6e01537..b5129f0b1 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -55,8 +55,8 @@ import org.schabi.newpipe.R; import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.databinding.FragmentVideoDetailBinding; import org.schabi.newpipe.download.DownloadDialog; -import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.ReCaptchaActivity; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.InfoItem; @@ -533,7 +533,7 @@ public final class VideoDetailFragment NavigationHelper.openChannelFragment(getFM(), currentInfo.getServiceId(), subChannelUrl, subChannelName); } catch (final Exception e) { - ErrorActivity.reportUiErrorInSnackbar(this, "Opening channel fragment", e); + ErrorUtil.showUiErrorSnackbar(this, "Opening channel fragment", e); } } @@ -1681,9 +1681,8 @@ public final class VideoDetailFragment downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog"); } catch (final Exception e) { - ErrorActivity.reportErrorInSnackbar(activity, - new ErrorInfo(e, UserAction.DOWNLOAD_OPEN_DIALOG, "Showing download dialog", - currentInfo)); + ErrorUtil.showSnackbar(activity, new ErrorInfo(e, UserAction.DOWNLOAD_OPEN_DIALOG, + "Showing download dialog", currentInfo)); } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java index b9065c969..4319d42ee 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java @@ -21,7 +21,7 @@ import androidx.viewbinding.ViewBinding; import org.schabi.newpipe.R; import org.schabi.newpipe.databinding.PignateFooterBinding; -import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.channel.ChannelInfoItem; import org.schabi.newpipe.extractor.comments.CommentsInfoItem; @@ -293,7 +293,7 @@ public abstract class BaseListFragment extends BaseStateFragment selectedItem.getUrl(), selectedItem.getName()); } catch (final Exception e) { - ErrorActivity.reportUiErrorInSnackbar( + ErrorUtil.showUiErrorSnackbar( BaseListFragment.this, "Opening channel fragment", e); } } @@ -309,7 +309,7 @@ public abstract class BaseListFragment extends BaseStateFragment selectedItem.getUrl(), selectedItem.getName()); } catch (final Exception e) { - ErrorActivity.reportUiErrorInSnackbar(BaseListFragment.this, + ErrorUtil.showUiErrorSnackbar(BaseListFragment.this, "Opening playlist fragment", e); } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java index 30e38a966..37954478d 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java @@ -26,8 +26,8 @@ import org.schabi.newpipe.database.subscription.SubscriptionEntity; import org.schabi.newpipe.databinding.ChannelHeaderBinding; import org.schabi.newpipe.databinding.FragmentChannelBinding; import org.schabi.newpipe.databinding.PlaylistControlBinding; -import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor; @@ -407,7 +407,7 @@ public class ChannelFragment extends BaseListInfoFragment currentInfo.getParentChannelUrl(), currentInfo.getParentChannelName()); } catch (final Exception e) { - ErrorActivity.reportUiErrorInSnackbar(this, "Opening channel fragment", e); + ErrorUtil.showUiErrorSnackbar(this, "Opening channel fragment", e); } } else if (DEBUG) { Log.i(TAG, "Can't open parent channel because we got no channel URL"); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java index a8763af73..a61cec11d 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java @@ -24,8 +24,8 @@ import org.schabi.newpipe.R; import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; import org.schabi.newpipe.databinding.PlaylistControlBinding; import org.schabi.newpipe.databinding.PlaylistHeaderBinding; -import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor; @@ -310,7 +310,7 @@ public class PlaylistFragment extends BaseListInfoFragment { NavigationHelper.openChannelFragment(getFM(), result.getServiceId(), result.getUploaderUrl(), result.getUploaderName()); } catch (final Exception e) { - ErrorActivity.reportUiErrorInSnackbar(this, "Opening channel fragment", e); + ErrorUtil.showUiErrorSnackbar(this, "Opening channel fragment", e); } }); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java index d4d73f74f..ba0bd50c6 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java @@ -38,8 +38,8 @@ import androidx.recyclerview.widget.RecyclerView; import org.schabi.newpipe.R; import org.schabi.newpipe.database.history.model.SearchHistoryEntry; import org.schabi.newpipe.databinding.FragmentSearchBinding; -import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.ReCaptchaActivity; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.InfoItem; @@ -225,8 +225,7 @@ public class SearchFragment extends BaseListFragment Toast.makeText(context, R.string.watch_history_states_deleted, Toast.LENGTH_SHORT).show(), - throwable -> ErrorActivity.reportError(context, + throwable -> ErrorUtil.openActivity(context, new ErrorInfo(throwable, UserAction.DELETE_FROM_HISTORY, "Delete playback states"))); } @@ -76,7 +76,7 @@ public class HistorySettingsFragment extends BasePreferenceFragment { .subscribe( howManyDeleted -> Toast.makeText(context, R.string.watch_history_deleted, Toast.LENGTH_SHORT).show(), - throwable -> ErrorActivity.reportError(context, + throwable -> ErrorUtil.openActivity(context, new ErrorInfo(throwable, UserAction.DELETE_FROM_HISTORY, "Delete from history"))); } @@ -87,7 +87,7 @@ public class HistorySettingsFragment extends BasePreferenceFragment { .observeOn(AndroidSchedulers.mainThread()) .subscribe( howManyDeleted -> { }, - throwable -> ErrorActivity.reportError(context, + throwable -> ErrorUtil.openActivity(context, new ErrorInfo(throwable, UserAction.DELETE_FROM_HISTORY, "Clear orphaned records"))); } @@ -99,7 +99,7 @@ public class HistorySettingsFragment extends BasePreferenceFragment { .subscribe( howManyDeleted -> Toast.makeText(context, R.string.search_history_deleted, Toast.LENGTH_SHORT).show(), - throwable -> ErrorActivity.reportError(context, + throwable -> ErrorUtil.openActivity(context, new ErrorInfo(throwable, UserAction.DELETE_FROM_HISTORY, "Delete search history"))); } diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java index a0105a11f..116807cbc 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java @@ -16,7 +16,7 @@ import androidx.recyclerview.widget.RecyclerView; import org.schabi.newpipe.R; import org.schabi.newpipe.database.subscription.SubscriptionEntity; -import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.local.subscription.SubscriptionManager; import org.schabi.newpipe.util.PicassoHelper; import org.schabi.newpipe.util.ThemeHelper; @@ -153,7 +153,7 @@ public class SelectChannelFragment extends DialogFragment { @Override public void onError(@NonNull final Throwable exception) { - ErrorActivity.reportUiErrorInSnackbar(SelectChannelFragment.this, + ErrorUtil.showUiErrorSnackbar(SelectChannelFragment.this, "Loading subscription", exception); } diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java index 9d8736076..a766ee074 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java @@ -16,7 +16,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import org.schabi.newpipe.R; -import org.schabi.newpipe.error.ErrorActivity; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.util.KioskTranslator; @@ -48,7 +48,6 @@ import java.util.Vector; */ public class SelectKioskFragment extends DialogFragment { - private RecyclerView recyclerView = null; private SelectKioskAdapter selectKioskAdapter = null; private OnSelectedListener onSelectedListener = null; @@ -76,12 +75,12 @@ public class SelectKioskFragment extends DialogFragment { public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { final View v = inflater.inflate(R.layout.select_kiosk_fragment, container, false); - recyclerView = v.findViewById(R.id.items_list); + final RecyclerView recyclerView = v.findViewById(R.id.items_list); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); try { selectKioskAdapter = new SelectKioskAdapter(); } catch (final Exception e) { - ErrorActivity.reportUiErrorInSnackbar(this, "Selecting kiosk", e); + ErrorUtil.showUiErrorSnackbar(this, "Selecting kiosk", e); } recyclerView.setAdapter(selectKioskAdapter); diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java index f94e391ba..e8491d52c 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java @@ -1,6 +1,5 @@ package org.schabi.newpipe.settings; -import android.app.Activity; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -21,8 +20,8 @@ import org.schabi.newpipe.database.LocalItem; import org.schabi.newpipe.database.playlist.PlaylistLocalItem; import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry; import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; -import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.local.playlist.LocalPlaylistManager; import org.schabi.newpipe.local.playlist.RemotePlaylistManager; @@ -105,8 +104,7 @@ public class SelectPlaylistFragment extends DialogFragment { } protected void onError(final Throwable e) { - final Activity activity = requireActivity(); - ErrorActivity.reportErrorInSnackbar(activity, new ErrorInfo(e, + ErrorUtil.showSnackbar(requireActivity(), new ErrorInfo(e, UserAction.UI_ERROR, "Loading playlists")); } diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java b/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java index b0b9567d8..8924ecbe1 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java @@ -8,8 +8,8 @@ import android.util.Log; import androidx.preference.PreferenceManager; import org.schabi.newpipe.R; -import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.DeviceUtils; @@ -157,7 +157,7 @@ public final class SettingMigrations { } catch (final Exception e) { // save the version with the last successful migration and report the error sp.edit().putInt(lastPrefVersionKey, currentVersion).apply(); - ErrorActivity.reportError(context, new ErrorInfo( + ErrorUtil.openActivity(context, new ErrorInfo( e, UserAction.PREFERENCES_MIGRATION, "Migrating preferences from version " + lastPrefVersion + " to " diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java index c9eb42fca..95f7f50ba 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java @@ -27,8 +27,8 @@ import androidx.recyclerview.widget.RecyclerView; import com.google.android.material.floatingactionbutton.FloatingActionButton; import org.schabi.newpipe.R; -import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.settings.SelectChannelFragment; @@ -182,7 +182,7 @@ public class ChooseTabsFragment extends Fragment { final Tab.Type type = typeFrom(tabId); if (type == null) { - ErrorActivity.reportErrorInSnackbar(this, + ErrorUtil.showSnackbar(this, new ErrorInfo(new IllegalStateException("Tab id not found: " + tabId), UserAction.SOMETHING_ELSE, "Choosing tabs on settings")); return; diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java index a148255b3..eac5ce311 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java @@ -12,8 +12,8 @@ import com.grack.nanojson.JsonSink; import org.schabi.newpipe.R; import org.schabi.newpipe.database.LocalItem.LocalItemType; -import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.StreamingService; @@ -506,7 +506,7 @@ public abstract class Tab { final StreamingService service = NewPipe.getService(kioskServiceId); kioskId = service.getKioskList().getDefaultKioskId(); } catch (final ExtractionException e) { - ErrorActivity.reportErrorInSnackbar(context, new ErrorInfo(e, + ErrorUtil.showSnackbar(context, new ErrorInfo(e, UserAction.REQUESTED_KIOSK, "Loading default kiosk for selected service")); } return kioskId; diff --git a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java index 057b9cb09..569c50001 100644 --- a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java +++ b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java @@ -39,8 +39,8 @@ import com.google.android.material.snackbar.Snackbar; import org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.R; +import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.Localization; @@ -581,7 +581,7 @@ public class MissionAdapter extends Adapter implements Handler.Callb service = ErrorInfo.SERVICE_NONE; } - ErrorActivity.reportError(mContext, + ErrorUtil.createNotification(mContext, new ErrorInfo(ErrorInfo.Companion.throwableToStringList(mission.errObject), action, service, request.toString(), reason, null)); } From 09d137f7407f3a0674d46b5c46c7283e1b6be9f9 Mon Sep 17 00:00:00 2001 From: Stypox Date: Wed, 1 Dec 2021 10:13:28 +0100 Subject: [PATCH 3/8] Add PendingIntent to ErrorUtil.createNotification --- .../org/schabi/newpipe/error/ErrorUtil.kt | 30 +++++++++++++++---- app/src/main/res/values/strings.xml | 1 + 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt index 7e10d5608..e62aad1df 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt @@ -2,9 +2,11 @@ package org.schabi.newpipe.error import android.app.Activity import android.app.NotificationManager +import android.app.PendingIntent import android.content.Context import android.content.Intent import android.graphics.Color +import android.os.Build import android.view.View import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat @@ -28,10 +30,7 @@ class ErrorUtil { */ @JvmStatic fun openActivity(context: Context, errorInfo: ErrorInfo) { - val intent = Intent(context, ErrorActivity::class.java) - intent.putExtra(ErrorActivity.ERROR_INFO, errorInfo) - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - context.startActivity(intent) + context.startActivity(getErrorActivityIntent(context, errorInfo)) } @JvmStatic @@ -68,18 +67,39 @@ class ErrorUtil { openActivity(context, errorInfo) } + var pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + pendingIntentFlags = pendingIntentFlags or PendingIntent.FLAG_IMMUTABLE + } + val notificationBuilder: NotificationCompat.Builder = NotificationCompat.Builder( context, context.getString(R.string.error_report_channel_id) ) .setSmallIcon(R.drawable.ic_bug_report) - .setContentTitle(context.getString(R.string.error_report_title)) + .setContentTitle(context.getString(R.string.error_report_notification_title)) .setContentText(context.getString(errorInfo.messageStringId)) + .setAutoCancel(true) + .setContentIntent( + PendingIntent.getActivity( + context, + 0, + getErrorActivityIntent(context, errorInfo), + pendingIntentFlags + ) + ) notificationManager!!.notify(ERROR_REPORT_NOTIFICATION_ID, notificationBuilder.build()) } + private fun getErrorActivityIntent(context: Context, errorInfo: ErrorInfo): Intent { + val intent = Intent(context, ErrorActivity::class.java) + intent.putExtra(ErrorActivity.ERROR_INFO, errorInfo) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + return intent + } + private fun showSnackbar(context: Context, rootView: View?, errorInfo: ErrorInfo) { if (rootView == null) { // fallback to showing a notification if no root view is available diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2824c9efb..f47322b79 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -246,6 +246,7 @@ Do you want to restore defaults? Give permission to display over other apps + NewPipe encountered an error, tap to report Sorry, that should not have happened. Guru Meditation. Report this error via e-mail From 397f93b079fb118c3f17650057f5ad13484b60d3 Mon Sep 17 00:00:00 2001 From: Stypox Date: Wed, 1 Dec 2021 10:28:35 +0100 Subject: [PATCH 4/8] Prevent exception from being serialized in ErrorInfo The wrong @Decorator was put in the wrong place to mark the throwable fieldd as transient, now this is fixed and the exception is not serialized. So if a non-serializable throwable is passed, that's not an issue, since it's not going to be serialized. The need for EnsureExceptionSerializable is also gone. --- .../newpipe/error/AcraReportSender.java | 3 +- .../error/EnsureExceptionSerializable.java | 103 ------------------ .../org/schabi/newpipe/error/ErrorInfo.kt | 24 ++-- .../org/schabi/newpipe/error/ErrorUtil.kt | 4 - .../SubscriptionsImportFragment.java | 3 +- .../playererror/PlayerErrorHandler.java | 3 +- .../giga/ui/adapter/MissionAdapter.java | 2 +- 7 files changed, 19 insertions(+), 123 deletions(-) delete mode 100644 app/src/main/java/org/schabi/newpipe/error/EnsureExceptionSerializable.java diff --git a/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java b/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java index bf9030509..4d9966364 100644 --- a/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java +++ b/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java @@ -38,7 +38,6 @@ public class AcraReportSender implements ReportSender { UserAction.UI_ERROR, ErrorInfo.SERVICE_NONE, "ACRA report", - R.string.app_ui_crash, - null)); + R.string.app_ui_crash)); } } diff --git a/app/src/main/java/org/schabi/newpipe/error/EnsureExceptionSerializable.java b/app/src/main/java/org/schabi/newpipe/error/EnsureExceptionSerializable.java deleted file mode 100644 index db94de5e5..000000000 --- a/app/src/main/java/org/schabi/newpipe/error/EnsureExceptionSerializable.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.schabi.newpipe.error; - -import android.util.Log; - -import androidx.annotation.NonNull; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectOutputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Ensures that a Exception is serializable. - * This is - */ -public final class EnsureExceptionSerializable { - private static final String TAG = "EnsureExSerializable"; - - private EnsureExceptionSerializable() { - // No instance - } - - /** - * Ensures that an exception is serializable. - *
- * If that is not the case a {@link WorkaroundNotSerializableException} is created. - * - * @param exception - * @return if an exception is not serializable a new {@link WorkaroundNotSerializableException} - * otherwise the exception from the parameter - */ - public static Exception ensureSerializable(@NonNull final Exception exception) { - return checkIfSerializable(exception) - ? exception - : WorkaroundNotSerializableException.create(exception); - } - - public static boolean checkIfSerializable(@NonNull final Exception exception) { - try { - // Check by creating a new ObjectOutputStream which does the serialization - try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(bos) - ) { - oos.writeObject(exception); - oos.flush(); - - bos.toByteArray(); - } - - return true; - } catch (final IOException ex) { - Log.d(TAG, "Exception is not serializable", ex); - return false; - } - } - - public static class WorkaroundNotSerializableException extends Exception { - protected WorkaroundNotSerializableException( - final Throwable notSerializableException, - final Throwable cause) { - super(notSerializableException.toString(), cause); - setStackTrace(notSerializableException.getStackTrace()); - } - - protected WorkaroundNotSerializableException(final Throwable notSerializableException) { - super(notSerializableException.toString()); - setStackTrace(notSerializableException.getStackTrace()); - } - - public static WorkaroundNotSerializableException create( - @NonNull final Exception notSerializableException - ) { - // Build a list of the exception + all causes - final List throwableList = new ArrayList<>(); - - int pos = 0; - Throwable throwableToProcess = notSerializableException; - - while (throwableToProcess != null) { - throwableList.add(throwableToProcess); - - pos++; - throwableToProcess = throwableToProcess.getCause(); - } - - // Reverse list so that it starts with the last one - Collections.reverse(throwableList); - - // Build exception stack - WorkaroundNotSerializableException cause = null; - for (final Throwable t : throwableList) { - cause = cause == null - ? new WorkaroundNotSerializableException(t) - : new WorkaroundNotSerializableException(t, cause); - } - - return cause; - } - - } -} diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt index 6581b5752..ba1204e12 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt @@ -2,6 +2,7 @@ package org.schabi.newpipe.error import android.os.Parcelable import androidx.annotation.StringRes +import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize import org.schabi.newpipe.R import org.schabi.newpipe.extractor.Info @@ -21,11 +22,14 @@ class ErrorInfo( val userAction: UserAction, val serviceName: String, val request: String, - val messageStringId: Int, - @Transient // no need to store throwable, all data for report is in other variables - var throwable: Throwable? = null + val messageStringId: Int ) : Parcelable { + // no need to store throwable, all data for report is in other variables + // also, the throwable might not be serializable, see TeamNewPipe/NewPipe#7302 + @IgnoredOnParcel + var throwable: Throwable? = null + private constructor( throwable: Throwable, userAction: UserAction, @@ -36,9 +40,10 @@ class ErrorInfo( userAction, serviceName, request, - getMessageStringId(throwable, userAction), - throwable - ) + getMessageStringId(throwable, userAction) + ) { + this.throwable = throwable + } private constructor( throwable: List, @@ -50,9 +55,10 @@ class ErrorInfo( userAction, serviceName, request, - getMessageStringId(throwable.firstOrNull(), userAction), - throwable.firstOrNull() - ) + getMessageStringId(throwable.firstOrNull(), userAction) + ) { + this.throwable = throwable.firstOrNull() + } // constructors with single throwable constructor(throwable: Throwable, userAction: UserAction, request: String) : diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt index e62aad1df..5fb8bff92 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt @@ -20,10 +20,6 @@ class ErrorUtil { /** * Reports a new error by starting a new activity. - *

- * Ensure that the data within errorInfo is serializable otherwise - * an exception will be thrown!

- * [EnsureExceptionSerializable] might help. * * @param context * @param errorInfo diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java index 8164c656d..8dbd7b2c5 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java @@ -90,8 +90,7 @@ public class SubscriptionsImportFragment extends BaseFragment { new ErrorInfo(new String[]{}, UserAction.SUBSCRIPTION_IMPORT_EXPORT, NewPipe.getNameOfService(currentServiceId), "Service does not support importing subscriptions", - R.string.general_error, - null)); + R.string.general_error)); activity.finish(); } } diff --git a/app/src/main/java/org/schabi/newpipe/player/playererror/PlayerErrorHandler.java b/app/src/main/java/org/schabi/newpipe/player/playererror/PlayerErrorHandler.java index d77073e00..ca9b4e7df 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playererror/PlayerErrorHandler.java +++ b/app/src/main/java/org/schabi/newpipe/player/playererror/PlayerErrorHandler.java @@ -12,7 +12,6 @@ import androidx.preference.PreferenceManager; import com.google.android.exoplayer2.ExoPlaybackException; import org.schabi.newpipe.R; -import org.schabi.newpipe.error.EnsureExceptionSerializable; import org.schabi.newpipe.error.ErrorInfo; import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.UserAction; @@ -70,7 +69,7 @@ public class PlayerErrorHandler { ErrorUtil.createNotification( context, new ErrorInfo( - EnsureExceptionSerializable.ensureSerializable(exception), + exception, UserAction.PLAY_STREAM, "Player error[type=" + exception.type + "] occurred while playing: " + info.getUrl(), diff --git a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java index 569c50001..39bdefbe0 100644 --- a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java +++ b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java @@ -583,7 +583,7 @@ public class MissionAdapter extends Adapter implements Handler.Callb ErrorUtil.createNotification(mContext, new ErrorInfo(ErrorInfo.Companion.throwableToStringList(mission.errObject), action, - service, request.toString(), reason, null)); + service, request.toString(), reason)); } public void clearFinishedDownloads(boolean delete) { From c8e2ab4c83f93a3ce3561a30f53f584af40dce2e Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 2 Dec 2021 14:24:45 +0100 Subject: [PATCH 5/8] Remove PlayerErrorHandler and correctly set ErrorInfo msg --- .../org/schabi/newpipe/error/ErrorInfo.kt | 8 ++ .../org/schabi/newpipe/player/Player.java | 33 ++++--- .../playererror/PlayerErrorHandler.java | 88 ------------------- app/src/main/res/values/settings_keys.xml | 2 - app/src/main/res/values/strings.xml | 2 - app/src/main/res/xml/debug_settings.xml | 8 -- 6 files changed, 24 insertions(+), 117 deletions(-) delete mode 100644 app/src/main/java/org/schabi/newpipe/player/playererror/PlayerErrorHandler.java diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt index ba1204e12..b2ba912ec 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt @@ -2,6 +2,7 @@ package org.schabi.newpipe.error import android.os.Parcelable import androidx.annotation.StringRes +import com.google.android.exoplayer2.ExoPlaybackException import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize import org.schabi.newpipe.R @@ -108,6 +109,13 @@ class ErrorInfo( throwable is ContentNotSupportedException -> R.string.content_not_supported throwable is DeobfuscateException -> R.string.youtube_signature_deobfuscation_error throwable is ExtractionException -> R.string.parsing_error + throwable is ExoPlaybackException -> { + when (throwable.type) { + ExoPlaybackException.TYPE_SOURCE -> R.string.player_stream_failure + ExoPlaybackException.TYPE_UNEXPECTED -> R.string.player_recoverable_failure + else -> R.string.player_unrecoverable_failure + } + } action == UserAction.UI_ERROR -> R.string.app_ui_crash action == UserAction.REQUESTED_COMMENTS -> R.string.error_unable_to_load_comments action == UserAction.SUBSCRIPTION_CHANGE -> R.string.subscription_change_failed diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index 2d8c1a830..ee09cb866 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -141,6 +141,9 @@ import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; import org.schabi.newpipe.databinding.PlayerBinding; import org.schabi.newpipe.databinding.PlayerPopupCloseOverlayBinding; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamSegment; @@ -165,7 +168,6 @@ import org.schabi.newpipe.player.playback.MediaSourceManager; import org.schabi.newpipe.player.playback.PlaybackListener; import org.schabi.newpipe.player.playback.PlayerMediaSession; import org.schabi.newpipe.player.playback.SurfaceHolderCallback; -import org.schabi.newpipe.player.playererror.PlayerErrorHandler; import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueueAdapter; import org.schabi.newpipe.player.playqueue.PlayQueueItem; @@ -268,8 +270,6 @@ public final class Player implements @Nullable private MediaSourceTag currentMetadata; @Nullable private Bitmap currentThumbnail; - @NonNull private PlayerErrorHandler playerErrorHandler; - /*////////////////////////////////////////////////////////////////////////// // Player //////////////////////////////////////////////////////////////////////////*/ @@ -413,8 +413,6 @@ public final class Player implements videoResolver = new VideoPlaybackResolver(context, dataSource, getQualityResolver()); audioResolver = new AudioPlaybackResolver(context, dataSource); - playerErrorHandler = new PlayerErrorHandler(context); - windowManager = ContextCompat.getSystemService(context, WindowManager.class); } @@ -2518,29 +2516,30 @@ public final class Player implements saveStreamProgressState(); + // create error notification + final ErrorInfo errorInfo; + if (currentMetadata == null) { + errorInfo = new ErrorInfo(error, UserAction.PLAY_STREAM, + "Player error[type=" + error.type + "] occurred, currentMetadata is null"); + } else { + errorInfo = new ErrorInfo(error, UserAction.PLAY_STREAM, + "Player error[type=" + error.type + "] occurred while playing " + + currentMetadata.getMetadata().getUrl(), + currentMetadata.getMetadata()); + } + ErrorUtil.createNotification(context, errorInfo); + switch (error.type) { case ExoPlaybackException.TYPE_SOURCE: processSourceError(error.getSourceException()); - playerErrorHandler.showPlayerError( - error, - currentMetadata.getMetadata(), - R.string.player_stream_failure); break; case ExoPlaybackException.TYPE_UNEXPECTED: - playerErrorHandler.showPlayerError( - error, - currentMetadata.getMetadata(), - R.string.player_recoverable_failure); setRecovery(); reloadPlayQueueManager(); break; case ExoPlaybackException.TYPE_REMOTE: case ExoPlaybackException.TYPE_RENDERER: default: - playerErrorHandler.showPlayerError( - error, - currentMetadata.getMetadata(), - R.string.player_unrecoverable_failure); onPlaybackShutdown(); break; } diff --git a/app/src/main/java/org/schabi/newpipe/player/playererror/PlayerErrorHandler.java b/app/src/main/java/org/schabi/newpipe/player/playererror/PlayerErrorHandler.java deleted file mode 100644 index ca9b4e7df..000000000 --- a/app/src/main/java/org/schabi/newpipe/player/playererror/PlayerErrorHandler.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.schabi.newpipe.player.playererror; - -import android.content.Context; -import android.util.Log; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; -import androidx.preference.PreferenceManager; - -import com.google.android.exoplayer2.ExoPlaybackException; - -import org.schabi.newpipe.R; -import org.schabi.newpipe.error.ErrorInfo; -import org.schabi.newpipe.error.ErrorUtil; -import org.schabi.newpipe.error.UserAction; -import org.schabi.newpipe.extractor.Info; - -/** - * Handles (exoplayer)errors that occur in the player. - */ -public class PlayerErrorHandler { - // This has to be <= 23 chars on devices running Android 7 or lower (API <= 25) - // or it fails with an IllegalArgumentException - // https://stackoverflow.com/a/54744028 - private static final String TAG = "PlayerErrorHandler"; - - @Nullable - private Toast errorToast; - - @NonNull - private final Context context; - - public PlayerErrorHandler(@NonNull final Context context) { - this.context = context; - } - - public void showPlayerError( - @NonNull final ExoPlaybackException exception, - @NonNull final Info info, - @StringRes final int textResId - ) { - // Hide existing toast message - if (errorToast != null) { - Log.d(TAG, "Trying to cancel previous player error error toast"); - errorToast.cancel(); - errorToast = null; - } - - if (shouldReportError()) { - try { - reportError(exception, info); - // When a report pops up we need no toast - return; - } catch (final Exception ex) { - Log.w(TAG, "Unable to report error:", ex); - // This will show the toast as fallback - } - } - - Log.d(TAG, "Showing player error toast"); - errorToast = Toast.makeText(context, textResId, Toast.LENGTH_SHORT); - errorToast.show(); - } - - private void reportError(@NonNull final ExoPlaybackException exception, - @NonNull final Info info) { - ErrorUtil.createNotification( - context, - new ErrorInfo( - exception, - UserAction.PLAY_STREAM, - "Player error[type=" + exception.type + "] occurred while playing: " - + info.getUrl(), - info - ) - ); - } - - private boolean shouldReportError() { - return PreferenceManager - .getDefaultSharedPreferences(context) - .getBoolean( - context.getString(R.string.report_player_errors_key), - false); - } -} diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index e2b797576..b88b2d064 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -89,8 +89,6 @@ @string/never - report_player_errors_key - seekbar_preview_thumbnail_key seekbar_preview_thumbnail_high_quality seekbar_preview_thumbnail_low_quality diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f47322b79..3319d5fb9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -53,8 +53,6 @@ Show \"Play with Kodi\" option Display an option to play a video via Kodi media center Crash the player - Report player errors - Reports player errors in full detail instead of showing a short-lived toast message (useful for diagnosing problems) Scale thumbnail to 1:1 aspect ratio Scale the video thumbnail shown in the notification from 16:9 to 1:1 aspect ratio (may introduce distortions) First action button diff --git a/app/src/main/res/xml/debug_settings.xml b/app/src/main/res/xml/debug_settings.xml index 5e2cc28ed..df1559c37 100644 --- a/app/src/main/res/xml/debug_settings.xml +++ b/app/src/main/res/xml/debug_settings.xml @@ -49,14 +49,6 @@ android:title="@string/show_image_indicators_title" app:iconSpaceReserved="false" /> - - Date: Thu, 2 Dec 2021 14:56:45 +0100 Subject: [PATCH 6/8] Add debug prefs to show error snackbar/notification --- .../settings/DebugSettingsFragment.java | 21 ++++++++++++++++ app/src/main/res/values/settings_keys.xml | 4 +++- app/src/main/res/values/strings.xml | 4 +++- app/src/main/res/xml/debug_settings.xml | 24 +++++++++++++------ 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/app/src/debug/java/org/schabi/newpipe/settings/DebugSettingsFragment.java b/app/src/debug/java/org/schabi/newpipe/settings/DebugSettingsFragment.java index 55b2c7708..f48be553f 100644 --- a/app/src/debug/java/org/schabi/newpipe/settings/DebugSettingsFragment.java +++ b/app/src/debug/java/org/schabi/newpipe/settings/DebugSettingsFragment.java @@ -5,6 +5,9 @@ import android.os.Bundle; import androidx.preference.Preference; import org.schabi.newpipe.R; +import org.schabi.newpipe.error.ErrorInfo; +import org.schabi.newpipe.error.ErrorUtil; +import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.util.PicassoHelper; import leakcanary.LeakCanary; @@ -20,10 +23,16 @@ public class DebugSettingsFragment extends BasePreferenceFragment { = findPreference(getString(R.string.show_image_indicators_key)); final Preference crashTheAppPreference = findPreference(getString(R.string.crash_the_app_key)); + final Preference showErrorSnackbarPreference + = findPreference(getString(R.string.show_error_snackbar_key)); + final Preference createErrorNotificationPreference + = findPreference(getString(R.string.create_error_notification_key)); assert showMemoryLeaksPreference != null; assert showImageIndicatorsPreference != null; assert crashTheAppPreference != null; + assert showErrorSnackbarPreference != null; + assert createErrorNotificationPreference != null; showMemoryLeaksPreference.setOnPreferenceClickListener(preference -> { startActivity(LeakCanary.INSTANCE.newLeakDisplayActivityIntent()); @@ -38,5 +47,17 @@ public class DebugSettingsFragment extends BasePreferenceFragment { crashTheAppPreference.setOnPreferenceClickListener(preference -> { throw new RuntimeException(); }); + + showErrorSnackbarPreference.setOnPreferenceClickListener(preference -> { + ErrorUtil.showUiErrorSnackbar(DebugSettingsFragment.this, + "Dummy", new RuntimeException("Dummy")); + return true; + }); + + createErrorNotificationPreference.setOnPreferenceClickListener(preference -> { + ErrorUtil.createNotification(requireContext(), + new ErrorInfo(new RuntimeException("Dummy"), UserAction.UI_ERROR, "Dummy")); + return true; + }); } } diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index b88b2d064..b6f76fce2 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -186,9 +186,11 @@ allow_disposed_exceptions_key show_original_time_ago_key disable_media_tunneling_key - crash_the_app_key show_image_indicators_key show_crash_the_player_key + crash_the_app_key + show_error_snackbar_key + create_error_notification_key theme diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3319d5fb9..4acd04d27 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -477,9 +477,11 @@ Disable media tunneling if you experience a black screen or stuttering on video playback Show image indicators Show Picasso colored ribbons on top of images indicating their source: red for network, blue for disk and green for memory - Crash the app Show \"crash the player\" Shows a crash option when using the player + Crash the app + Show an error snackbar + Create an error notification Import Import from diff --git a/app/src/main/res/xml/debug_settings.xml b/app/src/main/res/xml/debug_settings.xml index df1559c37..0052125a2 100644 --- a/app/src/main/res/xml/debug_settings.xml +++ b/app/src/main/res/xml/debug_settings.xml @@ -49,18 +49,28 @@ android:title="@string/show_image_indicators_title" app:iconSpaceReserved="false" /> + + - + + From 950956ebf22ef72c54c73cf30941bb1a87e6df3b Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 4 Dec 2021 10:45:15 +0100 Subject: [PATCH 7/8] Also show a toast on error notification since the notification is silent, also show a toast, otherwise the user is confused --- app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt | 5 +++++ app/src/main/res/values/strings.xml | 1 + 2 files changed, 6 insertions(+) diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt index 5fb8bff92..b766d91c6 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt @@ -8,6 +8,7 @@ import android.content.Intent import android.graphics.Color import android.os.Build import android.view.View +import android.widget.Toast import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment @@ -87,6 +88,10 @@ class ErrorUtil { ) notificationManager!!.notify(ERROR_REPORT_NOTIFICATION_ID, notificationBuilder.build()) + + // since the notification is silent, also show a toast, otherwise the user is confused + Toast.makeText(context, R.string.error_report_notification_toast, Toast.LENGTH_SHORT) + .show() } private fun getErrorActivityIntent(context: Context, errorInfo: ErrorInfo): Intent { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4acd04d27..cc518e2bb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -245,6 +245,7 @@ Give permission to display over other apps NewPipe encountered an error, tap to report + An error occurred, see the notification Sorry, that should not have happened. Guru Meditation. Report this error via e-mail From bb49b1cfb1cdb4fa04a8ec2fd472ccc01b34ae56 Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 7 Dec 2021 18:11:36 +0100 Subject: [PATCH 8/8] Add javadoc to ErrorUtil and ErrorActivity --- .../schabi/newpipe/error/ErrorActivity.java | 4 ++ .../org/schabi/newpipe/error/ErrorUtil.kt | 54 +++++++++++++++++-- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java index 07f736af3..bd8430296 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java @@ -52,6 +52,10 @@ import java.util.Arrays; * along with NewPipe. If not, see . */ +/** + * This activity is used to show error details and allow reporting them in various ways. Use {@link + * ErrorUtil#openActivity(Context, ErrorInfo)} to correctly open this activity. + */ public class ErrorActivity extends AppCompatActivity { // LOG TAGS public static final String TAG = ErrorActivity.class.toString(); diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt index b766d91c6..3fd743c69 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt @@ -15,27 +15,59 @@ import androidx.fragment.app.Fragment import com.google.android.material.snackbar.Snackbar import org.schabi.newpipe.R +/** + * This class contains all of the methods that should be used to let the user know that an error has + * occurred in the least intrusive way possible for each case. This class is for unexpected errors, + * for handled errors (e.g. network errors) use e.g. [ErrorPanelHelper] instead. + * - Use a snackbar if the exception is not critical and it happens in a place where a root view + * is available. + * - Use a notification if the exception happens inside a background service (player, subscription + * import, ...) or there is no activity/fragment from which to extract a root view. + * - Finally use the error activity only as a last resort in case the exception is critical and + * happens in an open activity (since the workflow would be interrupted anyway in that case). + */ class ErrorUtil { companion object { private const val ERROR_REPORT_NOTIFICATION_ID = 5340681 /** - * Reports a new error by starting a new activity. + * Starts a new error activity allowing the user to report the provided error. Only use this + * method directly as a last resort in case the exception is critical and happens in an open + * activity (since the workflow would be interrupted anyway in that case). So never use this + * for background services. * - * @param context - * @param errorInfo + * @param context the context to use to start the new activity + * @param errorInfo the error info to be reported */ @JvmStatic fun openActivity(context: Context, errorInfo: ErrorInfo) { context.startActivity(getErrorActivityIntent(context, errorInfo)) } + /** + * Show a bottom snackbar to the user, with a report button that opens the error activity. + * Use this method if the exception is not critical and it happens in a place where a root + * view is available. + * + * @param context will be used to obtain the root view if it is an [Activity]; if no root + * view can be found an error notification is shown instead + * @param errorInfo the error info to be reported + */ @JvmStatic fun showSnackbar(context: Context, errorInfo: ErrorInfo) { val rootView = if (context is Activity) context.findViewById(R.id.content) else null showSnackbar(context, rootView, errorInfo) } + /** + * Show a bottom snackbar to the user, with a report button that opens the error activity. + * Use this method if the exception is not critical and it happens in a place where a root + * view is available. + * + * @param fragment will be used to obtain the root view if it has a connected [Activity]; if + * no root view can be found an error notification is shown instead + * @param errorInfo the error info to be reported + */ @JvmStatic fun showSnackbar(fragment: Fragment, errorInfo: ErrorInfo) { var rootView = fragment.view @@ -45,16 +77,32 @@ class ErrorUtil { showSnackbar(fragment.requireContext(), rootView, errorInfo) } + /** + * Shortcut to calling [showSnackbar] with an [ErrorInfo] of type [UserAction.UI_ERROR] + */ @JvmStatic fun showUiErrorSnackbar(context: Context, request: String, throwable: Throwable) { showSnackbar(context, ErrorInfo(throwable, UserAction.UI_ERROR, request)) } + /** + * Shortcut to calling [showSnackbar] with an [ErrorInfo] of type [UserAction.UI_ERROR] + */ @JvmStatic fun showUiErrorSnackbar(fragment: Fragment, request: String, throwable: Throwable) { showSnackbar(fragment, ErrorInfo(throwable, UserAction.UI_ERROR, request)) } + /** + * Create an error notification. Tapping on the notification opens the error activity. Use + * this method if the exception happens inside a background service (player, subscription + * import, ...) or there is no activity/fragment from which to extract a root view. + * + * @param context the context to use to show the notification + * @param errorInfo the error info to be reported; the error message + * [ErrorInfo.messageStringId] will be shown in the notification + * description + */ @JvmStatic fun createNotification(context: Context, errorInfo: ErrorInfo) { val notificationManager =