diff --git a/CHANGELOG.md b/CHANGELOG.md index dc7a8a77..bf5164ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,52 @@ +# [0.94.0-dev.6](https://github.com/revanced/revanced-integrations/compare/v0.94.0-dev.5...v0.94.0-dev.6) (2023-01-28) + + +### Features + +* **youtube:** show toasts along exceptions ([#293](https://github.com/revanced/revanced-integrations/issues/293)) ([dbf1f3f](https://github.com/revanced/revanced-integrations/commit/dbf1f3f0ce0500752e5d6c4ce49d7d2b27cc6dc4)) + +# [0.94.0-dev.5](https://github.com/revanced/revanced-integrations/compare/v0.94.0-dev.4...v0.94.0-dev.5) (2023-01-28) + + +### Bug Fixes + +* **youtube/return-youtube-dislike:** do not fetch voting stats when watching shorts ([#302](https://github.com/revanced/revanced-integrations/issues/302)) ([7551f01](https://github.com/revanced/revanced-integrations/commit/7551f0104c463714749acc6abedbea5cd7afb52f)) + +# [0.94.0-dev.4](https://github.com/revanced/revanced-integrations/compare/v0.94.0-dev.3...v0.94.0-dev.4) (2023-01-28) + + +### Features + +* **youtube/general-ads:** remove hiding video shelf ([04147c1](https://github.com/revanced/revanced-integrations/commit/04147c17c98bccea27e0293a71ffccc97f5a155d)) + +# [0.94.0-dev.3](https://github.com/revanced/revanced-integrations/compare/v0.94.0-dev.2...v0.94.0-dev.3) (2023-01-22) + + +### Bug Fixes + +* **youtube/return-youtube-dislike:** gracefully exit if Vanced MicroG is missing or not running ([#303](https://github.com/revanced/revanced-integrations/issues/303)) ([03764bc](https://github.com/revanced/revanced-integrations/commit/03764bcc651c6b723a999a58ed9cc9d253075905)) + +# [0.94.0-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.94.0-dev.1...v0.94.0-dev.2) (2023-01-22) + + +### Features + +* **youtube/microg-support:** check if Vanced MicroG is running in the background ([#301](https://github.com/revanced/revanced-integrations/issues/301)) ([6e31b78](https://github.com/revanced/revanced-integrations/commit/6e31b7889a2488b3d61042111437a6ed4eec019c)) + +# [0.94.0-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.93.2-dev.1...v0.94.0-dev.1) (2023-01-22) + + +### Features + +* **youtube:** `open-links-externally` patch ([4cbe833](https://github.com/revanced/revanced-integrations/commit/4cbe8338b3f4ab49139168d7a3d0c9ebebf68952)) + +## [0.93.2-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.93.1...v0.93.2-dev.1) (2023-01-21) + + +### Bug Fixes + +* **youtube:** save new instead of default value ([#298](https://github.com/revanced/revanced-integrations/issues/298)) ([559bbf9](https://github.com/revanced/revanced-integrations/commit/559bbf9778f20ac0f5ce3af677230a1ec28a55ff)) + ## [0.93.1](https://github.com/revanced/revanced-integrations/compare/v0.93.0...v0.93.1) (2023-01-17) diff --git a/app/src/main/java/app/revanced/integrations/patches/GeneralAdsPatch.java b/app/src/main/java/app/revanced/integrations/patches/GeneralAdsPatch.java index d0c5379e..abfc8790 100644 --- a/app/src/main/java/app/revanced/integrations/patches/GeneralAdsPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/GeneralAdsPatch.java @@ -1,7 +1,6 @@ package app.revanced.integrations.patches; import android.view.View; - import app.revanced.integrations.adremover.AdRemoverAPI; import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.utils.LogHelper; @@ -32,7 +31,6 @@ public final class GeneralAdsPatch extends Filter { var paidContent = new BlockRule(SettingsEnum.ADREMOVER_PAID_CONTENT_REMOVAL, "paid_content_overlay"); var merchandise = new BlockRule(SettingsEnum.ADREMOVER_MERCHANDISE_REMOVAL, "product_carousel"); var infoPanel = new BlockRule(SettingsEnum.ADREMOVER_INFO_PANEL_REMOVAL, "publisher_transparency_panel", "single_item_information_panel"); - var suggestions = new BlockRule(SettingsEnum.ADREMOVER_SUGGESTIONS_REMOVAL, "horizontal_video_shelf"); var latestPosts = new BlockRule(SettingsEnum.ADREMOVER_HIDE_LATEST_POSTS, "post_shelf"); var channelGuidelines = new BlockRule(SettingsEnum.ADREMOVER_HIDE_CHANNEL_GUIDELINES, "channel_guidelines_entry_banner"); var artistCard = new BlockRule(SettingsEnum.HIDE_ARTIST_CARD, "official_card"); @@ -69,7 +67,6 @@ public final class GeneralAdsPatch extends Filter { buttonedAd, communityPosts, paidContent, - suggestions, latestPosts, movieAds, chapterTeaser, @@ -115,7 +112,7 @@ public final class GeneralAdsPatch extends Filter { else result = BlockResult.UNBLOCKED; - log(String.format("%s (ID: %s): %s", result.message, identifier, path)); + LogHelper.printDebug(() -> String.format("%s (ID: %s): %s", result.message, identifier, path)); return result.filter; } @@ -144,7 +141,7 @@ public final class GeneralAdsPatch extends Filter { private static void hideView(SettingsEnum condition, View view) { if (!condition.getBoolean()) return; - log("Hiding view with setting: " + condition); + LogHelper.printDebug(() -> "Hiding view with setting: " + condition); AdRemoverAPI.HideViewWithLayout1dp(view); } @@ -167,7 +164,4 @@ public final class GeneralAdsPatch extends Filter { hideView(SettingsEnum.ADREMOVER_SHORTS_REMOVAL, view); } - private static void log(String message) { - LogHelper.printDebug(() -> message); - } } diff --git a/app/src/main/java/app/revanced/integrations/patches/HideCreateButtonPatch.java b/app/src/main/java/app/revanced/integrations/patches/HideCreateButtonPatch.java index 062ee960..c595a209 100644 --- a/app/src/main/java/app/revanced/integrations/patches/HideCreateButtonPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/HideCreateButtonPatch.java @@ -10,8 +10,7 @@ public class HideCreateButtonPatch { //Used by app.revanced.patches.youtube.layout.createbutton.patch.CreateButtonRemoverPatch public static void hideCreateButton(View view) { boolean hidden = SettingsEnum.HIDE_CREATE_BUTTON.getBoolean(); - String message = "Create button: " + (hidden ? "hidden" : "shown"); - LogHelper.printDebug(() -> message); + LogHelper.printDebug(() -> "Create button: " + (hidden ? "hidden" : "shown")); view.setVisibility(hidden ? View.GONE : View.VISIBLE); } } diff --git a/app/src/main/java/app/revanced/integrations/patches/HideShortsButtonPatch.java b/app/src/main/java/app/revanced/integrations/patches/HideShortsButtonPatch.java index ae2311b3..b70c251b 100644 --- a/app/src/main/java/app/revanced/integrations/patches/HideShortsButtonPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/HideShortsButtonPatch.java @@ -12,10 +12,9 @@ public class HideShortsButtonPatch { public static void hideShortsButton(View view) { if (lastPivotTab != null && lastPivotTab.name() == "TAB_SHORTS") { boolean hide = SettingsEnum.HIDE_SHORTS_BUTTON.getBoolean(); - String message = hide ? "Shorts button: hidden" : "Shorts button: shown"; - LogHelper.printDebug(() -> message); + LogHelper.printDebug(() -> hide ? "Shorts button: hidden" : "Shorts button: shown"); if (hide) { - view.setVisibility(hide ? View.GONE : View.VISIBLE); + view.setVisibility(View.GONE); } } } diff --git a/app/src/main/java/app/revanced/integrations/patches/MicroGSupport.java b/app/src/main/java/app/revanced/integrations/patches/MicroGSupport.java index f7aaaac0..bdb43e05 100644 --- a/app/src/main/java/app/revanced/integrations/patches/MicroGSupport.java +++ b/app/src/main/java/app/revanced/integrations/patches/MicroGSupport.java @@ -2,11 +2,14 @@ package app.revanced.integrations.patches; import static app.revanced.integrations.sponsorblock.StringRef.str; +import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.widget.Toast; +import java.util.Objects; + import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.utils.ReVancedUtils; @@ -14,21 +17,35 @@ public class MicroGSupport { private static final String MICROG_VENDOR = "com.mgoogle"; private static final String MICROG_PACKAGE_NAME = "com.mgoogle.android.gms"; private static final String VANCED_MICROG_DOWNLOAD_LINK = "https://github.com/TeamVanced/VancedMicroG/releases/latest"; + private static final String DONT_KILL_MY_APP_LINK = "https://dontkillmyapp.com"; + private static final Uri VANCED_MICROG_PROVIDER = Uri.parse("content://com.mgoogle.android.gsf.gservices/prefix"); + + private static void startIntent(Context context, String uriString, String message) { + Toast.makeText(context, message, Toast.LENGTH_LONG).show(); + + var intent = new Intent(Intent.ACTION_VIEW); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setData(Uri.parse(uriString)); + context.startActivity(intent); + } public static void checkAvailability() { - var context = ReVancedUtils.getContext(); - assert context != null; + var context = Objects.requireNonNull(ReVancedUtils.getContext()); + try { context.getPackageManager().getPackageInfo(MICROG_PACKAGE_NAME, PackageManager.GET_ACTIVITIES); - LogHelper.printDebug(() -> "MicroG is installed on the device"); } catch (PackageManager.NameNotFoundException exception) { - LogHelper.printException(() -> ("MicroG was not found"), exception); - Toast.makeText(context, str("microg_not_installed_warning"), Toast.LENGTH_LONG).show(); + LogHelper.printInfo(() -> "Vanced MicroG was not found", exception); + startIntent(context, VANCED_MICROG_DOWNLOAD_LINK, str("microg_not_installed_warning")); - var intent = new Intent(Intent.ACTION_VIEW); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setData(Uri.parse(VANCED_MICROG_DOWNLOAD_LINK)); - context.startActivity(intent); + // Gracefully exit the app, so it does not crash. + System.exit(0); + } + + try (var client = context.getContentResolver().acquireContentProviderClient(VANCED_MICROG_PROVIDER)) { + if (client != null) return; + LogHelper.printInfo(() -> "Vanced MicroG is not running in the background"); + startIntent(context, DONT_KILL_MY_APP_LINK, str("microg_not_running_warning")); } } } diff --git a/app/src/main/java/app/revanced/integrations/patches/OpenLinksExternallyPatch.java b/app/src/main/java/app/revanced/integrations/patches/OpenLinksExternallyPatch.java new file mode 100644 index 00000000..4f5ce40b --- /dev/null +++ b/app/src/main/java/app/revanced/integrations/patches/OpenLinksExternallyPatch.java @@ -0,0 +1,19 @@ +package app.revanced.integrations.patches; + +import app.revanced.integrations.settings.SettingsEnum; + +public class OpenLinksExternallyPatch { + /** + * Override 'android.support.customtabs.action.CustomTabsService', + * in order to open links in the default browser. This is done by returning an empty string, + * for the service that handles custom tabs in the Android support library + * which opens links in the default service instead. + * + * @param original The original custom tabs service. + * @return The new, default service to open links with or the original service. + */ + public static String enableExternalBrowser(String original) { + if (SettingsEnum.ENABLE_EXTERNAL_BROWSER.getBoolean()) original = ""; + return original; + } +} diff --git a/app/src/main/java/app/revanced/integrations/patches/PlayerTypeHookPatch.java b/app/src/main/java/app/revanced/integrations/patches/PlayerTypeHookPatch.java index 5173cf48..3e31d5ed 100644 --- a/app/src/main/java/app/revanced/integrations/patches/PlayerTypeHookPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/PlayerTypeHookPatch.java @@ -2,8 +2,8 @@ package app.revanced.integrations.patches; import androidx.annotation.Nullable; -import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.shared.PlayerType; +import app.revanced.integrations.utils.LogHelper; /** * Hook receiver class for 'player-type-hook' patch @@ -24,7 +24,9 @@ public class PlayerTypeHookPatch { // update current player type final PlayerType newType = PlayerType.safeParseFromString(type.toString()); - if (newType != null) { + if (newType == null) { + LogHelper.printException(() -> "Unknown PlayerType encountered: " + type); + } else { PlayerType.setCurrent(newType); LogHelper.printDebug(() -> "YouTubePlayerOverlaysLayout player type was updated to " + newType); } diff --git a/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java b/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java index e25744c7..4c02a3d3 100644 --- a/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java +++ b/app/src/main/java/app/revanced/integrations/patches/VideoInformation.java @@ -36,7 +36,7 @@ public final class VideoInformation { seekMethod = thisRef.getClass().getMethod(SEEK_METHOD_NAME, Long.TYPE); seekMethod.setAccessible(true); } catch (NoSuchMethodException ex) { - LogHelper.printDebug(() -> "Failed to initialize: " + ex.getMessage()); + LogHelper.printException(() -> "Failed to initialize", ex); } } @@ -87,7 +87,7 @@ public final class VideoInformation { LogHelper.printDebug(() -> "Seeking to " + millisecond); seekMethod.invoke(playerController.get(), millisecond); } catch (Exception ex) { - LogHelper.printDebug(() -> "Failed to seek: " + ex.getMessage()); + LogHelper.printException(() -> "Failed to seek", ex); } }); } diff --git a/app/src/main/java/app/revanced/integrations/patches/playback/quality/RememberVideoQualityPatch.java b/app/src/main/java/app/revanced/integrations/patches/playback/quality/RememberVideoQualityPatch.java index d58d8a31..3a883967 100644 --- a/app/src/main/java/app/revanced/integrations/patches/playback/quality/RememberVideoQualityPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/playback/quality/RememberVideoQualityPatch.java @@ -1,5 +1,6 @@ package app.revanced.integrations.patches.playback.quality; +import android.annotation.SuppressLint; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; @@ -26,24 +27,25 @@ public class RememberVideoQualityPatch { if (isConnectedWifi(context)) { try { SharedPrefHelper.saveString(SharedPrefHelper.SharedPrefNames.REVANCED_PREFS, "wifi_quality", defaultQuality + ""); + String message = "Changing default Wi-Fi quality to: " + defaultQuality; + LogHelper.printDebug(() -> message); + Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); } catch (Exception ex) { - LogHelper.printException(() -> ("Failed to change default WI-FI quality:" + ex)); - Toast.makeText(context, "Failed to change default WI-FI quality:", Toast.LENGTH_SHORT).show(); + LogHelper.printException(() -> "Failed to change default WI-FI quality", ex); } - LogHelper.printDebug(() -> "Changing default Wi-Fi quality to: " + defaultQuality); - Toast.makeText(context, "Changing default Wi-Fi quality to: " + defaultQuality, Toast.LENGTH_SHORT).show(); } else if (isConnectedMobile(context)) { try { SharedPrefHelper.saveString(SharedPrefHelper.SharedPrefNames.REVANCED_PREFS, "mobile_quality", defaultQuality + ""); + String message = "Changing default mobile data quality to:" + defaultQuality; + LogHelper.printDebug(() -> message); + Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); } catch (Exception ex) { - LogHelper.printDebug(() -> "Failed to change default mobile data quality" + ex); - Toast.makeText(context, "Failed to change default mobile data quality", Toast.LENGTH_SHORT).show(); + LogHelper.printException(() -> "Failed to change default mobile data quality", ex); } - LogHelper.printDebug(() -> "Changing default mobile data quality to:" + defaultQuality); - Toast.makeText(context, "Changing default mobile data quality to:" + defaultQuality, Toast.LENGTH_SHORT).show(); } else { - LogHelper.printDebug(() -> "No internet connection."); - Toast.makeText(context, "No internet connection.", Toast.LENGTH_SHORT).show(); + String message = "No internet connection."; + LogHelper.printDebug(() -> message); + Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); } userChangedQuality = false; } @@ -88,7 +90,7 @@ public class RememberVideoQualityPatch { LogHelper.printDebug(() -> "Quality: " + qualityToLog); Context context = ReVancedUtils.getContext(); if (context == null) { - LogHelper.printException(() -> ("Context is null or settings not initialized, returning quality: " + qualityToLog)); + LogHelper.printException(() -> "Context is null or settings not initialized, returning quality: " + qualityToLog); return quality; } if (isConnectedWifi(context)) { @@ -129,8 +131,7 @@ public class RememberVideoQualityPatch { LogHelper.printDebug(() -> "Quality changed to: " + qualityIndex); return qualityIndex; } catch (Exception ex) { - LogHelper.printException(() -> ("Failed to set quality"), ex); - Toast.makeText(context, "Failed to set quality", Toast.LENGTH_SHORT).show(); + LogHelper.printException(() -> "Failed to set quality", ex); return qualityIndex; } } @@ -147,6 +148,7 @@ public class RememberVideoQualityPatch { newVideo = true; } + @SuppressLint("MissingPermission") private static NetworkInfo getNetworkInfo(Context context) { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); return cm.getActiveNetworkInfo(); diff --git a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java index 89e2463c..ab324401 100644 --- a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java +++ b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/ReturnYouTubeDislike.java @@ -2,7 +2,6 @@ package app.revanced.integrations.returnyoutubedislike; import static app.revanced.integrations.sponsorblock.StringRef.str; -import android.content.Context; import android.icu.text.CompactDecimalFormat; import android.os.Build; import android.text.Spannable; @@ -13,7 +12,6 @@ import android.text.style.CharacterStyle; import android.text.style.ForegroundColorSpan; import android.text.style.RelativeSizeSpan; import android.text.style.ScaleXSpan; -import android.util.DisplayMetrics; import androidx.annotation.GuardedBy; import androidx.annotation.Nullable; @@ -31,6 +29,7 @@ import java.util.concurrent.atomic.AtomicReference; import app.revanced.integrations.returnyoutubedislike.requests.RYDVoteData; import app.revanced.integrations.returnyoutubedislike.requests.ReturnYouTubeDislikeApi; import app.revanced.integrations.settings.SettingsEnum; +import app.revanced.integrations.shared.PlayerType; import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.utils.ReVancedUtils; import app.revanced.integrations.utils.SharedPrefHelper; @@ -96,7 +95,16 @@ public class ReturnYouTubeDislike { private static NumberFormat dislikePercentageFormatter; public static void onEnabledChange(boolean enabled) { - isEnabled = enabled; + synchronized (videoIdLockObject) { + isEnabled = enabled; + if (!enabled) { + // must clear old values, to protect against using stale data + // if the user re-enables RYD while watching a video + LogHelper.printDebug(() -> "Clearing previously fetched RYD vote data"); + currentVideoId = null; + voteFetchFuture = null; + } + } } private static String getCurrentVideoId() { @@ -117,8 +125,12 @@ public class ReturnYouTubeDislike { if (!isEnabled) return; try { Objects.requireNonNull(videoId); - LogHelper.printDebug(() -> "New video loaded: " + videoId); - + PlayerType currentPlayerType = PlayerType.getCurrent(); + if (currentPlayerType == PlayerType.INLINE_MINIMAL) { + LogHelper.printDebug(() -> "Ignoring inline playback of video: "+ videoId); + return; + } + LogHelper.printDebug(() -> " new video loaded: " + videoId + " playerType: " + currentPlayerType); synchronized (videoIdLockObject) { currentVideoId = videoId; // no need to wrap the call in a try/catch, @@ -157,6 +169,10 @@ public class ReturnYouTubeDislike { long fetchStartTime = 0; try { Future fetchFuture = getVoteFetchFuture(); + if (fetchFuture == null) { + LogHelper.printDebug(() -> "fetch future not available (user enabled RYD while video was playing?)"); + return; + } if (SettingsEnum.DEBUG.getBoolean() && !fetchFuture.isDone()) { fetchStartTime = System.currentTimeMillis(); } @@ -175,8 +191,7 @@ public class ReturnYouTubeDislike { if (updateDislike(textRef, isSegmentedButton, votingData)) { LogHelper.printDebug(() -> "Updated dislike span to: " + textRef.get()); } else { - LogHelper.printDebug(() -> "Ignoring dislike span: " + textRef.get() - + " that appears to already show voting data: " + votingData); + LogHelper.printDebug(() -> "Ignoring already updated dislike span: " + textRef.get()); } } catch (Exception ex) { LogHelper.printException(() -> "Error while trying to update dislikes", ex); @@ -187,12 +202,24 @@ public class ReturnYouTubeDislike { if (!isEnabled) return; try { Objects.requireNonNull(vote); + + if (PlayerType.getCurrent() == PlayerType.NONE) { // should occur if shorts is playing + LogHelper.printDebug(() -> "Ignoring vote during Shorts playback"); + return; + } if (SharedPrefHelper.getBoolean(SharedPrefHelper.SharedPrefNames.YOUTUBE, "user_signed_out", true)) { + LogHelper.printDebug(() -> "User is logged out, ignoring voting"); return; } // Must make a local copy of videoId, since it may change between now and when the vote thread runs String videoIdToVoteFor = getCurrentVideoId(); + if (videoIdToVoteFor == null) { + // user enabled RYD after starting playback of a video + LogHelper.printException(() -> "Cannot vote, current video is is null (user enabled RYD while video was playing?)", + null, str("revanced_ryd_failure_ryd_enabled_while_playing_video_then_user_voted")); + return; + } voteSerialExecutor.execute(() -> { // must wrap in try/catch to properly log exceptions @@ -278,9 +305,6 @@ public class ReturnYouTubeDislike { // // Change the "Likes" string to show that likes and dislikes are hidden // - LogHelper.printDebug(() -> "Like count is hidden by video creator. " - + "RYD does not provide data for videos with hidden likes."); - String hiddenMessageString = str("revanced_ryd_video_likes_hidden_by_video_owner"); if (hiddenMessageString.equals(oldLikesString)) { return false; @@ -449,7 +473,6 @@ public class ReturnYouTubeDislike { private static String formatDislikeCount(long dislikeCount) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - String formatted; synchronized (ReturnYouTubeDislike.class) { // number formatter is not thread safe, must synchronize if (dislikeCountFormatter == null) { // Note: Java number formatters will use the locale specific number characters. @@ -460,18 +483,15 @@ public class ReturnYouTubeDislike { LogHelper.printDebug(() -> "Locale: " + locale); dislikeCountFormatter = CompactDecimalFormat.getInstance(locale, CompactDecimalFormat.CompactStyle.SHORT); } - formatted = dislikeCountFormatter.format(dislikeCount); + return dislikeCountFormatter.format(dislikeCount); } - LogHelper.printDebug(() -> "Dislike count: " + dislikeCount + " formatted as: " + formatted); - return formatted; } - // never will be reached, as the oldest supported YouTube app requires Android N or greater + // will never be reached, as the oldest supported YouTube app requires Android N or greater return String.valueOf(dislikeCount); } private static String formatDislikePercentage(float dislikePercentage) { - String formatted; synchronized (ReturnYouTubeDislike.class) { // number formatter is not thread safe, must synchronize if (dislikePercentageFormatter == null) { Locale locale = ReVancedUtils.getContext().getResources().getConfiguration().locale; @@ -483,10 +503,8 @@ public class ReturnYouTubeDislike { } else { dislikePercentageFormatter.setMaximumFractionDigits(1); // show up to 1 digit precision } - formatted = dislikePercentageFormatter.format(dislikePercentage); + return dislikePercentageFormatter.format(dislikePercentage); } - LogHelper.printDebug(() -> "Dislike percentage: " + dislikePercentage + " formatted as: " + formatted); - return formatted; } @@ -500,6 +518,7 @@ public class ReturnYouTubeDislike { */ private static volatile long totalTimeUIWaitedOnNetworkCalls; + @SuppressWarnings("NonAtomicOperationOnVolatileField") private static void recordTimeUISpentWaitingForNetworkCall(long timeUIWaitStarted) { if (timeUIWaitStarted == 0 || !SettingsEnum.DEBUG.getBoolean()) { return; diff --git a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java index f0850c1a..7729c653 100644 --- a/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java +++ b/app/src/main/java/app/revanced/integrations/returnyoutubedislike/requests/ReturnYouTubeDislikeApi.java @@ -185,11 +185,15 @@ public class ReturnYouTubeDislikeApi { lastTimeRateLimitWasHit = System.currentTimeMillis(); LogHelper.printDebug(() -> "API rate limit was hit. Stopping API calls for the next " + RATE_LIMIT_BACKOFF_SECONDS + " seconds"); + ReVancedUtils.runOnMainThread(() -> { // must show toasts on main thread + Toast.makeText(ReVancedUtils.getContext(), str("revanced_ryd_failure_client_rate_limit_requested"), Toast.LENGTH_LONG).show(); + }); return true; } return false; } + @SuppressWarnings("NonAtomicOperationOnVolatileField") // do not want to pay performance cost of full synchronization for debug fields that are only estimates anyways private static void updateStatistics(long timeNetworkCallStarted, long timeNetworkCallEnded, boolean connectionError, boolean rateLimitHit) { if (connectionError && rateLimitHit) { throw new IllegalArgumentException("both connection error and rate limit parameter were true"); @@ -202,11 +206,9 @@ public class ReturnYouTubeDislikeApi { if (connectionError) { fetchCallResponseTimeLast = responseTimeOfFetchCall; fetchCallNumberOfFailures++; - showToast("revanced_ryd_failure_connection_timeout"); } else if (rateLimitHit) { fetchCallResponseTimeLast = FETCH_CALL_RESPONSE_TIME_VALUE_RATE_LIMIT; numberOfRateLimitRequestsEncountered++; - showToast("revanced_ryd_failure_client_rate_limit_requested"); } else { fetchCallResponseTimeLast = responseTimeOfFetchCall; } @@ -226,6 +228,7 @@ public class ReturnYouTubeDislikeApi { LogHelper.printDebug(() -> "Fetching votes for: " + videoId); final long timeNetworkCallStarted = System.currentTimeMillis(); + String connectionErrorMessageStringKey = "revanced_ryd_failure_connection_timeout"; try { HttpURLConnection connection = getRYDConnectionFromRoute(ReturnYouTubeDislikeRoutes.GET_DISLIKES, videoId); // request headers, as per https://returnyoutubedislike.com/docs/fetching @@ -261,12 +264,12 @@ public class ReturnYouTubeDislikeApi { // fall thru to update statistics } } else { - LogHelper.printDebug(() -> "Failed to fetch votes for video: " + videoId - + " response code was: " + responseCode); + LogHelper.printException(() -> "Failed to fetch votes for video: " + videoId + + " response code was: " + responseCode, null, str(connectionErrorMessageStringKey)); connection.disconnect(); // something went wrong, might as well disconnect } } catch (Exception ex) { // connection timed out, response timeout, or some other network error - LogHelper.printException(() -> "Failed to fetch votes", ex); + LogHelper.printException(() -> "Failed to fetch votes", ex, str(connectionErrorMessageStringKey)); } updateStatistics(timeNetworkCallStarted, System.currentTimeMillis(), true, false); @@ -304,13 +307,12 @@ public class ReturnYouTubeDislikeApi { String solution = solvePuzzle(challenge, difficulty); return confirmRegistration(userId, solution); } - LogHelper.printDebug(() -> "Failed to register new user: " + userId + LogHelper.printException(() -> "Failed to register new user: " + userId + " response code was: " + responseCode); connection.disconnect(); } catch (Exception ex) { LogHelper.printException(() -> "Failed to register user", ex); } - showToast("revanced_ryd_failure_register_user"); return null; } @@ -344,10 +346,10 @@ public class ReturnYouTubeDislikeApi { LogHelper.printDebug(() -> "Registration confirmation successful for user: " + userId); return userId; } - LogHelper.printDebug(() -> "Failed to confirm registration for user: " + userId + LogHelper.printException(() -> "Failed to confirm registration for user: " + userId + " solution: " + solution + " response string was: " + result); } else { - LogHelper.printDebug(() -> "Failed to confirm registration for user: " + userId + LogHelper.printException(() -> "Failed to confirm registration for user: " + userId + " solution: " + solution + " response code was: " + responseCode); } connection.disconnect(); // something went wrong, might as well disconnect @@ -355,8 +357,6 @@ public class ReturnYouTubeDislikeApi { LogHelper.printException(() -> "Failed to confirm registration for user: " + userId + "solution: " + solution, ex); } - showToast("revanced_ryd_failure_confirm_user"); - return null; } @@ -395,14 +395,13 @@ public class ReturnYouTubeDislikeApi { String solution = solvePuzzle(challenge, difficulty); return confirmVote(videoId, userId, solution); } - LogHelper.printDebug(() -> "Failed to send vote for video: " + videoId + LogHelper.printException(() -> "Failed to send vote for video: " + videoId + " userId: " + userId + " vote: " + vote + " response code was: " + responseCode); connection.disconnect(); // something went wrong, might as well disconnect } catch (Exception ex) { LogHelper.printException(() -> "Failed to send vote for video: " + videoId + " user: " + userId + " vote: " + vote, ex); } - showToast("revanced_ryd_failure_send_vote_failed"); return false; } @@ -438,10 +437,10 @@ public class ReturnYouTubeDislikeApi { LogHelper.printDebug(() -> "Vote confirm successful for video: " + videoId); return true; } - LogHelper.printDebug(() -> "Failed to confirm vote for video: " + videoId + LogHelper.printException(() -> "Failed to confirm vote for video: " + videoId + " user: " + userId + " solution: " + solution + " response string was: " + result); } else { - LogHelper.printDebug(() -> "Failed to confirm vote for video: " + videoId + LogHelper.printException(() -> "Failed to confirm vote for video: " + videoId + " user: " + userId + " solution: " + solution + " response code was: " + responseCode); } connection.disconnect(); // something went wrong, might as well disconnect @@ -449,16 +448,9 @@ public class ReturnYouTubeDislikeApi { LogHelper.printException(() -> "Failed to confirm vote for video: " + videoId + " user: " + userId + " solution: " + solution, ex); } - showToast("revanced_ryd_failure_confirm_vote_failed"); return false; } - private static void showToast(String toastTextStringKey) { - ReVancedUtils.runOnMainThread(() -> { // must show toasts on main thread - Toast.makeText(ReVancedUtils.getContext(), str(toastTextStringKey), Toast.LENGTH_LONG).show(); - }); - } - private static void applyCommonPostRequestSettings(HttpURLConnection connection) throws ProtocolException { connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/json"); @@ -477,7 +469,7 @@ public class ReturnYouTubeDislikeApi { byte[] decodedChallenge = Base64.decode(challenge, Base64.NO_WRAP); byte[] buffer = new byte[20]; - for (int i = 4; i < 20; i++) { + for (int i = 4; i < 20; i++) { // FIXME replace with System.arrayCopy buffer[i] = decodedChallenge[i - 4]; } diff --git a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java index 8d376386..10a73ece 100644 --- a/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java +++ b/app/src/main/java/app/revanced/integrations/settings/SettingsEnum.java @@ -1,14 +1,13 @@ package app.revanced.integrations.settings; import android.content.Context; - -import java.util.ArrayList; -import java.util.List; - import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.utils.ReVancedUtils; import app.revanced.integrations.utils.SharedPrefHelper; +import java.util.ArrayList; +import java.util.List; + public enum SettingsEnum { //Download Settings // TODO: DOWNLOAD_PATH("revanced_download_path", Environment.getExternalStorageDirectory().getPath() + "/Download", ReturnType.STRING), @@ -47,7 +46,6 @@ public enum SettingsEnum { ADREMOVER_INFO_PANEL_REMOVAL("revanced_adremover_info_panel", true, ReturnType.BOOLEAN), ADREMOVER_MEDICAL_PANEL_REMOVAL("revanced_adremover_medical_panel", true, ReturnType.BOOLEAN), ADREMOVER_PAID_CONTENT_REMOVAL("revanced_adremover_paid_content", true, ReturnType.BOOLEAN), - ADREMOVER_SUGGESTIONS_REMOVAL("revanced_adremover_hide_suggestions", true, ReturnType.BOOLEAN), ADREMOVER_HIDE_LATEST_POSTS("revanced_adremover_hide_latest_posts", true, ReturnType.BOOLEAN), ADREMOVER_HIDE_CHANNEL_GUIDELINES("revanced_adremover_hide_channel_guidelines", true, ReturnType.BOOLEAN), ADREMOVER_SELF_SPONSOR_REMOVAL("revanced_adremover_self_sponsor", true, ReturnType.BOOLEAN), @@ -100,6 +98,7 @@ public enum SettingsEnum { ENABLE_MINIMIZED_PLAYBACK("revanced_enable_minimized_playback", true, ReturnType.BOOLEAN), OPEN_LINKS_DIRECTLY("revanced_uri_redirect", true, ReturnType.BOOLEAN, true), DISABLE_ZOOM_HAPTICS("revanced_disable_zoom_haptics", true, ReturnType.BOOLEAN, false), + ENABLE_EXTERNAL_BROWSER("revanced_enable_external_browser", true, ReturnType.BOOLEAN, true), // Swipe controls ENABLE_SWIPE_BRIGHTNESS("revanced_enable_swipe_brightness", true, ReturnType.BOOLEAN), @@ -116,9 +115,10 @@ public enum SettingsEnum { PLAYBACK_MAX_BUFFER("revanced_pref_buffer_for_playback_ms", 2500, ReturnType.INTEGER), MAX_PLAYBACK_BUFFER_AFTER_REBUFFER("revanced_pref_buffer_for_playback_after_rebuffer_ms", 5000, ReturnType.INTEGER), - // ReVanced settings + // Debug settings DEBUG("revanced_debug_enabled", false, ReturnType.BOOLEAN), DEBUG_STACKTRACE("revanced_debug_stacktrace_enabled", false, ReturnType.BOOLEAN), + DEBUG_SHOW_TOAST_ON_ERROR("revanced_debug_toast_on_error_enabled", true, ReturnType.BOOLEAN), USE_DARK_THEME("app_theme_dark", false, ReturnType.BOOLEAN), @@ -224,7 +224,7 @@ public enum SettingsEnum { // // old/new settings where old is default off, and new has inverted value and is default on - SettingsEnum invertedSettingsToMigrate[][] = { + SettingsEnum[][] invertedSettingsToMigrate = { {DEPRECATED_FULLSCREEN_PANELS_SHOWN, HIDE_FULLSCREEN_PANELS}, {DEPRECATED_CREATE_BUTTON_ENABLED, HIDE_CREATE_BUTTON}, {DEPRECATED_SHORTS_BUTTON_SHOWN, HIDE_SHORTS_BUTTON}, @@ -234,7 +234,7 @@ public enum SettingsEnum { {DEPRECATED_BRANDING_SHOWN, HIDE_VIDEO_WATERMARK}, {DEPRECATED_REMEMBER_VIDEO_QUALITY, REMEMBER_VIDEO_QUALITY_LAST_SELECTED}, }; - for (SettingsEnum oldNewSetting[] : invertedSettingsToMigrate) { + for (SettingsEnum[] oldNewSetting : invertedSettingsToMigrate) { // by default, old setting was default off // migrate to new setting of default on SettingsEnum oldSetting = oldNewSetting[0]; @@ -253,7 +253,7 @@ public enum SettingsEnum { // // migrate preference of prior 'default off' settings, into replacement setting with different path name but otherwise is identical // - SettingsEnum renamedSettings[][] = { + SettingsEnum[][] renamedSettings = { {DEPRECATED_HIDE_MIX_PLAYLISTS, HIDE_MIX_PLAYLISTS}, {DEPRECATED_HIDE_LIKE_BUTTON, HIDE_LIKE_BUTTON}, {DEPRECATED_HIDE_DISLIKE_BUTTON, HIDE_DISLIKE_BUTTON}, @@ -262,7 +262,7 @@ public enum SettingsEnum { {DEPRECATED_HIDE_ACTION_BUTTON, HIDE_ACTION_BUTTON}, {DEPRECATED_HIDE_SHARE_BUTTON, HIDE_SHARE_BUTTON}, }; - for (SettingsEnum oldNewSetting[] : renamedSettings) { + for (SettingsEnum[] oldNewSetting : renamedSettings) { SettingsEnum oldSetting = oldNewSetting[0]; SettingsEnum newSetting = oldNewSetting[1]; @@ -304,7 +304,7 @@ public enum SettingsEnum { defaultValue = SharedPrefHelper.getString(setting.sharedPref, path, (String) defaultValue); break; default: - LogHelper.printException(() -> ("Setting does not have a valid Type. Name is: " + setting.name())); + LogHelper.printException(() -> "Setting does not have a valid Type. Name is: " + setting.name()); break; } setting.setValue(defaultValue); @@ -337,28 +337,28 @@ public enum SettingsEnum { Context context = ReVancedUtils.getContext(); if (context == null) { - LogHelper.printException(() -> ("Context on SaveValue is null!")); + LogHelper.printException(() -> "Context on SaveValue is null!"); return; } switch (getReturnType()) { case FLOAT: - SharedPrefHelper.saveFloat(sharedPref, path, (float) defaultValue); + SharedPrefHelper.saveFloat(sharedPref, path, (float) newValue); break; case LONG: - SharedPrefHelper.saveLong(sharedPref, path, (long) defaultValue); + SharedPrefHelper.saveLong(sharedPref, path, (long) newValue); break; case BOOLEAN: SharedPrefHelper.saveBoolean(sharedPref, path, (boolean) newValue); break; case INTEGER: - SharedPrefHelper.saveInt(sharedPref, path, (int) defaultValue); + SharedPrefHelper.saveInt(sharedPref, path, (int) newValue); break; case STRING: - SharedPrefHelper.saveString(sharedPref, path, (String) defaultValue); + SharedPrefHelper.saveString(sharedPref, path, (String) newValue); break; default: - LogHelper.printException(() -> ("Setting does not have a valid Type. Name is: " + name())); + LogHelper.printException(() -> "Setting does not have a valid Type. Name is: " + name()); break; } diff --git a/app/src/main/java/app/revanced/integrations/settingsmenu/ReVancedSettingActivity.java b/app/src/main/java/app/revanced/integrations/settingsmenu/ReVancedSettingActivity.java index 9b46b338..c511f1a6 100644 --- a/app/src/main/java/app/revanced/integrations/settingsmenu/ReVancedSettingActivity.java +++ b/app/src/main/java/app/revanced/integrations/settingsmenu/ReVancedSettingActivity.java @@ -7,6 +7,8 @@ import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.TextView; +import androidx.annotation.Nullable; + import com.google.android.libraries.social.licenses.LicenseActivity; import app.revanced.integrations.utils.LogHelper; @@ -44,15 +46,23 @@ public class ReVancedSettingActivity { } try { - getTextView((ViewGroup) base.findViewById(getIdentifier("toolbar", "id"))).setText(preferenceIdentifier); + TextView toolbar = getTextView((ViewGroup) base.findViewById(getIdentifier("toolbar", "id"))); + if (toolbar == null) { + // FIXME + // https://github.com/revanced/revanced-patches/issues/1384 + LogHelper.printDebug(() -> "Could not find toolbar"); + } else { + toolbar.setText(preferenceIdentifier); + } } catch (Exception e) { - LogHelper.printException(() -> ("Couldn't set Toolbar title"), e); + LogHelper.printException(() -> "Could not set Toolbar title", e); } base.getFragmentManager().beginTransaction().replace(getIdentifier("revanced_settings_fragments", "id"), preferenceFragment).commit(); } + @Nullable public static T getView(Class typeClass, ViewGroup viewGroup) { if (viewGroup == null) { return null; @@ -67,10 +77,12 @@ public class ReVancedSettingActivity { return null; } + @Nullable public static ImageButton getImageButton(ViewGroup viewGroup) { return getView(ImageButton.class, viewGroup); } + @Nullable public static TextView getTextView(ViewGroup viewGroup) { return getView(TextView.class, viewGroup); } diff --git a/app/src/main/java/app/revanced/integrations/settingsmenu/ReVancedSettingsFragment.java b/app/src/main/java/app/revanced/integrations/settingsmenu/ReVancedSettingsFragment.java index ea81036e..c7a3535f 100644 --- a/app/src/main/java/app/revanced/integrations/settingsmenu/ReVancedSettingsFragment.java +++ b/app/src/main/java/app/revanced/integrations/settingsmenu/ReVancedSettingsFragment.java @@ -66,12 +66,12 @@ public class ReVancedSettingsFragment extends PreferenceFragment { value = Integer.parseInt(editPref.getText()); break; default: - LogHelper.printException(() -> ("Setting has no valid return type! " + setting.getReturnType())); + LogHelper.printException(() -> "Setting has no valid return type! " + setting.getReturnType()); break; } setting.setValue(value); } else { - LogHelper.printException(() -> ("Setting cannot be handled! " + pref.toString())); + LogHelper.printException(() -> "Setting cannot be handled: " + pref.getClass() + " " + pref.toString()); } if (ReVancedUtils.getContext() != null && settingsInitialized && setting.shouldRebootOnChange()) { @@ -96,7 +96,7 @@ public class ReVancedSettingsFragment extends PreferenceFragment { this.settingsInitialized = true; } catch (Throwable th) { - LogHelper.printException(() -> ("Error during onCreate()"), th); + LogHelper.printException(() -> "Error during onCreate()", th); } } @@ -111,7 +111,7 @@ public class ReVancedSettingsFragment extends PreferenceFragment { private Preference findPreferenceOnScreen(CharSequence key) { if (key == null) { - LogHelper.printException(() -> ("Key cannot be null!")); + LogHelper.printException(() -> "Key cannot be null!"); return null; } Preference pref = null; @@ -144,7 +144,7 @@ public class ReVancedSettingsFragment extends PreferenceFragment { private String getPackageName() { Context context = ReVancedUtils.getContext(); if (context == null) { - LogHelper.printException(() -> ("Context is null, returning com.google.android.youtube!")); + LogHelper.printException(() -> "Context is null, returning com.google.android.youtube!"); return "com.google.android.youtube"; } String PACKAGE_NAME = context.getPackageName(); @@ -169,7 +169,7 @@ public class ReVancedSettingsFragment extends PreferenceFragment { Resources res = context.getResources(); return res.getString(res.getIdentifier(name, "string", context.getPackageName())); } catch (Throwable exception) { - LogHelper.printException(() -> ("Resource not found."), exception); + LogHelper.printException(() -> "Resource not found.", exception); return ""; } } diff --git a/app/src/main/java/app/revanced/integrations/shared/PlayerType.kt b/app/src/main/java/app/revanced/integrations/shared/PlayerType.kt index 2ea15366..561b3840 100644 --- a/app/src/main/java/app/revanced/integrations/shared/PlayerType.kt +++ b/app/src/main/java/app/revanced/integrations/shared/PlayerType.kt @@ -7,7 +7,7 @@ import app.revanced.integrations.utils.Event */ @Suppress("unused") enum class PlayerType { - NONE, + NONE, // this also includes when shorts are playing HIDDEN, WATCH_WHILE_MINIMIZED, WATCH_WHILE_MAXIMIZED, diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/PlayerController.java b/app/src/main/java/app/revanced/integrations/sponsorblock/PlayerController.java index 6d275177..bc5ae6d6 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/PlayerController.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/PlayerController.java @@ -1,17 +1,18 @@ package app.revanced.integrations.sponsorblock; -import static app.revanced.integrations.sponsorblock.SponsorBlockUtils.timeWithoutSegments; -import static app.revanced.integrations.sponsorblock.SponsorBlockUtils.videoHasSegments; - -import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; -import android.os.Handler; -import android.os.Looper; import android.view.View; import android.view.ViewGroup; +import app.revanced.integrations.patches.VideoInformation; +import app.revanced.integrations.settings.SettingsEnum; +import app.revanced.integrations.shared.PlayerType; +import app.revanced.integrations.sponsorblock.objects.SponsorSegment; +import app.revanced.integrations.sponsorblock.requests.SBRequester; +import app.revanced.integrations.utils.LogHelper; +import app.revanced.integrations.utils.ReVancedUtils; import java.lang.ref.WeakReference; import java.lang.reflect.Field; @@ -19,14 +20,9 @@ import java.util.Arrays; import java.util.Timer; import java.util.TimerTask; -import app.revanced.integrations.patches.VideoInformation; -import app.revanced.integrations.settings.SettingsEnum; -import app.revanced.integrations.sponsorblock.objects.SponsorSegment; -import app.revanced.integrations.sponsorblock.requests.SBRequester; -import app.revanced.integrations.utils.LogHelper; -import app.revanced.integrations.utils.ReVancedUtils; +import static app.revanced.integrations.sponsorblock.SponsorBlockUtils.timeWithoutSegments; +import static app.revanced.integrations.sponsorblock.SponsorBlockUtils.videoHasSegments; -@SuppressLint({"LongLogTag"}) public class PlayerController { private static final Timer sponsorTimer = new Timer("sponsor-skip-timer"); @@ -43,126 +39,149 @@ public class PlayerController { private static float sponsorBarThickness = 2f; private static TimerTask skipSponsorTask = null; - public static boolean shorts_playing = false; - public static String getCurrentVideoId() { return currentVideoId; } public static void setCurrentVideoId(final String videoId) { - if (videoId == null) { - currentVideoId = null; - sponsorSegmentsOfCurrentVideo = null; - return; - } - - SponsorBlockSettings.update(null); - - if (!SettingsEnum.SB_ENABLED.getBoolean()) { - currentVideoId = null; - return; - } - - if (videoId.equals(currentVideoId)) - return; - - currentVideoId = videoId; - sponsorSegmentsOfCurrentVideo = null; - LogHelper.printDebug(() -> "setCurrentVideoId: videoId=" + videoId); - - sponsorTimer.schedule(new TimerTask() { - @Override - public void run() { - executeDownloadSegments(currentVideoId); + try { + if (videoId == null) { + currentVideoId = null; + sponsorSegmentsOfCurrentVideo = null; + return; } - }, 0); + + // currently this runs every time a video is loaded (regardless if sponsorblock is turned on or off) + // FIXME: change this so if sponsorblock is disabled, then run this method exactly once and once only + SponsorBlockSettings.update(null); + + if (!SettingsEnum.SB_ENABLED.getBoolean()) { + currentVideoId = null; + return; + } + if (PlayerType.getCurrent() == PlayerType.NONE) { + LogHelper.printDebug(() -> "ignoring shorts video"); + currentVideoId = null; + return; + } + if (videoId.equals(currentVideoId)) + return; + + currentVideoId = videoId; + sponsorSegmentsOfCurrentVideo = null; + LogHelper.printDebug(() -> "setCurrentVideoId: videoId=" + videoId); + + sponsorTimer.schedule(new TimerTask() { + @Override + public void run() { + try { + executeDownloadSegments(currentVideoId); + } catch (Exception e) { + LogHelper.printException(() -> "Failed to download segments", e); + } + } + }, 0); + } catch (Exception ex) { + LogHelper.printException(() -> "setCurrentVideoId failure", ex); + } } /** * Called when creating some kind of youtube internal player controlled, every time when new video starts to play */ public static void initialize(Object _o) { - lastKnownVideoTime = 0; - SkipSegmentView.hide(); - NewSegmentHelperLayout.hide(); + try { + lastKnownVideoTime = 0; + SkipSegmentView.hide(); + NewSegmentHelperLayout.hide(); + } catch (Exception ex) { + LogHelper.printException(() -> "initialize failure", ex); + } } public static void executeDownloadSegments(String videoId) { - videoHasSegments = false; - timeWithoutSegments = ""; - if (shorts_playing) { - return; - } - SponsorSegment[] segments = SBRequester.getSegments(videoId); - Arrays.sort(segments); + try { + videoHasSegments = false; + timeWithoutSegments = ""; - for (SponsorSegment segment : segments) { - LogHelper.printDebug(() -> "Detected segment: " + segment.toString()); - } + SponsorSegment[] segments = SBRequester.getSegments(videoId); + Arrays.sort(segments); - sponsorSegmentsOfCurrentVideo = segments; - // new Handler(Looper.getMainLooper()).post(findAndSkipSegmentRunnable); + for (SponsorSegment segment : segments) { + LogHelper.printDebug(() -> "Detected segment: " + segment.toString()); + } + + sponsorSegmentsOfCurrentVideo = segments; + // new Handler(Looper.getMainLooper()).post(findAndSkipSegmentRunnable); + } catch (Exception ex) { + LogHelper.printException(() -> "executeDownloadSegments failure", ex); + } } public static void setVideoTime(long millis) { - LogHelper.printDebug(() -> "setCurrentVideoTime: current video time: " + millis); - if (!SettingsEnum.SB_ENABLED.getBoolean()) return; - lastKnownVideoTime = millis; - if (millis <= 0) return; - //findAndSkipSegment(false); + try { + if (!SettingsEnum.SB_ENABLED.getBoolean()) return; + LogHelper.printDebug(() -> "setCurrentVideoTime: current video time: " + millis); + // fixme? if (millis == lastKnownVideoTime), should it return here and not continue? + lastKnownVideoTime = millis; + if (millis <= 0) return; + //findAndSkipSegment(false); - if (millis == VideoInformation.getCurrentVideoLength()) { - SponsorBlockUtils.hideShieldButton(); - SponsorBlockUtils.hideVoteButton(); - return; - } - - SponsorSegment[] segments = sponsorSegmentsOfCurrentVideo; - if (segments == null || segments.length == 0) return; - - final long START_TIMER_BEFORE_SEGMENT_MILLIS = 1200; - final long startTimerAtMillis = millis + START_TIMER_BEFORE_SEGMENT_MILLIS; - - for (final SponsorSegment segment : segments) { - if (segment.start > millis) { - if (segment.start > startTimerAtMillis) - break; // it's more then START_TIMER_BEFORE_SEGMENT_MILLIS far away - if (!segment.category.behaviour.skip) - break; - - if (skipSponsorTask == null) { - LogHelper.printDebug(() -> "Scheduling skipSponsorTask"); - skipSponsorTask = new TimerTask() { - @Override - public void run() { - skipSponsorTask = null; - lastKnownVideoTime = segment.start + 1; - new Handler(Looper.getMainLooper()).post(findAndSkipSegmentRunnable); - } - }; - sponsorTimer.schedule(skipSponsorTask, segment.start - millis); - } else { - LogHelper.printDebug(() -> "skipSponsorTask is already scheduled..."); - } - - break; - } - - if (segment.end < millis) - continue; - - // we are in the segment! - if (segment.category.behaviour.skip && !(segment.category.behaviour.key.equals("skip-once") && segment.didAutoSkipped)) { - sendViewRequestAsync(millis, segment); - skipSegment(segment, false); - break; - } else { - SkipSegmentView.show(); + if (millis == VideoInformation.getCurrentVideoLength()) { + SponsorBlockUtils.hideShieldButton(); + SponsorBlockUtils.hideVoteButton(); return; } + + SponsorSegment[] segments = sponsorSegmentsOfCurrentVideo; + if (segments == null || segments.length == 0) return; + + final long START_TIMER_BEFORE_SEGMENT_MILLIS = 1200; + final long startTimerAtMillis = millis + START_TIMER_BEFORE_SEGMENT_MILLIS; + + for (final SponsorSegment segment : segments) { + if (segment.start > millis) { + if (segment.start > startTimerAtMillis) + break; // it's more then START_TIMER_BEFORE_SEGMENT_MILLIS far away + if (!segment.category.behaviour.skip) + break; + + if (skipSponsorTask == null) { + LogHelper.printDebug(() -> "Scheduling skipSponsorTask"); + skipSponsorTask = new TimerTask() { + @Override + public void run() { + skipSponsorTask = null; + lastKnownVideoTime = segment.start + 1; + ReVancedUtils.runOnMainThread(findAndSkipSegmentRunnable); + } + }; + sponsorTimer.schedule(skipSponsorTask, segment.start - millis); + } else { + LogHelper.printDebug(() -> "skipSponsorTask is already scheduled..."); + } + + break; + } + + if (segment.end < millis) + continue; + + // we are in the segment! + if (segment.category.behaviour.skip && !(segment.category.behaviour.key.equals("skip-once") && segment.didAutoSkipped)) { + sendViewRequestAsync(millis, segment); + skipSegment(segment, false); + break; + } else { + SkipSegmentView.show(); + return; + } + } + SkipSegmentView.hide(); + } catch (Exception e) { + LogHelper.printException(() -> "setVideoTime failure", e); } - SkipSegmentView.hide(); } private static void sendViewRequestAsync(final long millis, final SponsorSegment segment) { @@ -174,7 +193,7 @@ public class PlayerController { SettingsEnum.SB_SKIPPED_SEGMENTS_TIME.saveValue(newSkippedTime); } } - new Thread(() -> { + new Thread(() -> { // fixme: use ReVancedUtils#runOnBackgroundThread if (SettingsEnum.SB_COUNT_SKIPS.getBoolean() && segment.category != SponsorBlockSettings.SegmentInfo.UNSUBMITTED && millis - segment.start < 2000) { @@ -185,14 +204,18 @@ public class PlayerController { } public static void setHighPrecisionVideoTime(final long millis) { - if ((millis < lastKnownVideoTime && lastKnownVideoTime >= VideoInformation.getCurrentVideoLength()) || millis == 0) { - SponsorBlockUtils.showShieldButton(); // skipping from end to the video will show the buttons again - SponsorBlockUtils.showVoteButton(); + try { + if ((millis < lastKnownVideoTime && lastKnownVideoTime >= VideoInformation.getCurrentVideoLength()) || millis == 0) { + SponsorBlockUtils.showShieldButton(); // skipping from end to the video will show the buttons again + SponsorBlockUtils.showVoteButton(); + } + if (lastKnownVideoTime > 0) { + lastKnownVideoTime = millis; + } else + setVideoTime(millis); + } catch (Exception ex) { + LogHelper.printException(() -> "setHighPrecisionVideoTime failure", ex); } - if (lastKnownVideoTime > 0) { - lastKnownVideoTime = millis; - } else - setVideoTime(millis); } public static long getCurrentVideoLength() { @@ -222,8 +245,8 @@ public class PlayerController { setSponsorBarAbsoluteLeft(rect.left); setSponsorBarAbsoluteRight(rect.right); } - } catch (IllegalAccessException | NoSuchFieldException e) { - e.printStackTrace(); + } catch (Exception ex) { + LogHelper.printException(() -> "setSponsorBarRect failure", ex); } } @@ -238,7 +261,11 @@ public class PlayerController { } public static void setSponsorBarThickness(final int thickness) { - setSponsorBarThickness((float) thickness); + try { + setSponsorBarThickness((float) thickness); + } catch (Exception ex) { + LogHelper.printException(() -> "setSponsorBarThickness failure", ex); + } } public static void setSponsorBarThickness(final float thickness) { @@ -255,24 +282,33 @@ public class PlayerController { public static void addSkipSponsorView15(final View view) { - playerActivity = new WeakReference<>((Activity) view.getContext()); - LogHelper.printDebug(() -> "addSkipSponsorView15: view=" + view.toString()); + try { + playerActivity = new WeakReference<>((Activity) view.getContext()); + LogHelper.printDebug(() -> "addSkipSponsorView15: view=" + view.toString()); - new Handler(Looper.getMainLooper()).postDelayed(() -> { - final ViewGroup viewGroup = (ViewGroup) ((ViewGroup) view).getChildAt(2); - Activity context = ((Activity) viewGroup.getContext()); - NewSegmentHelperLayout.context = context; - }, 500); + ReVancedUtils.runOnMainThreadDelayed(() -> { + final ViewGroup viewGroup = (ViewGroup) ((ViewGroup) view).getChildAt(2); + Activity context = ((Activity) viewGroup.getContext()); + NewSegmentHelperLayout.context = context; + }, 500); + } catch (Exception ex) { + LogHelper.printException(() -> "addSkipSponsorView15 failure", ex); + } } + // Edit: Is this method ever called? Where is the patch code that calls this? public static void addSkipSponsorView14(final View view) { - playerActivity = new WeakReference<>((Activity) view.getContext()); - LogHelper.printDebug(() -> "addSkipSponsorView14: view=" + view.toString()); - new Handler(Looper.getMainLooper()).postDelayed(() -> { - final ViewGroup viewGroup = (ViewGroup) view.getParent(); - Activity activity = (Activity) viewGroup.getContext(); - NewSegmentHelperLayout.context = activity; - }, 500); + try { + playerActivity = new WeakReference<>((Activity) view.getContext()); + LogHelper.printDebug(() -> "addSkipSponsorView14: view=" + view.toString()); + ReVancedUtils.runOnMainThreadDelayed(() -> { + final ViewGroup viewGroup = (ViewGroup) view.getParent(); + Activity activity = (Activity) viewGroup.getContext(); + NewSegmentHelperLayout.context = activity; + }, 500); + } catch (Exception ex) { + LogHelper.printException(() -> "addSkipSponsorView14 failure", ex); + } } @@ -280,21 +316,25 @@ public class PlayerController { * Called when it's time to draw time bar */ public static void drawSponsorTimeBars(final Canvas canvas, final float posY) { - if (sponsorBarThickness < 0.1) return; - if (sponsorSegmentsOfCurrentVideo == null) return; + try { + if (sponsorBarThickness < 0.1) return; + if (sponsorSegmentsOfCurrentVideo == null) return; - final float thicknessDiv2 = sponsorBarThickness / 2; - final float top = posY - thicknessDiv2; - final float bottom = posY + thicknessDiv2; - final float absoluteLeft = sponsorBarLeft; - final float absoluteRight = sponsorBarRight; + final float thicknessDiv2 = sponsorBarThickness / 2; + final float top = posY - thicknessDiv2; + final float bottom = posY + thicknessDiv2; + final float absoluteLeft = sponsorBarLeft; + final float absoluteRight = sponsorBarRight; - final float tmp1 = 1f / (float) VideoInformation.getCurrentVideoLength() * (absoluteRight - absoluteLeft); - for (SponsorSegment segment : sponsorSegmentsOfCurrentVideo) { - float left = segment.start * tmp1 + absoluteLeft; - float right = segment.end * tmp1 + absoluteLeft; - canvas.drawRect(left, top, right, bottom, segment.category.paint); + final float tmp1 = 1f / (float) VideoInformation.getCurrentVideoLength() * (absoluteRight - absoluteLeft); + for (SponsorSegment segment : sponsorSegmentsOfCurrentVideo) { + float left = segment.start * tmp1 + absoluteLeft; + float right = segment.end * tmp1 + absoluteLeft; + canvas.drawRect(left, top, right, bottom, segment.category.paint); + } + } catch (Exception ex) { + LogHelper.printException(() -> "drawSponsorTimeBars failure", ex); } } @@ -326,7 +366,7 @@ public class PlayerController { lastKnownVideoTime = finalMillisecond; VideoInformation.seekTo(finalMillisecond); } catch (Exception e) { - LogHelper.printException(() -> ("Cannot skip to millisecond"), e); + LogHelper.printException(() -> "Cannot skip to millisecond", e); } return true; @@ -334,51 +374,59 @@ public class PlayerController { private static void findAndSkipSegment(boolean wasClicked) { - if (sponsorSegmentsOfCurrentVideo == null) - return; - - final long millis = lastKnownVideoTime; - - for (SponsorSegment segment : sponsorSegmentsOfCurrentVideo) { - if (segment.start > millis) - break; - - if (segment.end < millis) - continue; - - SkipSegmentView.show(); - if (!((segment.category.behaviour.skip && !(segment.category.behaviour.key.equals("skip-once") && segment.didAutoSkipped)) || wasClicked)) + try { + if (sponsorSegmentsOfCurrentVideo == null) return; - sendViewRequestAsync(millis, segment); - skipSegment(segment, wasClicked); - break; - } + final long millis = lastKnownVideoTime; - SkipSegmentView.hide(); + for (SponsorSegment segment : sponsorSegmentsOfCurrentVideo) { + if (segment.start > millis) + break; + + if (segment.end < millis) + continue; + + SkipSegmentView.show(); + if (!((segment.category.behaviour.skip && !(segment.category.behaviour.key.equals("skip-once") && segment.didAutoSkipped)) || wasClicked)) + return; + + sendViewRequestAsync(millis, segment); + skipSegment(segment, wasClicked); + break; + } + + SkipSegmentView.hide(); + } catch (Exception ex) { + LogHelper.printException(() -> "findAndSkipSegment failure", ex); + } } private static void skipSegment(SponsorSegment segment, boolean wasClicked) { -// if (lastSkippedSegment == segment) return; -// lastSkippedSegment = segment; - LogHelper.printDebug(() -> "Skipping segment: " + segment.toString()); + try { +// if (lastSkippedSegment == segment) return; +// lastSkippedSegment = segment; + LogHelper.printDebug(() -> "Skipping segment: " + segment.toString()); - if (SettingsEnum.SB_SHOW_TOAST_WHEN_SKIP.getBoolean() && !wasClicked) - SkipSegmentView.notifySkipped(segment); + if (SettingsEnum.SB_SHOW_TOAST_WHEN_SKIP.getBoolean() && !wasClicked) + SkipSegmentView.notifySkipped(segment); - boolean didSucceed = skipToMillisecond(segment.end + 2); - if (didSucceed && !wasClicked) { - segment.didAutoSkipped = true; - } - SkipSegmentView.hide(); - if (segment.category == SponsorBlockSettings.SegmentInfo.UNSUBMITTED) { - SponsorSegment[] newSegments = new SponsorSegment[sponsorSegmentsOfCurrentVideo.length - 1]; - int i = 0; - for (SponsorSegment sponsorSegment : sponsorSegmentsOfCurrentVideo) { - if (sponsorSegment != segment) - newSegments[i++] = sponsorSegment; + boolean didSucceed = skipToMillisecond(segment.end + 2); + if (didSucceed && !wasClicked) { + segment.didAutoSkipped = true; } - sponsorSegmentsOfCurrentVideo = newSegments; + SkipSegmentView.hide(); + if (segment.category == SponsorBlockSettings.SegmentInfo.UNSUBMITTED) { + SponsorSegment[] newSegments = new SponsorSegment[sponsorSegmentsOfCurrentVideo.length - 1]; + int i = 0; + for (SponsorSegment sponsorSegment : sponsorSegmentsOfCurrentVideo) { + if (sponsorSegment != segment) + newSegments[i++] = sponsorSegment; + } + sponsorSegmentsOfCurrentVideo = newSegments; + } + } catch (Exception ex) { + LogHelper.printException(() -> "skipSegment failure", ex); } } } diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/ShieldButton.java b/app/src/main/java/app/revanced/integrations/sponsorblock/ShieldButton.java index c3928bf1..4c5a55c3 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/ShieldButton.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/ShieldButton.java @@ -52,7 +52,7 @@ public class ShieldButton { isShowing = true; changeVisibilityImmediate(false); } catch (Exception ex) { - LogHelper.printException(() -> ("Unable to set RelativeLayout"), ex); + LogHelper.printException(() -> "Unable to set RelativeLayout", ex); } } @@ -69,29 +69,33 @@ public class ShieldButton { } public static void changeVisibility(boolean visible, boolean immediate) { - if (isShowing == visible) return; - isShowing = visible; + try { + if (isShowing == visible) return; + isShowing = visible; - ImageView iView = _shieldBtn.get(); - if (_youtubeControlsLayout == null || iView == null) return; + ImageView iView = _shieldBtn.get(); + if (_youtubeControlsLayout == null || iView == null) return; - if (visible && shouldBeShown()) { - if (getLastKnownVideoTime() >= getCurrentVideoLength()) { + if (visible && shouldBeShown()) { + if (getLastKnownVideoTime() >= getCurrentVideoLength()) { + return; + } + LogHelper.printDebug(() -> "Fading in"); + + iView.setVisibility(View.VISIBLE); + if (!immediate) + iView.startAnimation(fadeIn); return; } - LogHelper.printDebug(() -> "Fading in"); - iView.setVisibility(View.VISIBLE); - if (!immediate) - iView.startAnimation(fadeIn); - return; - } - - if (iView.getVisibility() == View.VISIBLE) { - LogHelper.printDebug(() -> "Fading out"); - if (!immediate) - iView.startAnimation(fadeOut); - iView.setVisibility(shouldBeShown() ? View.INVISIBLE : View.GONE); + if (iView.getVisibility() == View.VISIBLE) { + LogHelper.printDebug(() -> "Fading out"); + if (!immediate) + iView.startAnimation(fadeOut); + iView.setVisibility(shouldBeShown() ? View.INVISIBLE : View.GONE); + } + } catch (Exception ex) { + LogHelper.printException(() -> "changeVisibility failure", ex); } } diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/SkipSegmentView.java b/app/src/main/java/app/revanced/integrations/sponsorblock/SkipSegmentView.java index 4ce09452..e5e651a1 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/SkipSegmentView.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/SkipSegmentView.java @@ -13,7 +13,7 @@ import app.revanced.integrations.utils.ReVancedUtils; import static app.revanced.integrations.sponsorblock.player.ui.SponsorBlockView.hideSkipButton; import static app.revanced.integrations.sponsorblock.player.ui.SponsorBlockView.showSkipButton; -@SuppressLint({"RtlHardcoded", "SetTextI18n", "LongLogTag", "AppCompatCustomView"}) +@SuppressLint({"RtlHardcoded", "SetTextI18n", "AppCompatCustomView"}) public class SkipSegmentView { private static SponsorSegment lastNotifiedSegment; diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/SponsorBlockUtils.java b/app/src/main/java/app/revanced/integrations/sponsorblock/SponsorBlockUtils.java index 515e7841..13a90f35 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/SponsorBlockUtils.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/SponsorBlockUtils.java @@ -51,7 +51,6 @@ import app.revanced.integrations.sponsorblock.objects.SponsorSegment; import app.revanced.integrations.sponsorblock.objects.UserStats; import app.revanced.integrations.sponsorblock.requests.SBRequester; -@SuppressWarnings({"LongLogTag"}) public abstract class SponsorBlockUtils { public static final String DATE_FORMAT = "HH:mm:ss.SSS"; @SuppressLint("SimpleDateFormat") @@ -154,7 +153,7 @@ public abstract class SponsorBlockUtils { Toast.makeText(context, str("submit_started"), Toast.LENGTH_SHORT).show(); appContext = new WeakReference<>(context); - new Thread(submitRunnable).start(); + new Thread(submitRunnable).start(); // fixme: use ReVancedUtils#runOnBackgroundThread } }; public static String messageToToast = ""; @@ -233,13 +232,13 @@ public abstract class SponsorBlockUtils { final SponsorBlockSettings.SegmentInfo segmentType = SponsorBlockUtils.newSponsorBlockSegmentType; try { if (start < 0 || end < 0 || start >= end || segmentType == null || videoId == null || uuid == null) { - LogHelper.printException(() -> ("Unable to submit times, invalid parameters")); + LogHelper.printException(() -> "Unable to submit times, invalid parameters"); return; } SBRequester.submitSegments(videoId, uuid, ((float) start) / 1000f, ((float) end) / 1000f, segmentType.key, toastRunnable); newSponsorSegmentEndMillis = newSponsorSegmentStartMillis = -1; } catch (Exception e) { - LogHelper.printException(() -> ("Unable to submit segment"), e); + LogHelper.printException(() -> "Unable to submit segment", e); } if (videoId != null) @@ -403,11 +402,15 @@ public abstract class SponsorBlockUtils { } public static String appendTimeWithoutSegments(String totalTime) { - if (videoHasSegments && (SettingsEnum.SB_ENABLED.getBoolean() && SettingsEnum.SB_SHOW_TIME_WITHOUT_SEGMENTS.getBoolean()) && !TextUtils.isEmpty(totalTime) && getCurrentVideoLength() > 1) { - if (timeWithoutSegments.isEmpty()) { - timeWithoutSegments = getTimeWithoutSegments(sponsorSegmentsOfCurrentVideo); + try { + if (videoHasSegments && (SettingsEnum.SB_ENABLED.getBoolean() && SettingsEnum.SB_SHOW_TIME_WITHOUT_SEGMENTS.getBoolean()) && !TextUtils.isEmpty(totalTime) && getCurrentVideoLength() > 1) { + if (timeWithoutSegments.isEmpty()) { + timeWithoutSegments = getTimeWithoutSegments(sponsorSegmentsOfCurrentVideo); + } + return totalTime + timeWithoutSegments; } - return totalTime + timeWithoutSegments; + } catch (Exception ex) { + LogHelper.printException(() -> "appendTimeWithoutSegments failure", ex); } return totalTime; @@ -436,7 +439,7 @@ public abstract class SponsorBlockUtils { PlayerController.setCurrentVideoId(null); } } catch (Exception ex) { - LogHelper.printException(() -> ("Player type changed caused a crash."), ex); + LogHelper.printException(() -> "Player type changed caused a crash.", ex); } } @@ -558,8 +561,8 @@ public abstract class SponsorBlockUtils { Toast.makeText(context, str("settings_import_successful"), Toast.LENGTH_SHORT).show(); } catch (Exception ex) { + LogHelper.printInfo(() -> "failed to import settings", ex); // use info level, as we are showing our own toast Toast.makeText(context, str("settings_import_failed"), Toast.LENGTH_SHORT).show(); - ex.printStackTrace(); } } @@ -598,8 +601,8 @@ public abstract class SponsorBlockUtils { return json.toString(); } catch (Exception ex) { + LogHelper.printInfo(() -> "failed to export settings", ex); // use info level, as we are showing our own toast Toast.makeText(context, str("settings_export_failed"), Toast.LENGTH_SHORT).show(); - ex.printStackTrace(); return ""; } } diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/StringRef.java b/app/src/main/java/app/revanced/integrations/sponsorblock/StringRef.java index 14f1a201..437290a2 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/StringRef.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/StringRef.java @@ -103,11 +103,11 @@ public class StringRef { if (resources != null) { final int identifier = resources.getIdentifier(value, "string", packageName); if (identifier == 0) - LogHelper.printException(() -> ("Resource not found: " + value)); + LogHelper.printException(() -> "Resource not found: " + value); else value = resources.getString(identifier); } else { - LogHelper.printException(() -> ("Could not resolve resources!")); + LogHelper.printException(() -> "Could not resolve resources!"); } } return value; diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/SwipeHelper.java b/app/src/main/java/app/revanced/integrations/sponsorblock/SwipeHelper.java index 09ded108..aa3da868 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/SwipeHelper.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/SwipeHelper.java @@ -25,7 +25,7 @@ public class SwipeHelper { isTabletMode = true; } } catch (Exception e) { - LogHelper.printException(() -> ("Unable to set FrameLayout"), e); + LogHelper.printException(() -> "Unable to set FrameLayout", e); } } @@ -33,7 +33,7 @@ public class SwipeHelper { try { nextGenWatchLayout = (ViewGroup) obj; } catch (Exception e) { - LogHelper.printException(() -> ("Unable to set _nextGenWatchLayout"), e); + LogHelper.printException(() -> "Unable to set _nextGenWatchLayout", e); } } @@ -44,7 +44,7 @@ public class SwipeHelper { } try { } catch (Exception e) { - LogHelper.printException(() -> ("Unable to get related_endscreen_results visibility"), e); + LogHelper.printException(() -> "Unable to get related_endscreen_results visibility", e); } if (_frameLayout.getChildCount() > 0) { return _frameLayout.getChildAt(0).getVisibility() == View.VISIBLE; @@ -61,7 +61,7 @@ public class SwipeHelper { LogHelper.printDebug(() -> "related_endscreen_results refreshed"); } } catch (Exception e) { - LogHelper.printException(() -> ("Unable to refresh related_endscreen_results layout"), e); + LogHelper.printException(() -> "Unable to refresh related_endscreen_results layout", e); } } diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/VotingButton.java b/app/src/main/java/app/revanced/integrations/sponsorblock/VotingButton.java index 5d644643..99031c03 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/VotingButton.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/VotingButton.java @@ -51,7 +51,7 @@ public class VotingButton { isShowing = true; changeVisibilityImmediate(false); } catch (Exception ex) { - LogHelper.printException(() -> ("Unable to set RelativeLayout"), ex); + LogHelper.printException(() -> "Unable to set RelativeLayout", ex); } } @@ -68,28 +68,32 @@ public class VotingButton { } public static void changeVisibility(boolean visible, boolean immediate) { - if (isShowing == visible) return; - isShowing = visible; + try { + if (isShowing == visible) return; + isShowing = visible; - ImageView iView = _votingButton.get(); - if (_youtubeControlsLayout == null || iView == null) return; + ImageView iView = _votingButton.get(); + if (_youtubeControlsLayout == null || iView == null) return; - if (visible && shouldBeShown()) { - if (getLastKnownVideoTime() >= getCurrentVideoLength()) { + if (visible && shouldBeShown()) { + if (getLastKnownVideoTime() >= getCurrentVideoLength()) { + return; + } + LogHelper.printDebug(() -> "Fading in"); + iView.setVisibility(View.VISIBLE); + if (!immediate) + iView.startAnimation(fadeIn); return; } - LogHelper.printDebug(() -> "Fading in"); - iView.setVisibility(View.VISIBLE); - if (!immediate) - iView.startAnimation(fadeIn); - return; - } - if (iView.getVisibility() == View.VISIBLE) { - LogHelper.printDebug(() -> "Fading out"); - if (!immediate) - iView.startAnimation(fadeOut); - iView.setVisibility(shouldBeShown() ? View.INVISIBLE : View.GONE); + if (iView.getVisibility() == View.VISIBLE) { + LogHelper.printDebug(() -> "Fading out"); + if (!immediate) + iView.startAnimation(fadeOut); + iView.setVisibility(shouldBeShown() ? View.INVISIBLE : View.GONE); + } + } catch (Exception ex) { + LogHelper.printException(() -> "changeVisibility failure", ex); } } diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SlimButton.java b/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SlimButton.java index 0c50fc0b..2827f856 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SlimButton.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SlimButton.java @@ -48,7 +48,7 @@ public abstract class SlimButton implements View.OnClickListener { } setContainerVisibility(); } catch (Exception ex) { - LogHelper.printException(() -> ("Error while changing button visibility"), ex); + LogHelper.printException(() -> "Error while changing button visibility", ex); } } diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SponsorBlockView.java b/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SponsorBlockView.java index 983561c4..f7bfef5a 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SponsorBlockView.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/player/ui/SponsorBlockView.java @@ -29,7 +29,7 @@ public class SponsorBlockView { addView(); } catch (Exception ex) { - LogHelper.printException(() -> ("Unable to set ViewGroup"), ex); + LogHelper.printException(() -> "Unable to set ViewGroup", ex); } } @@ -62,7 +62,7 @@ public class SponsorBlockView { setSkipBtnMargins(false); setNewSegmentLayoutMargins(false); } catch (Exception ex) { - LogHelper.printException(() -> ("Player type changed caused a crash."), ex); + LogHelper.printException(() -> "Player type changed caused a crash.", ex); } } @@ -87,13 +87,13 @@ public class SponsorBlockView { private static void setSkipBtnMargins(boolean fullScreen) { SkipSponsorButton skipSponsorButton = _skipSponsorButton.get(); if (skipSponsorButton == null) { - LogHelper.printException(() -> ("Unable to setSkipBtnMargins")); + LogHelper.printException(() -> "Unable to setSkipBtnMargins"); return; } RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) skipSponsorButton.getLayoutParams(); if (params == null) { - LogHelper.printException(() -> ("Unable to setSkipBtnMargins")); + LogHelper.printException(() -> "Unable to setSkipBtnMargins"); return; } params.bottomMargin = fullScreen ? skipSponsorButton.ctaBottomMargin : skipSponsorButton.defaultBottomMargin; @@ -103,7 +103,7 @@ public class SponsorBlockView { private static void skipSponsorButtonVisibility(boolean visible) { SkipSponsorButton skipSponsorButton = _skipSponsorButton.get(); if (skipSponsorButton == null) { - LogHelper.printException(() -> ("Unable to skipSponsorButtonVisibility")); + LogHelper.printException(() -> "Unable to skipSponsorButtonVisibility"); return; } @@ -116,13 +116,13 @@ public class SponsorBlockView { private static void setNewSegmentLayoutMargins(boolean fullScreen) { NewSegmentLayout newSegmentLayout = _newSegmentLayout.get(); if (newSegmentLayout == null) { - LogHelper.printException(() -> ("Unable to setNewSegmentLayoutMargins")); + LogHelper.printException(() -> "Unable to setNewSegmentLayoutMargins"); return; } RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) newSegmentLayout.getLayoutParams(); if (params == null) { - LogHelper.printException(() -> ("Unable to setNewSegmentLayoutMargins")); + LogHelper.printException(() -> "Unable to setNewSegmentLayoutMargins"); return; } params.bottomMargin = fullScreen ? newSegmentLayout.ctaBottomMargin : newSegmentLayout.defaultBottomMargin; @@ -132,7 +132,7 @@ public class SponsorBlockView { private static void newSegmentLayoutVisibility(boolean visible) { NewSegmentLayout newSegmentLayout = _newSegmentLayout.get(); if (newSegmentLayout == null) { - LogHelper.printException(() -> ("Unable to newSegmentLayoutVisibility")); + LogHelper.printException(() -> "Unable to newSegmentLayoutVisibility"); return; } diff --git a/app/src/main/java/app/revanced/integrations/sponsorblock/requests/SBRequester.java b/app/src/main/java/app/revanced/integrations/sponsorblock/requests/SBRequester.java index babdd1e6..180aad7d 100644 --- a/app/src/main/java/app/revanced/integrations/sponsorblock/requests/SBRequester.java +++ b/app/src/main/java/app/revanced/integrations/sponsorblock/requests/SBRequester.java @@ -31,6 +31,7 @@ import app.revanced.integrations.sponsorblock.SponsorBlockUtils; import app.revanced.integrations.sponsorblock.SponsorBlockUtils.VoteOption; import app.revanced.integrations.sponsorblock.objects.SponsorSegment; import app.revanced.integrations.sponsorblock.objects.UserStats; +import app.revanced.integrations.utils.LogHelper; public class SBRequester { private static final String TIME_TEMPLATE = "%.3f"; @@ -79,7 +80,7 @@ public class SBRequester { } connection.disconnect(); } catch (Exception ex) { - ex.printStackTrace(); + LogHelper.printException(() -> "failed to get segments", ex); } return segments.toArray(new SponsorSegment[0]); } @@ -115,7 +116,7 @@ public class SBRequester { runOnMainThread(toastRunnable); connection.disconnect(); } catch (Exception ex) { - ex.printStackTrace(); + LogHelper.printException(() -> "failed to submit segments", ex); } } @@ -124,12 +125,12 @@ public class SBRequester { HttpURLConnection connection = getConnectionFromRoute(SBRoutes.VIEWED_SEGMENT, segment.UUID); connection.disconnect(); } catch (Exception ex) { - ex.printStackTrace(); + LogHelper.printException(() -> "failed to send view count request", ex); } } public static void voteForSegment(SponsorSegment segment, VoteOption voteOption, Context context, String... args) { - new Thread(() -> { + new Thread(() -> { // fixme: use ReVancedUtils#runOnBackgroundThread try { String segmentUuid = segment.UUID; String uuid = SettingsEnum.SB_UUID.getString(); @@ -156,7 +157,7 @@ public class SBRequester { runOnMainThread(() -> Toast.makeText(context, SponsorBlockUtils.messageToToast, Toast.LENGTH_LONG).show()); connection.disconnect(); } catch (Exception ex) { - ex.printStackTrace(); + LogHelper.printException(() -> "failed to vote for segment", ex); } }).start(); } @@ -167,20 +168,20 @@ public class SBRequester { return; } - new Thread(() -> { + new Thread(() -> { // fixme: use ReVancedUtils#runOnBackgroundThread try { JSONObject json = getJSONObject(SBRoutes.GET_USER_STATS, SettingsEnum.SB_UUID.getString()); UserStats stats = new UserStats(json.getString("userName"), json.getDouble("minutesSaved"), json.getInt("segmentCount"), json.getInt("viewCount")); SponsorBlockUtils.addUserStats(category, loadingPreference, stats); } catch (Exception ex) { - ex.printStackTrace(); + LogHelper.printException(() -> "failed to retrieve user stats", ex); } }).start(); } public static void setUsername(String username, EditTextPreference preference, Runnable toastRunnable) { - new Thread(() -> { + new Thread(() -> { // fixme: use ReVancedUtils#runOnBackgroundThread try { HttpURLConnection connection = getConnectionFromRoute(SBRoutes.CHANGE_USERNAME, SettingsEnum.SB_UUID.getString(), username); int responseCode = connection.getResponseCode(); @@ -197,7 +198,7 @@ public class SBRequester { runOnMainThread(toastRunnable); connection.disconnect(); } catch (Exception ex) { - ex.printStackTrace(); + LogHelper.printException(() -> "failed to set username", ex); } }).start(); } @@ -213,7 +214,7 @@ public class SBRequester { SettingsEnum.SB_IS_VIP.saveValue(vip); SettingsEnum.SB_LAST_VIP_CHECK.saveValue(now); } catch (Exception ex) { - ex.printStackTrace(); + LogHelper.printException(() -> "failed to check VIP", ex); } } diff --git a/app/src/main/java/app/revanced/integrations/swipecontrols/controller/AudioVolumeController.kt b/app/src/main/java/app/revanced/integrations/swipecontrols/controller/AudioVolumeController.kt index 7743a48e..8663d58e 100644 --- a/app/src/main/java/app/revanced/integrations/swipecontrols/controller/AudioVolumeController.kt +++ b/app/src/main/java/app/revanced/integrations/swipecontrols/controller/AudioVolumeController.kt @@ -4,7 +4,7 @@ import android.content.Context import android.media.AudioManager import android.os.Build import app.revanced.integrations.swipecontrols.misc.clamp -import app.revanced.integrations.utils.LogHelper.printDebug +import app.revanced.integrations.utils.LogHelper.printException import kotlin.properties.Delegates /** @@ -29,7 +29,7 @@ class AudioVolumeController( // bind audio service val mgr = context.getSystemService(Context.AUDIO_SERVICE) as? AudioManager if (mgr == null) { - printDebug { "failed to acquire AUDIO_SERVICE" } + printException { "failed to acquire AUDIO_SERVICE" } } else { audioManager = mgr maximumVolumeIndex = audioManager.getStreamMaxVolume(targetStream) diff --git a/app/src/main/java/app/revanced/integrations/utils/LogHelper.java b/app/src/main/java/app/revanced/integrations/utils/LogHelper.java index 70a73438..aa7746a8 100644 --- a/app/src/main/java/app/revanced/integrations/utils/LogHelper.java +++ b/app/src/main/java/app/revanced/integrations/utils/LogHelper.java @@ -1,6 +1,11 @@ package app.revanced.integrations.utils; +import android.content.Context; import android.util.Log; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.io.PrintWriter; import java.io.StringWriter; @@ -13,16 +18,19 @@ public class LogHelper { * Log messages using lambdas. */ public interface LogMessage { + @NonNull String buildMessageString(); /** - * @return For non inner classes, this returns {@link Class#getSimpleName()}. - * For inner classes (static and anonymous), this returns the enclosing class simple name.
+ * @return For outer classes, this returns {@link Class#getSimpleName()}. + * For inner, static, or anonymous classes, this returns the simple name of the enclosing class.
*
- * For example, each of these classes return 'SomethingView':
- * com.company.SomethingView
- * com.company.SomethingView$StaticClass
- * com.company.SomethingView$1
+ * For example, each of these classes return 'SomethingView': + * + * com.company.SomethingView + * com.company.SomethingView$StaticClass + * com.company.SomethingView$1 + * */ private String findOuterClassSimpleName() { var selfClass = this.getClass(); @@ -32,8 +40,8 @@ public class LogHelper { if (dollarSignIndex == -1) { return selfClass.getSimpleName(); // already an outer class } - // else, class is inner class (static or anonymous) + // class is inner, static, or anonymous // parse the simple name full name // a class with no package returns index of -1, but incrementing gives index zero which is correct final int simpleClassNameStartIndex = fullClassName.lastIndexOf('.') + 1; @@ -41,17 +49,14 @@ public class LogHelper { } } - /** - * Logs information messages with the most outer class name of the code that is calling this method. - */ - public static void printInfo(LogMessage message) { - Log.i("revanced: " + message.findOuterClassSimpleName(), message.buildMessageString()); - } + private static final String REVANCED_LOG_PREFIX = "revanced: "; /** - * Logs debug messages with the most outer class name of the code that is calling this method. + * Logs debug messages under the outer class name of the code calling this method. + * Whenever possible, the log string should be constructed entirely inside {@link LogMessage#buildMessageString()} + * so the performance cost of building strings is paid only if {@link SettingsEnum#DEBUG} is enabled. */ - public static void printDebug(LogMessage message) { + public static void printDebug(@NonNull LogMessage message) { if (SettingsEnum.DEBUG.getBoolean()) { var messageString = message.buildMessageString(); @@ -60,62 +65,79 @@ public class LogHelper { var sw = new StringWriter(); new Throwable().printStackTrace(new PrintWriter(sw)); - builder.append(String.format("\n%s", sw)); + builder.append('\n').append(sw); messageString = builder.toString(); } - Log.d("revanced: " + message.findOuterClassSimpleName(), messageString); + Log.d(REVANCED_LOG_PREFIX + message.findOuterClassSimpleName(), messageString); } } /** - * Logs messages with the most outer class name of the code that is calling this method. + * Logs information messages using the outer class name of the code calling this method. */ - public static void printException(LogMessage message) { - Log.e("revanced: " + message.findOuterClassSimpleName(), message.buildMessageString()); + public static void printInfo(@NonNull LogMessage message) { + printInfo(message, null); } /** - * Logs exceptions with the most outer class name of the code that is calling this method. + * Logs information messages using the outer class name of the code calling this method. */ - public static void printException(LogMessage message, Throwable ex) { - Log.e("revanced: " + message.findOuterClassSimpleName(), message.buildMessageString(), ex); + public static void printInfo(@NonNull LogMessage message, @Nullable Exception ex) { + String logTag = REVANCED_LOG_PREFIX + message.findOuterClassSimpleName(); + String logMessage = message.buildMessageString(); + if (ex == null) { + Log.i(logTag, logMessage); + } else { + Log.i(logTag, logMessage, ex); + } } /** - * Deprecated. Instead call {@link #printDebug(LogMessage)}, - * which does not cause log messages to be constructed unless logging is enabled. + * Logs exceptions under the outer class name of the code calling this method. */ - @Deprecated - public static void debug(Class _clazz, String message) { - printDebug(() -> message); // this fails to show the correct calling class name, but it's deprecated who cares + public static void printException(@NonNull LogMessage message) { + printException(message, null, null); } /** - * Deprecated. Instead call {@link #printException(LogMessage, Throwable)} - * or {@link #printException(LogMessage)} - * which does not cause log messages to be constructed unless logging is enabled. + * Logs exceptions under the outer class name of the code calling this method. */ - @Deprecated - public static void printException(Class _clazz, String message, Throwable ex) { - printException(() -> message, ex); + public static void printException(@NonNull LogMessage message, @Nullable Throwable ex) { + printException(message, ex, null); } /** - * Deprecated. Instead call {@link #printException(LogMessage)}, - * which does not cause log messages to be constructed unless logging is enabled. + * Logs exceptions under the outer class name of the code calling this method. + *

+ * If the calling code is showing it's own error toast, + * instead use {@link #printInfo(LogMessage, Exception)} + * + * @param message log message + * @param ex exception (optional) + * @param userToastMessage user specific toast message to show instead of the log message (optional) */ - @Deprecated - public static void printException(Class _clazz, String message) { - printException(() -> message); + public static void printException(@NonNull LogMessage message, @Nullable Throwable ex, + @Nullable String userToastMessage) { + String messageString = message.buildMessageString(); + String outerClassSimpleName = message.findOuterClassSimpleName(); + String logMessage = REVANCED_LOG_PREFIX + outerClassSimpleName; + if (ex == null) { + Log.e(logMessage, messageString); + } else { + Log.e(logMessage, messageString, ex); + } + if (SettingsEnum.DEBUG_SHOW_TOAST_ON_ERROR.getBoolean()) { + String toastMessageToDisplay = (userToastMessage != null) + ? userToastMessage + : outerClassSimpleName + ": " + messageString; + ReVancedUtils.runOnMainThread(() -> { + Context context = ReVancedUtils.getContext(); + if (context != null) { + Toast.makeText(context, toastMessageToDisplay, Toast.LENGTH_LONG).show(); + } + }); + } } - /** - * Deprecated. Instead call {@link #printInfo(LogMessage)}, - * which does not cause log messages to be constructed unless logging is enabled. - */ - @Deprecated - public static void info(Class _clazz, String message) { - printInfo(() -> message); - } } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java b/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java index ee083a51..8858fdb8 100644 --- a/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java +++ b/app/src/main/java/app/revanced/integrations/utils/ReVancedUtils.java @@ -6,6 +6,8 @@ import android.content.res.Resources; import android.os.Handler; import android.os.Looper; +import androidx.annotation.NonNull; + import java.text.Bidi; import java.util.Locale; import java.util.concurrent.Callable; @@ -58,10 +60,6 @@ public class ReVancedUtils { // or some ReVanced code is submitting an unexpected number of background tasks. LogHelper.printException(() -> "Reached maximum background thread count of " + SHARED_THREAD_POOL_MAXIMUM_BACKGROUND_THREADS + " threads"); - - // Because this condition will manifest as a slow running app or a memory leak, - // it might be best to show the user a toast or some other suggestion to restart the app. - // TODO? if debug is enabled, show a toast? } } @@ -96,7 +94,7 @@ public class ReVancedUtils { Resources res = context.getResources(); return res.getIdentifier(name, type, context.getPackageName()); } catch (Throwable exception) { - LogHelper.printException(() -> ("Resource not found."), exception); + LogHelper.printException(() -> "Resource not found.", exception); return null; } } @@ -118,7 +116,7 @@ public class ReVancedUtils { if (context != null) { return context; } else { - LogHelper.printException(() -> ("Context is null, returning null!")); + LogHelper.printException(() -> "Context is null, returning null!"); return null; } } @@ -149,37 +147,44 @@ public class ReVancedUtils { * Automatically logs any exceptions the runnable throws */ public static void runOnMainThread(Runnable runnable) { - Runnable exceptLoggingRunnable = () -> { + runOnMainThreadDelayed(runnable, 0); + } + + /** + * Automatically logs any exceptions the runnable throws + */ + public static void runOnMainThreadDelayed(Runnable runnable, long delayMillis) { + Runnable loggingRunnable = () -> { try { runnable.run(); } catch (Exception ex) { - LogHelper.printException(() -> "Exception on main thread from runnable: " + runnable.toString(), ex); + LogHelper.printException(() -> runnable.getClass() + ": " + ex.getMessage(), ex); } }; - new Handler(Looper.getMainLooper()).post(exceptLoggingRunnable); + new Handler(Looper.getMainLooper()).postDelayed(loggingRunnable, delayMillis); } /** * @return if the calling thread is on the main thread */ - public static boolean currentIsOnMainThread() { + public static boolean currentlyIsOnMainThread() { return Looper.getMainLooper().isCurrentThread(); } /** - * @throws IllegalStateException if the calling thread is _not_ on the main thread + * @throws IllegalStateException if the calling thread is _off_ the main thread */ public static void verifyOnMainThread() throws IllegalStateException { - if (!currentIsOnMainThread()) { + if (!currentlyIsOnMainThread()) { throw new IllegalStateException("Must call _on_ the main thread"); } } /** - * @throws IllegalStateException if the calling thread _is_ on the main thread + * @throws IllegalStateException if the calling thread is _on_ the main thread */ public static void verifyOffMainThread() throws IllegalStateException { - if (currentIsOnMainThread()) { + if (currentlyIsOnMainThread()) { throw new IllegalStateException("Must call _off_ the main thread"); } } diff --git a/app/src/main/java/app/revanced/integrations/videoplayer/DownloadButton.java b/app/src/main/java/app/revanced/integrations/videoplayer/DownloadButton.java index 5f4b56ec..b3b8cdb5 100644 --- a/app/src/main/java/app/revanced/integrations/videoplayer/DownloadButton.java +++ b/app/src/main/java/app/revanced/integrations/videoplayer/DownloadButton.java @@ -62,7 +62,7 @@ public class DownloadButton extends BottomControlButton { LogHelper.printDebug(() -> "Launched the intent with the content: " + content); } catch (Exception error) { - LogHelper.printDebug(() -> "Failed to launch the intent: " + error); + LogHelper.printException(() -> "Failed to launch the intent: " + error, error); } } } diff --git a/app/src/main/java/app/revanced/tiktok/utils/LogHelper.java b/app/src/main/java/app/revanced/tiktok/utils/LogHelper.java index 8707d839..c0dab428 100644 --- a/app/src/main/java/app/revanced/tiktok/utils/LogHelper.java +++ b/app/src/main/java/app/revanced/tiktok/utils/LogHelper.java @@ -4,10 +4,11 @@ import android.util.Log; import app.revanced.tiktok.settings.SettingsEnum; +/** + * TODO: replace this with the higher performance logging code from {@link app.revanced.integrations.utils.LogHelper} + */ public class LogHelper { - //ToDo: Get Calling classname using Reflection - public static void debug(Class clazz, String message) { if (SettingsEnum.TIK_DEBUG.getBoolean()) { Log.d("revanced: " + (clazz != null ? clazz.getSimpleName() : ""), message); diff --git a/app/src/main/java/app/revanced/twitch/utils/LogHelper.java b/app/src/main/java/app/revanced/twitch/utils/LogHelper.java index f2752f7f..899aa20a 100644 --- a/app/src/main/java/app/revanced/twitch/utils/LogHelper.java +++ b/app/src/main/java/app/revanced/twitch/utils/LogHelper.java @@ -5,8 +5,14 @@ import android.widget.Toast; import app.revanced.twitch.settings.SettingsEnum; +/** + * TODO: replace this with the higher performance logging code from {@link app.revanced.integrations.utils.LogHelper} + */ public class LogHelper { + /** + * TODO: replace this with {@link app.revanced.integrations.utils.LogHelper.LogMessage#findOuterClassSimpleName()} + */ public static String getCallOrigin() { try { diff --git a/gradle.properties b/gradle.properties index 62384044..003b7ebb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.jvmargs = -Xmx2048m android.useAndroidX = true -version = 0.93.1 +version = 0.94.0-dev.6