mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2024-12-23 08:30:44 +00:00
Added a "Crash the player" debug option
This commit is contained in:
parent
e632fab4d0
commit
769791af7a
@ -205,6 +205,9 @@ public final class VideoDetailFragment
|
|||||||
private Player player;
|
private Player player;
|
||||||
private final PlayerHolder playerHolder = PlayerHolder.getInstance();
|
private final PlayerHolder playerHolder = PlayerHolder.getInstance();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private VideoDetailPlayerCrasher videoDetailPlayerCrasher = null;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Service management
|
// Service management
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
@ -594,6 +597,18 @@ public final class VideoDetailFragment
|
|||||||
// Init
|
// Init
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(rootView, savedInstanceState);
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
this.videoDetailPlayerCrasher = new VideoDetailPlayerCrasher(
|
||||||
|
() -> this.getContext(),
|
||||||
|
() -> this.getLayoutInflater()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override // called from onViewCreated in {@link BaseFragment#onViewCreated}
|
@Override // called from onViewCreated in {@link BaseFragment#onViewCreated}
|
||||||
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
||||||
super.initViews(rootView, savedInstanceState);
|
super.initViews(rootView, savedInstanceState);
|
||||||
@ -604,6 +619,18 @@ public final class VideoDetailFragment
|
|||||||
|
|
||||||
binding.detailThumbnailRootLayout.requestFocus();
|
binding.detailThumbnailRootLayout.requestFocus();
|
||||||
|
|
||||||
|
binding.detailControlsPlayWithKodi.setVisibility(
|
||||||
|
KoreUtils.shouldShowPlayWithKodi(requireContext(), serviceId)
|
||||||
|
? View.VISIBLE
|
||||||
|
: View.GONE
|
||||||
|
);
|
||||||
|
binding.detailControlsCrashThePlayer.setVisibility(
|
||||||
|
DEBUG && PreferenceManager.getDefaultSharedPreferences(getContext())
|
||||||
|
.getBoolean(getString(R.string.show_crash_the_player_key), false)
|
||||||
|
? View.VISIBLE
|
||||||
|
: View.GONE
|
||||||
|
);
|
||||||
|
|
||||||
if (DeviceUtils.isTv(getContext())) {
|
if (DeviceUtils.isTv(getContext())) {
|
||||||
// remove ripple effects from detail controls
|
// remove ripple effects from detail controls
|
||||||
final int transparent = ContextCompat.getColor(requireContext(),
|
final int transparent = ContextCompat.getColor(requireContext(),
|
||||||
@ -638,8 +665,10 @@ public final class VideoDetailFragment
|
|||||||
binding.detailControlsShare.setOnClickListener(this);
|
binding.detailControlsShare.setOnClickListener(this);
|
||||||
binding.detailControlsOpenInBrowser.setOnClickListener(this);
|
binding.detailControlsOpenInBrowser.setOnClickListener(this);
|
||||||
binding.detailControlsPlayWithKodi.setOnClickListener(this);
|
binding.detailControlsPlayWithKodi.setOnClickListener(this);
|
||||||
binding.detailControlsPlayWithKodi.setVisibility(KoreUtils.shouldShowPlayWithKodi(
|
if (DEBUG) {
|
||||||
requireContext(), serviceId) ? View.VISIBLE : View.GONE);
|
binding.detailControlsCrashThePlayer.setOnClickListener(
|
||||||
|
v -> videoDetailPlayerCrasher.onCrashThePlayer(this.player));
|
||||||
|
}
|
||||||
|
|
||||||
binding.overlayThumbnail.setOnClickListener(this);
|
binding.overlayThumbnail.setOnClickListener(this);
|
||||||
binding.overlayThumbnail.setOnLongClickListener(this);
|
binding.overlayThumbnail.setOnLongClickListener(this);
|
||||||
|
@ -0,0 +1,165 @@
|
|||||||
|
package org.schabi.newpipe.fragments.detail;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.ContextThemeWrapper;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.RadioButton;
|
||||||
|
import android.widget.RadioGroup;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
|
import com.google.android.exoplayer2.RendererCapabilities;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.databinding.ListRadioIconItemBinding;
|
||||||
|
import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding;
|
||||||
|
import org.schabi.newpipe.player.Player;
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class VideoDetailPlayerCrasher {
|
||||||
|
|
||||||
|
private static final String TAG = "VideoDetPlayerCrasher";
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final Supplier<Context> contextSupplier;
|
||||||
|
@NonNull
|
||||||
|
private final Supplier<LayoutInflater> layoutInflaterSupplier;
|
||||||
|
|
||||||
|
public VideoDetailPlayerCrasher(
|
||||||
|
@NonNull final Supplier<Context> contextSupplier,
|
||||||
|
@NonNull final Supplier<LayoutInflater> layoutInflaterSupplier
|
||||||
|
) {
|
||||||
|
this.contextSupplier = contextSupplier;
|
||||||
|
this.layoutInflaterSupplier = layoutInflaterSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Supplier<ExoPlaybackException>> getExceptionTypes() {
|
||||||
|
final String defaultMsg = "Dummy";
|
||||||
|
final Map<String, Supplier<ExoPlaybackException>> exceptionTypes = new LinkedHashMap<>();
|
||||||
|
exceptionTypes.put(
|
||||||
|
"Source",
|
||||||
|
() -> ExoPlaybackException.createForSource(
|
||||||
|
new IOException(defaultMsg)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
exceptionTypes.put(
|
||||||
|
"Renderer",
|
||||||
|
() -> ExoPlaybackException.createForRenderer(
|
||||||
|
new Exception(defaultMsg),
|
||||||
|
"Dummy renderer",
|
||||||
|
0,
|
||||||
|
null,
|
||||||
|
RendererCapabilities.FORMAT_HANDLED
|
||||||
|
)
|
||||||
|
);
|
||||||
|
exceptionTypes.put(
|
||||||
|
"Unexpected",
|
||||||
|
() -> ExoPlaybackException.createForUnexpected(
|
||||||
|
new RuntimeException(defaultMsg)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
exceptionTypes.put(
|
||||||
|
"Remote",
|
||||||
|
() -> ExoPlaybackException.createForRemote(defaultMsg)
|
||||||
|
);
|
||||||
|
exceptionTypes.put(
|
||||||
|
"Timeout",
|
||||||
|
() -> ExoPlaybackException.createForTimeout(
|
||||||
|
new TimeoutException(defaultMsg),
|
||||||
|
ExoPlaybackException.TIMEOUT_OPERATION_UNDEFINED
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return exceptionTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Context getContext() {
|
||||||
|
return this.contextSupplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private LayoutInflater getLayoutInflater() {
|
||||||
|
return this.layoutInflaterSupplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Context getThemeWrapperContext() {
|
||||||
|
return new ContextThemeWrapper(
|
||||||
|
getContext(),
|
||||||
|
ThemeHelper.isLightThemeSelected(getContext())
|
||||||
|
? R.style.LightTheme
|
||||||
|
: R.style.DarkTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onCrashThePlayer(final Player player) {
|
||||||
|
if (!isPlayerAvailable(player)) {
|
||||||
|
Log.d(TAG, "Player is not available");
|
||||||
|
Toast.makeText(getContext(), "Player is not available", Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Context themeWrapperContext = getThemeWrapperContext();
|
||||||
|
|
||||||
|
final LayoutInflater inflater = LayoutInflater.from(themeWrapperContext);
|
||||||
|
final RadioGroup radioGroup = SingleChoiceDialogViewBinding.inflate(getLayoutInflater())
|
||||||
|
.list;
|
||||||
|
|
||||||
|
final AlertDialog alertDialog = new AlertDialog.Builder(getThemeWrapperContext())
|
||||||
|
.setTitle("Choose an exception")
|
||||||
|
.setView(radioGroup)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
for (final Map.Entry<String, Supplier<ExoPlaybackException>> entry
|
||||||
|
: getExceptionTypes().entrySet()) {
|
||||||
|
final RadioButton radioButton = ListRadioIconItemBinding.inflate(inflater).getRoot();
|
||||||
|
radioButton.setText(entry.getKey());
|
||||||
|
radioButton.setChecked(false);
|
||||||
|
radioButton.setLayoutParams(
|
||||||
|
new RadioGroup.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
)
|
||||||
|
);
|
||||||
|
radioButton.setOnClickListener(v -> {
|
||||||
|
tryCrashPlayerWith(player, entry.getValue().get());
|
||||||
|
if (alertDialog != null) {
|
||||||
|
alertDialog.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
radioGroup.addView(radioButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
alertDialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryCrashPlayerWith(
|
||||||
|
@NonNull final Player player,
|
||||||
|
@NonNull final ExoPlaybackException exception
|
||||||
|
) {
|
||||||
|
Log.d(TAG, "Crashing the player using player.onPlayerError(ex)");
|
||||||
|
try {
|
||||||
|
player.onPlayerError(exception);
|
||||||
|
} catch (final Exception exPlayer) {
|
||||||
|
Log.e(TAG,
|
||||||
|
"Run into an exception while crashing the player:",
|
||||||
|
exPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPlayerAvailable(final Player player) {
|
||||||
|
return player != null;
|
||||||
|
}
|
||||||
|
}
|
@ -213,7 +213,7 @@
|
|||||||
android:layout_below="@id/detail_title_root_layout"
|
android:layout_below="@id/detail_title_root_layout"
|
||||||
android:layout_marginTop="@dimen/video_item_detail_error_panel_margin"
|
android:layout_marginTop="@dimen/video_item_detail_error_panel_margin"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible" />
|
tools:visibility="gone" />
|
||||||
|
|
||||||
<!--HIDING ROOT-->
|
<!--HIDING ROOT-->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@ -547,6 +547,22 @@
|
|||||||
android:textSize="@dimen/detail_control_text_size"
|
android:textSize="@dimen/detail_control_text_size"
|
||||||
app:drawableTopCompat="@drawable/ic_cast" />
|
app:drawableTopCompat="@drawable/ic_cast" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_controls_crash_the_player"
|
||||||
|
android:layout_width="@dimen/detail_control_width"
|
||||||
|
android:layout_height="@dimen/detail_control_height"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/crash_the_player"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingVertical="@dimen/detail_control_padding"
|
||||||
|
android:text="@string/crash_the_player"
|
||||||
|
android:textSize="@dimen/detail_control_text_size"
|
||||||
|
app:drawableTopCompat="@drawable/ic_bug_report" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
|
@ -190,6 +190,7 @@
|
|||||||
<string name="disable_media_tunneling_key" translatable="false">disable_media_tunneling_key</string>
|
<string name="disable_media_tunneling_key" translatable="false">disable_media_tunneling_key</string>
|
||||||
<string name="crash_the_app_key" translatable="false">crash_the_app_key</string>
|
<string name="crash_the_app_key" translatable="false">crash_the_app_key</string>
|
||||||
<string name="show_image_indicators_key" translatable="false">show_image_indicators_key</string>
|
<string name="show_image_indicators_key" translatable="false">show_image_indicators_key</string>
|
||||||
|
<string name="show_crash_the_player_key" translatable="false">show_crash_the_player_key</string>
|
||||||
|
|
||||||
<!-- THEMES -->
|
<!-- THEMES -->
|
||||||
<string name="theme_key" translatable="false">theme</string>
|
<string name="theme_key" translatable="false">theme</string>
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
<string name="kore_package" translatable="false">org.xbmc.kore</string>
|
<string name="kore_package" translatable="false">org.xbmc.kore</string>
|
||||||
<string name="show_play_with_kodi_title">Show \"Play with Kodi\" option</string>
|
<string name="show_play_with_kodi_title">Show \"Play with Kodi\" option</string>
|
||||||
<string name="show_play_with_kodi_summary">Display an option to play a video via Kodi media center</string>
|
<string name="show_play_with_kodi_summary">Display an option to play a video via Kodi media center</string>
|
||||||
|
<string name="crash_the_player">Crash the player</string>
|
||||||
<string name="report_player_errors_title">Report player errors</string>
|
<string name="report_player_errors_title">Report player errors</string>
|
||||||
<string name="report_player_errors_summary">Reports player errors in full detail instead of showing a short-lived toast message (useful for diagnosing problems)</string>
|
<string name="report_player_errors_summary">Reports player errors in full detail instead of showing a short-lived toast message (useful for diagnosing problems)</string>
|
||||||
<string name="notification_scale_to_square_image_title">Scale thumbnail to 1:1 aspect ratio</string>
|
<string name="notification_scale_to_square_image_title">Scale thumbnail to 1:1 aspect ratio</string>
|
||||||
@ -475,6 +476,8 @@
|
|||||||
<string name="show_image_indicators_title">Show image indicators</string>
|
<string name="show_image_indicators_title">Show image indicators</string>
|
||||||
<string name="show_image_indicators_summary">Show Picasso colored ribbons on top of images indicating their source: red for network, blue for disk and green for memory</string>
|
<string name="show_image_indicators_summary">Show Picasso colored ribbons on top of images indicating their source: red for network, blue for disk and green for memory</string>
|
||||||
<string name="crash_the_app">Crash the app</string>
|
<string name="crash_the_app">Crash the app</string>
|
||||||
|
<string name="show_crash_the_player_title">Show \"crash the player\"</string>
|
||||||
|
<string name="show_crash_the_player_summary">Shows a crash option when using the player</string>
|
||||||
<!-- Subscriptions import/export -->
|
<!-- Subscriptions import/export -->
|
||||||
<string name="import_title">Import</string>
|
<string name="import_title">Import</string>
|
||||||
<string name="import_from">Import from</string>
|
<string name="import_from">Import from</string>
|
||||||
|
@ -54,4 +54,13 @@
|
|||||||
android:title="@string/crash_the_app"
|
android:title="@string/crash_the_app"
|
||||||
app:singleLineTitle="false"
|
app:singleLineTitle="false"
|
||||||
app:iconSpaceReserved="false" />
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="@string/show_crash_the_player_key"
|
||||||
|
android:summary="@string/show_crash_the_player_summary"
|
||||||
|
android:title="@string/show_crash_the_player_title"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
Loading…
Reference in New Issue
Block a user