mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 07:13:00 +00:00 
			
		
		
		
	Merge pull request #10122 from TeamNewPipe/fix/media-tunneling
Disable media tunneling by default on known unsupported devices
This commit is contained in:
		| @@ -15,6 +15,7 @@ import android.widget.Toast; | ||||
| import androidx.activity.result.ActivityResult; | ||||
| import androidx.activity.result.ActivityResultLauncher; | ||||
| import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.appcompat.app.AlertDialog; | ||||
| import androidx.core.content.ContextCompat; | ||||
| import androidx.preference.Preference; | ||||
| @@ -230,8 +231,11 @@ public class ContentSettingsFragment extends BasePreferenceFragment { | ||||
|                         }) | ||||
|                         .setPositiveButton(R.string.ok, (dialog, which) -> { | ||||
|                             dialog.dismiss(); | ||||
|                             manager.loadSharedPreferences(PreferenceManager | ||||
|                                     .getDefaultSharedPreferences(requireContext())); | ||||
|                             final Context context = requireContext(); | ||||
|                             final SharedPreferences prefs = PreferenceManager | ||||
|                                     .getDefaultSharedPreferences(context); | ||||
|                             manager.loadSharedPreferences(prefs); | ||||
|                             cleanImport(context, prefs); | ||||
|                             finishImport(importDataUri); | ||||
|                         }) | ||||
|                         .show(); | ||||
| @@ -243,6 +247,38 @@ public class ContentSettingsFragment extends BasePreferenceFragment { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Remove settings that are not supposed to be imported on different devices | ||||
|      * and reset them to default values. | ||||
|      * @param context the context used for the import | ||||
|      * @param prefs the preferences used while running the import | ||||
|      */ | ||||
|     private void cleanImport(@NonNull final Context context, | ||||
|                              @NonNull final SharedPreferences prefs) { | ||||
|         // Check if media tunnelling needs to be disabled automatically, | ||||
|         // if it was disabled automatically in the imported preferences. | ||||
|         final String tunnelingKey = context.getString(R.string.disable_media_tunneling_key); | ||||
|         final String automaticTunnelingKey = | ||||
|                 context.getString(R.string.disabled_media_tunneling_automatically_key); | ||||
|         // R.string.disable_media_tunneling_key should always be true | ||||
|         // if R.string.disabled_media_tunneling_automatically_key equals 1, | ||||
|         // but we double check here just to be sure and to avoid regressions | ||||
|         // caused by possible later modification of the media tunneling functionality. | ||||
|         // R.string.disabled_media_tunneling_automatically_key == 0: | ||||
|         //     automatic value overridden by user in settings | ||||
|         // R.string.disabled_media_tunneling_automatically_key == -1: not set | ||||
|         final boolean wasMediaTunnelingDisabledAutomatically = | ||||
|                 prefs.getInt(automaticTunnelingKey, -1) == 1 | ||||
|                         && prefs.getBoolean(tunnelingKey, false); | ||||
|         if (wasMediaTunnelingDisabledAutomatically) { | ||||
|             prefs.edit() | ||||
|                     .putInt(automaticTunnelingKey, -1) | ||||
|                     .putBoolean(tunnelingKey, false) | ||||
|                     .apply(); | ||||
|             NewPipeSettings.setMediaTunneling(context); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Save import path and restart system. | ||||
|      * | ||||
|   | ||||
| @@ -67,6 +67,9 @@ class ContentSettingsManager(private val fileLocator: NewPipeFileLocator) { | ||||
|         return ZipHelper.extractFileFromZip(file, fileLocator.settings.path, "newpipe.settings") | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Remove all shared preferences from the app and load the preferences supplied to the manager. | ||||
|      */ | ||||
|     fun loadSharedPreferences(preferences: SharedPreferences) { | ||||
|         try { | ||||
|             val preferenceEditor = preferences.edit() | ||||
|   | ||||
| @@ -1,8 +1,14 @@ | ||||
| package org.schabi.newpipe.settings; | ||||
|  | ||||
| import android.content.SharedPreferences; | ||||
| import android.os.Bundle; | ||||
|  | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.preference.Preference; | ||||
| import androidx.preference.PreferenceManager; | ||||
| import androidx.preference.SwitchPreferenceCompat; | ||||
|  | ||||
| import org.schabi.newpipe.R; | ||||
|  | ||||
| public class ExoPlayerSettingsFragment extends BasePreferenceFragment { | ||||
|  | ||||
| @@ -10,5 +16,30 @@ public class ExoPlayerSettingsFragment extends BasePreferenceFragment { | ||||
|     public void onCreatePreferences(@Nullable final Bundle savedInstanceState, | ||||
|                                     @Nullable final String rootKey) { | ||||
|         addPreferencesFromResourceRegistry(); | ||||
|  | ||||
|         final String disabledMediaTunnelingAutomaticallyKey = | ||||
|                 getString(R.string.disabled_media_tunneling_automatically_key); | ||||
|         final SwitchPreferenceCompat disableMediaTunnelingPref = | ||||
|                 (SwitchPreferenceCompat) requirePreference(R.string.disable_media_tunneling_key); | ||||
|         final SharedPreferences prefs = PreferenceManager | ||||
|                 .getDefaultSharedPreferences(requireContext()); | ||||
|         final boolean mediaTunnelingAutomaticallyDisabled = | ||||
|                 prefs.getInt(disabledMediaTunnelingAutomaticallyKey, -1) == 1; | ||||
|         final String summaryText = getString(R.string.disable_media_tunneling_summary); | ||||
|         disableMediaTunnelingPref.setSummary(mediaTunnelingAutomaticallyDisabled | ||||
|                 ? summaryText + " " + getString(R.string.disable_media_tunneling_automatic_info) | ||||
|                 : summaryText); | ||||
|  | ||||
|         disableMediaTunnelingPref.setOnPreferenceChangeListener((Preference p, Object enabled) -> { | ||||
|                     if (Boolean.FALSE.equals(enabled)) { | ||||
|                         PreferenceManager.getDefaultSharedPreferences(requireContext()) | ||||
|                                 .edit() | ||||
|                                 .putInt(disabledMediaTunnelingAutomaticallyKey, 0) | ||||
|                                 .apply(); | ||||
|                         // the info text might have been shown before | ||||
|                         p.setSummary(R.string.disable_media_tunneling_summary); | ||||
|                     } | ||||
|                     return true; | ||||
|                 }); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| package org.schabi.newpipe.settings; | ||||
|  | ||||
| import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.content.SharedPreferences; | ||||
| import android.os.Build; | ||||
| @@ -15,8 +17,6 @@ import org.schabi.newpipe.util.DeviceUtils; | ||||
| import java.io.File; | ||||
| import java.util.Set; | ||||
|  | ||||
| import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; | ||||
|  | ||||
| /* | ||||
|  * Created by k3b on 07.01.2016. | ||||
|  * | ||||
| @@ -61,7 +61,7 @@ public final class NewPipeSettings { | ||||
|         } | ||||
|  | ||||
|         // first run migrations, then setDefaultValues, since the latter requires the correct types | ||||
|         SettingMigrations.initMigrations(context, isFirstRun); | ||||
|         SettingMigrations.runMigrationsIfNeeded(context, isFirstRun); | ||||
|  | ||||
|         // readAgain is true so that if new settings are added their default value is set | ||||
|         PreferenceManager.setDefaultValues(context, R.xml.main_settings, true); | ||||
| @@ -76,6 +76,8 @@ public final class NewPipeSettings { | ||||
|  | ||||
|         saveDefaultVideoDownloadDirectory(context); | ||||
|         saveDefaultAudioDownloadDirectory(context); | ||||
|  | ||||
|         disableMediaTunnelingIfNecessary(context, isFirstRun); | ||||
|     } | ||||
|  | ||||
|     static void saveDefaultVideoDownloadDirectory(final Context context) { | ||||
| @@ -152,4 +154,49 @@ public final class NewPipeSettings { | ||||
|         return showSearchSuggestions(context, sharedPreferences, | ||||
|                 R.string.show_remote_search_suggestions_key); | ||||
|     } | ||||
|  | ||||
|     private static void disableMediaTunnelingIfNecessary(@NonNull final Context context, | ||||
|                                                          final boolean isFirstRun) { | ||||
|         final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); | ||||
|         final String disabledTunnelingKey = context.getString(R.string.disable_media_tunneling_key); | ||||
|         final String disabledTunnelingAutomaticallyKey = | ||||
|                 context.getString(R.string.disabled_media_tunneling_automatically_key); | ||||
|         final String blacklistVersionKey = | ||||
|                 context.getString(R.string.media_tunneling_device_blacklist_version); | ||||
|  | ||||
|         final int lastMediaTunnelingUpdate = prefs.getInt(blacklistVersionKey, 0); | ||||
|         final boolean wasDeviceBlacklistUpdated = | ||||
|                 DeviceUtils.MEDIA_TUNNELING_DEVICE_BLACKLIST_VERSION != lastMediaTunnelingUpdate; | ||||
|         final boolean wasMediaTunnelingEnabledByUser = | ||||
|                 prefs.getInt(disabledTunnelingAutomaticallyKey, -1) == 0 | ||||
|                         && !prefs.getBoolean(disabledTunnelingKey, false); | ||||
|  | ||||
|         if (Boolean.TRUE.equals(isFirstRun) | ||||
|                 || (wasDeviceBlacklistUpdated && !wasMediaTunnelingEnabledByUser)) { | ||||
|             setMediaTunneling(context); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Check if device does not support media tunneling | ||||
|      * and disable that exoplayer feature if necessary. | ||||
|      * @see DeviceUtils#shouldSupportMediaTunneling() | ||||
|      * @param context | ||||
|      */ | ||||
|     public static void setMediaTunneling(@NonNull final Context context) { | ||||
|         final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); | ||||
|         if (!DeviceUtils.shouldSupportMediaTunneling()) { | ||||
|             prefs.edit() | ||||
|                     .putBoolean(context.getString(R.string.disable_media_tunneling_key), true) | ||||
|                     .putInt(context.getString( | ||||
|                             R.string.disabled_media_tunneling_automatically_key), 1) | ||||
|                     .putInt(context.getString(R.string.media_tunneling_device_blacklist_version), | ||||
|                             DeviceUtils.MEDIA_TUNNELING_DEVICE_BLACKLIST_VERSION) | ||||
|                     .apply(); | ||||
|         } else { | ||||
|             prefs.edit() | ||||
|                     .putInt(context.getString(R.string.media_tunneling_device_blacklist_version), | ||||
|                             DeviceUtils.MEDIA_TUNNELING_DEVICE_BLACKLIST_VERSION).apply(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import android.content.Context; | ||||
| import android.content.SharedPreferences; | ||||
| import android.util.Log; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.preference.PreferenceManager; | ||||
|  | ||||
| import org.schabi.newpipe.R; | ||||
| @@ -30,9 +31,9 @@ public final class SettingMigrations { | ||||
|     private static final String TAG = SettingMigrations.class.toString(); | ||||
|     private static SharedPreferences sp; | ||||
|  | ||||
|     public static final Migration MIGRATION_0_1 = new Migration(0, 1) { | ||||
|     private static final Migration MIGRATION_0_1 = new Migration(0, 1) { | ||||
|         @Override | ||||
|         public void migrate(final Context context) { | ||||
|         public void migrate(@NonNull final Context context) { | ||||
|             // We changed the content of the dialog which opens when sharing a link to NewPipe | ||||
|             // by removing the "open detail page" option. | ||||
|             // Therefore, show the dialog once again to ensure users need to choose again and are | ||||
| @@ -44,9 +45,9 @@ public final class SettingMigrations { | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     public static final Migration MIGRATION_1_2 = new Migration(1, 2) { | ||||
|     private static final Migration MIGRATION_1_2 = new Migration(1, 2) { | ||||
|         @Override | ||||
|         protected void migrate(final Context context) { | ||||
|         protected void migrate(@NonNull final Context context) { | ||||
|             // The new application workflow introduced in #2907 allows minimizing videos | ||||
|             // while playing to do other stuff within the app. | ||||
|             // For an even better workflow, we minimize a stream when switching the app to play in | ||||
| @@ -63,9 +64,9 @@ public final class SettingMigrations { | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     public static final Migration MIGRATION_2_3 = new Migration(2, 3) { | ||||
|     private static final Migration MIGRATION_2_3 = new Migration(2, 3) { | ||||
|         @Override | ||||
|         protected void migrate(final Context context) { | ||||
|         protected void migrate(@NonNull final Context context) { | ||||
|             // Storage Access Framework implementation was improved in #5415, allowing the modern | ||||
|             // and standard way to access folders and files to be used consistently everywhere. | ||||
|             // We reset the setting to its default value, i.e. "use SAF", since now there are no | ||||
| @@ -79,9 +80,9 @@ public final class SettingMigrations { | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     public static final Migration MIGRATION_3_4 = new Migration(3, 4) { | ||||
|     private static final Migration MIGRATION_3_4 = new Migration(3, 4) { | ||||
|         @Override | ||||
|         protected void migrate(final Context context) { | ||||
|         protected void migrate(@NonNull final Context context) { | ||||
|             // Pull request #3546 added support for choosing the type of search suggestions to | ||||
|             // show, replacing the on-off switch used before, so migrate the previous user choice | ||||
|  | ||||
| @@ -108,9 +109,9 @@ public final class SettingMigrations { | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     public static final Migration MIGRATION_4_5 = new Migration(4, 5) { | ||||
|     private static final Migration MIGRATION_4_5 = new Migration(4, 5) { | ||||
|         @Override | ||||
|         protected void migrate(final Context context) { | ||||
|         protected void migrate(@NonNull final Context context) { | ||||
|             final boolean brightness = sp.getBoolean("brightness_gesture_control", true); | ||||
|             final boolean volume = sp.getBoolean("volume_gesture_control", true); | ||||
|  | ||||
| @@ -144,10 +145,11 @@ public final class SettingMigrations { | ||||
|     /** | ||||
|      * Version number for preferences. Must be incremented every time a migration is necessary. | ||||
|      */ | ||||
|     public static final int VERSION = 5; | ||||
|     private static final int VERSION = 5; | ||||
|  | ||||
|  | ||||
|     public static void initMigrations(final Context context, final boolean isFirstRun) { | ||||
|     public static void runMigrationsIfNeeded(@NonNull final Context context, | ||||
|                                              final boolean isFirstRun) { | ||||
|         // setup migrations and check if there is something to do | ||||
|         sp = PreferenceManager.getDefaultSharedPreferences(context); | ||||
|         final String lastPrefVersionKey = context.getString(R.string.last_used_preferences_version); | ||||
| @@ -212,7 +214,7 @@ public final class SettingMigrations { | ||||
|             return oldVersion >= currentVersion; | ||||
|         } | ||||
|  | ||||
|         protected abstract void migrate(Context context); | ||||
|         protected abstract void migrate(@NonNull Context context); | ||||
|  | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -36,6 +36,91 @@ public final class DeviceUtils { | ||||
|     private static Boolean isTV = null; | ||||
|     private static Boolean isFireTV = null; | ||||
|  | ||||
|     /** | ||||
|      * <p>The app version code that corresponds to the last update | ||||
|      * of the media tunneling device blacklist.</p> | ||||
|      * <p>The value of this variable needs to be updated everytime a new device that does not | ||||
|      * support media tunneling to match the <strong>upcoming</strong> version code.</p> | ||||
|      * @see #shouldSupportMediaTunneling() | ||||
|      */ | ||||
|     public static final int MEDIA_TUNNELING_DEVICE_BLACKLIST_VERSION = 994; | ||||
|  | ||||
|     // region: devices not supporting media tunneling / media tunneling blacklist | ||||
|     /** | ||||
|      * <p>Formuler Z8 Pro, Z8, CC, Z Alpha, Z+ Neo.</p> | ||||
|      * <p>Blacklist reason: black screen</p> | ||||
|      * <p>Board: HiSilicon Hi3798MV200</p> | ||||
|      */ | ||||
|     private static final boolean HI3798MV200 = Build.VERSION.SDK_INT == 24 | ||||
|             && Build.DEVICE.equals("Hi3798MV200"); | ||||
|     /** | ||||
|      * <p>Zephir TS43UHD-2.</p> | ||||
|      * <p>Blacklist reason: black screen</p> | ||||
|      */ | ||||
|     private static final boolean CVT_MT5886_EU_1G = Build.VERSION.SDK_INT == 24 | ||||
|             && Build.DEVICE.equals("cvt_mt5886_eu_1g"); | ||||
|     /** | ||||
|      * Hilife TV. | ||||
|      * <p>Blacklist reason: black screen</p> | ||||
|      */ | ||||
|     private static final boolean REALTEKATV = Build.VERSION.SDK_INT == 25 | ||||
|             && Build.DEVICE.equals("RealtekATV"); | ||||
|     /** | ||||
|      * <p>Phillips 4K (O)LED TV.</p> | ||||
|      * Supports custom ROMs with different API levels | ||||
|      */ | ||||
|     private static final boolean PH7M_EU_5596 = Build.VERSION.SDK_INT >= 26 | ||||
|             && Build.DEVICE.equals("PH7M_EU_5596"); | ||||
|     /** | ||||
|      * <p>Philips QM16XE.</p> | ||||
|      * <p>Blacklist reason: black screen</p> | ||||
|      */ | ||||
|     private static final boolean QM16XE_U = Build.VERSION.SDK_INT == 23 | ||||
|             && Build.DEVICE.equals("QM16XE_U"); | ||||
|     /** | ||||
|      * <p>Sony Bravia VH1.</p> | ||||
|      * <p>Processor: MT5895</p> | ||||
|      * <p>Blacklist reason: fullscreen crash / stuttering</p> | ||||
|      */ | ||||
|     private static final boolean BRAVIA_VH1 = Build.VERSION.SDK_INT == 29 | ||||
|             && Build.DEVICE.equals("BRAVIA_VH1"); | ||||
|     /** | ||||
|      * <p>Sony Bravia VH2.</p> | ||||
|      * <p>Blacklist reason: fullscreen crash; this includes model A90J as reported in | ||||
|      * <a href="https://github.com/TeamNewPipe/NewPipe/issues/9023#issuecomment-1387106242"> | ||||
|      * #9023</a></p> | ||||
|      */ | ||||
|     private static final boolean BRAVIA_VH2 = Build.VERSION.SDK_INT == 29 | ||||
|             && Build.DEVICE.equals("BRAVIA_VH2"); | ||||
|     /** | ||||
|      * <p>Sony Bravia Android TV platform 2.</p> | ||||
|      * Uses a MediaTek MT5891 (MT5596) SoC. | ||||
|      * @see <a href="https://github.com/CiNcH83/bravia_atv2"> | ||||
|      *     https://github.com/CiNcH83/bravia_atv2</a> | ||||
|      */ | ||||
|     private static final boolean BRAVIA_ATV2 = Build.DEVICE.equals("BRAVIA_ATV2"); | ||||
|     /** | ||||
|      * <p>Sony Bravia Android TV platform 3 4K.</p> | ||||
|      * <p>Uses ARM MT5891 and a {@link #BRAVIA_ATV2} motherboard.</p> | ||||
|      * | ||||
|      * @see <a href="https://browser.geekbench.com/v4/cpu/9101105"> | ||||
|      *     https://browser.geekbench.com/v4/cpu/9101105</a> | ||||
|      */ | ||||
|     private static final boolean BRAVIA_ATV3_4K = Build.DEVICE.equals("BRAVIA_ATV3_4K"); | ||||
|     /** | ||||
|      * <p>Panasonic 4KTV-JUP.</p> | ||||
|      * <p>Blacklist reason: fullscreen crash</p> | ||||
|      */ | ||||
|     private static final boolean TX_50JXW834 = Build.DEVICE.equals("TX_50JXW834"); | ||||
|     /** | ||||
|      * <p>Bouygtel4K / Bouygues Telecom Bbox 4K.</p> | ||||
|      * <p>Blacklist reason: black screen; reported at | ||||
|      * <a href="https://github.com/TeamNewPipe/NewPipe/pull/10122#issuecomment-1638475769"> | ||||
|      *     #10122</a></p> | ||||
|      */ | ||||
|     private static final boolean HMB9213NW = Build.DEVICE.equals("HMB9213NW"); | ||||
|     // endregion | ||||
|  | ||||
|     private DeviceUtils() { | ||||
|     } | ||||
|  | ||||
| @@ -224,4 +309,30 @@ public final class DeviceUtils { | ||||
|             return point.y; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * <p>Some devices have broken tunneled video playback but claim to support it.</p> | ||||
|      * <p>This can cause a black video player surface while attempting to play a video or | ||||
|      * crashes while entering or exiting the full screen player. | ||||
|      * The issue effects Android TVs most commonly. | ||||
|      * See <a href="https://github.com/TeamNewPipe/NewPipe/issues/5911">#5911</a> and | ||||
|      * <a href="https://github.com/TeamNewPipe/NewPipe/issues/9023">#9023</a> for more info.</p> | ||||
|      * @Note Update {@link #MEDIA_TUNNELING_DEVICE_BLACKLIST_VERSION} | ||||
|      * when adding a new device to the method. | ||||
|      * @return {@code false} if affected device; {@code true} otherwise | ||||
|      */ | ||||
|     public static boolean shouldSupportMediaTunneling() { | ||||
|         // Maintainers note: update MEDIA_TUNNELING_DEVICES_UPDATE_APP_VERSION_CODE | ||||
|         return !HI3798MV200 | ||||
|                 && !CVT_MT5886_EU_1G | ||||
|                 && !REALTEKATV | ||||
|                 && !QM16XE_U | ||||
|                 && !BRAVIA_VH1 | ||||
|                 && !BRAVIA_VH2 | ||||
|                 && !BRAVIA_ATV2 | ||||
|                 && !BRAVIA_ATV3_4K | ||||
|                 && !PH7M_EU_5596 | ||||
|                 && !TX_50JXW834 | ||||
|                 && !HMB9213NW; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1382,6 +1382,8 @@ | ||||
|     <!-- ExoPlayer settings --> | ||||
|     <string name="exoplayer_settings_key">exoplayer_settings_key</string> | ||||
|     <string name="disable_media_tunneling_key">disable_media_tunneling_key</string> | ||||
|     <string name="disabled_media_tunneling_automatically_key">disabled_media_tunneling_automatically_key</string> | ||||
|     <string name="media_tunneling_device_blacklist_version">media_tunneling_device_blacklist_version</string> | ||||
|     <string name="use_exoplayer_decoder_fallback_key">use_exoplayer_decoder_fallback_key</string> | ||||
|     <string name="always_use_exoplayer_set_output_surface_workaround_key">always_use_exoplayer_set_output_surface_workaround_key</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -480,7 +480,8 @@ | ||||
|     <string name="show_original_time_ago_title">Show original time ago on items</string> | ||||
|     <string name="show_original_time_ago_summary">Original texts from services will be visible in stream items</string> | ||||
|     <string name="disable_media_tunneling_title">Disable media tunneling</string> | ||||
|     <string name="disable_media_tunneling_summary">Disable media tunneling if you experience a black screen or stuttering on video playback</string> | ||||
|     <string name="disable_media_tunneling_summary">Disable media tunneling if you experience a black screen or stuttering on video playback.</string> | ||||
|     <string name="disable_media_tunneling_automatic_info">Media tunneling was disabled by default on your device because your device model is known to not support it.</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_crash_the_player_title">Show \"Crash the player\"</string> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Tobi
					Tobi