Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 58 additions & 15 deletions app/src/main/java/com/brouken/player/PlayerActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.UriPermission;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
Expand Down Expand Up @@ -97,6 +98,7 @@

import com.brouken.player.dtpv.DoubleTapPlayerView;
import com.brouken.player.dtpv.youtube.YouTubeOverlay;
import com.brouken.player.osd.OsdSettingsController;
import com.getkeepsafe.taptargetview.TapTarget;
import com.getkeepsafe.taptargetview.TapTargetView;
import com.google.android.material.snackbar.Snackbar;
Expand All @@ -123,6 +125,7 @@ public class PlayerActivity extends Activity {
public CustomPlayerView playerView;
public static ExoPlayer player;
private YouTubeOverlay youTubeOverlay;
private OsdSettingsController osdSettingsController;

private Object mPictureInPictureParamsBuilder;

Expand All @@ -145,7 +148,7 @@ public class PlayerActivity extends Activity {
private static final int REQUEST_CHOOSER_VIDEO_MEDIASTORE = 20;
private static final int REQUEST_CHOOSER_SUBTITLE_MEDIASTORE = 21;
private static final int REQUEST_SETTINGS = 100;
private static final int REQUEST_SYSTEM_CAPTIONS = 200;
public static final int REQUEST_SYSTEM_CAPTIONS = 200;
public static final int CONTROLLER_TIMEOUT = 3500;
private static final String ACTION_MEDIA_CONTROL = "media_control";
private static final String EXTRA_CONTROL_TYPE = "control_type";
Expand All @@ -170,7 +173,7 @@ public class PlayerActivity extends Activity {
private boolean restorePlayState;
private boolean restorePlayStateAllowed;
private boolean play;
private float subtitlesScale;
// private float subtitlesScale;
private boolean isScrubbing;
private boolean scrubbingNoticeable;
private long scrubbingStart;
Expand Down Expand Up @@ -247,6 +250,8 @@ protected void onCreate(Bundle savedInstanceState) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
}

mPrefs.mSharedPreferences.registerOnSharedPreferenceChangeListener(preferenceListener);

final Intent launchIntent = getIntent();
final String action = launchIntent.getAction();
final String type = launchIntent.getType();
Expand Down Expand Up @@ -551,6 +556,9 @@ public void onScrubStop(TimeBar timeBar, long position, boolean canceled) {
}
return windowInsets;
});

osdSettingsController = new OsdSettingsController(this);

timeBar.setAdMarkerColor(Color.argb(0x00, 0xFF, 0xFF, 0xFF));
timeBar.setPlayedAdMarkerColor(Color.argb(0x98, 0xFF, 0xFF, 0xFF));

Expand Down Expand Up @@ -606,8 +614,7 @@ public void onScrubStop(TimeBar timeBar, long position, boolean canceled) {
});

exoSubtitle.setOnLongClickListener(v -> {
enableRotation();
safelyStartActivityForResult(new Intent(Settings.ACTION_CAPTIONING_SETTINGS), REQUEST_SYSTEM_CAPTIONS);
osdSettingsController.showSubtitleSettings();
return true;
});

Expand Down Expand Up @@ -758,6 +765,12 @@ public void onStop() {
releasePlayer(false);
}

@Override
protected void onDestroy() {
super.onDestroy();
mPrefs.mSharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceListener);
}

@Override
public void onBackPressed() {
restorePlayStateAllowed = false;
Expand Down Expand Up @@ -1596,7 +1609,7 @@ public void onPlayerError(PlaybackException error) {
}
}

private void enableRotation() {
public void enableRotation() {
try {
if (Settings.System.getInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION) == 0) {
Settings.System.putInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 1);
Expand Down Expand Up @@ -1697,7 +1710,7 @@ private Intent createBaseFileIntent(final String action, final Uri initialUri) {
return intent;
}

void safelyStartActivityForResult(final Intent intent, final int code) {
public void safelyStartActivityForResult(final Intent intent, final int code) {
if (intent.resolveActivity(getPackageManager()) == null)
showSnack(getText(R.string.error_files_missing).toString(), intent.toString());
else
Expand Down Expand Up @@ -1790,10 +1803,16 @@ public String getSelectedTrack(final int trackType) {
}

void setSubtitleTextSize() {
setSubtitleTextSize(getResources().getConfiguration().orientation);
// setSubtitleTextSize(getResources().getConfiguration().orientation);

final SubtitleView subtitleView = playerView.getSubtitleView();
if (subtitleView != null) {
final CaptioningManager captioningManager = (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE);
SubtitleUtils.updateFractionalTextSize(subtitleView, captioningManager, mPrefs);
}
}

void setSubtitleTextSize(final int orientation) {
/*void setSubtitleTextSize(final int orientation) {
// Tweak text size as fraction size doesn't work well in portrait
final SubtitleView subtitleView = playerView.getSubtitleView();
if (subtitleView != null) {
Expand All @@ -1810,7 +1829,7 @@ void setSubtitleTextSize(final int orientation) {

subtitleView.setFractionalTextSize(size);
}
}
}*/

void updateSubtitleViewMargin() {
if (player == null) {
Expand Down Expand Up @@ -1839,6 +1858,13 @@ void updateSubtitleViewMargin(Format format) {
int videoWidth = metrics.heightPixels / aspectVideo.getDenominator() * aspectVideo.getNumerator();
marginHorizontal = (metrics.widthPixels - videoWidth) / 2;
}
} else {
// SubtitleView’s height must be the same in both landscape
// and portrait modes to maintain the same subtitle size.
DisplayMetrics realMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getRealMetrics(realMetrics);
int minMarginVertical = (realMetrics.heightPixels - realMetrics.widthPixels) / 2;
if (marginVertical < minMarginVertical) marginVertical = minMarginVertical;
}

Utils.setViewParams(playerView.getSubtitleView(), 0, 0, 0, 0,
Expand Down Expand Up @@ -1884,7 +1910,7 @@ public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);

if (!isInPip()) {
setSubtitleTextSize(newConfig.orientation);
setSubtitleTextSize(/*newConfig.orientation*/);
}
updateSubtitleViewMargin();

Expand Down Expand Up @@ -1949,24 +1975,30 @@ void reportScrubbing(long position) {
void updateSubtitleStyle(final Context context) {
final CaptioningManager captioningManager = (CaptioningManager) getSystemService(Context.CAPTIONING_SERVICE);
final SubtitleView subtitleView = playerView.getSubtitleView();
final boolean isTablet = Utils.isTablet(context);
subtitlesScale = SubtitleUtils.normalizeFontScale(captioningManager.getFontScale(), isTvBox || isTablet);
// final boolean isTablet = Utils.isTablet(context);
// subtitlesScale = SubtitleUtils.normalizeFontScale(captioningManager.getFontScale(), isTvBox || isTablet);
if (subtitleView != null) {
final CaptioningManager.CaptionStyle userStyle = captioningManager.getUserStyle();
final CaptionStyleCompat userStyleCompat = CaptionStyleCompat.createFromCaptionStyle(userStyle);
final CaptionStyleCompat captionStyle = new CaptionStyleCompat(
userStyle.hasForegroundColor() ? userStyleCompat.foregroundColor : Color.WHITE,
userStyle.hasBackgroundColor() ? userStyleCompat.backgroundColor : Color.TRANSPARENT,
userStyle.hasWindowColor() ? userStyleCompat.windowColor : Color.TRANSPARENT,
userStyle.hasEdgeType() ? userStyleCompat.edgeType : CaptionStyleCompat.EDGE_TYPE_OUTLINE,
SubtitleUtils.getSubtitleEdgeType(mPrefs.subtitleEdgeType, userStyle),
userStyle.hasEdgeColor() ? userStyleCompat.edgeColor : Color.BLACK,
Typeface.create(userStyleCompat.typeface != null ? userStyleCompat.typeface : Typeface.DEFAULT,
mPrefs.subtitleStyleBold ? Typeface.BOLD : Typeface.NORMAL));
subtitleView.setStyle(captionStyle);
subtitleView.setApplyEmbeddedStyles(mPrefs.subtitleStyleEmbedded);
subtitleView.setBottomPaddingFraction(SubtitleView.DEFAULT_BOTTOM_PADDING_FRACTION * 2f / 3f);
updateSubtitleBottomPaddingFraction(mPrefs.subtitleVerticalPosition);
SubtitleUtils.updateFractionalTextSize(subtitleView, captioningManager, mPrefs);
}
setSubtitleTextSize();
// setSubtitleTextSize();
}

private void updateSubtitleBottomPaddingFraction(int subtitleVerticalPosition) {
float bottomPaddingFraction = SubtitleView.DEFAULT_BOTTOM_PADDING_FRACTION + (subtitleVerticalPosition * 0.01f);
playerView.getSubtitleView().setBottomPaddingFraction(bottomPaddingFraction);
}

void searchSubtitles() {
Expand Down Expand Up @@ -2317,4 +2349,15 @@ private void updateButtonRotation() {
}
}
}

private final SharedPreferences.OnSharedPreferenceChangeListener preferenceListener = (sharedPreferences, key) -> {
switch (key) {
case Prefs.PREF_KEY_SUBTITLE_VERTICAL_POSITION:
case Prefs.PREF_KEY_SUBTITLE_SIZE:
case Prefs.PREF_KEY_SUBTITLE_EDGE_TYPE:
case Prefs.PREF_KEY_SUBTITLE_STYLE_BOLD:
case Prefs.PREF_KEY_SUBTITLE_STYLE_EMBEDDED:
updateSubtitleStyle(PlayerActivity.this);
}
};
}
63 changes: 60 additions & 3 deletions app/src/main/java/com/brouken/player/Prefs.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@
import android.net.Uri;
import android.preference.PreferenceManager;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.media3.exoplayer.DefaultRenderersFactory;
import androidx.media3.ui.AspectRatioFrameLayout;

import com.brouken.player.osd.subtitle.SubtitleEdgeType;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.LinkedHashMap;
import java.util.Set;

class Prefs {
public class Prefs {
// Previously used
// private static final String PREF_KEY_AUDIO_TRACK = "audioTrack";
// private static final String PREF_KEY_AUDIO_TRACK_FFMPEG = "audioTrackFfmpeg";
Expand Down Expand Up @@ -45,8 +49,11 @@ class Prefs {
private static final String PREF_KEY_DECODER_PRIORITY = "decoderPriority";
private static final String PREF_KEY_MAP_DV7 = "mapDV7ToHevc";
private static final String PREF_KEY_LANGUAGE_AUDIO = "languageAudio";
private static final String PREF_KEY_SUBTITLE_STYLE_EMBEDDED = "subtitleStyleEmbedded";
private static final String PREF_KEY_SUBTITLE_STYLE_BOLD = "subtitleStyleBold";
static final String PREF_KEY_SUBTITLE_STYLE_EMBEDDED = "subtitleStyleEmbedded";
static final String PREF_KEY_SUBTITLE_STYLE_BOLD = "subtitleStyleBold";
static final String PREF_KEY_SUBTITLE_VERTICAL_POSITION = "subtitleVerticalPosition";
static final String PREF_KEY_SUBTITLE_SIZE = "subtitleSize";
static final String PREF_KEY_SUBTITLE_EDGE_TYPE = "subtitleEdgeType";

public static final String TRACK_DEFAULT = "default";
public static final String TRACK_DEVICE = "device";
Expand Down Expand Up @@ -81,6 +88,9 @@ class Prefs {
public String languageAudio = TRACK_DEVICE;
public boolean subtitleStyleEmbedded = true;
public boolean subtitleStyleBold = false;
public int subtitleVerticalPosition = 0;
public int subtitleSize = 0;
public SubtitleEdgeType subtitleEdgeType = SubtitleEdgeType.Default;

private LinkedHashMap positions;

Expand All @@ -94,6 +104,15 @@ public Prefs(Context context) {
loadPositions();
}

private static <T extends Enum<T>> T valueOfEnum(@NonNull Class<T> clazz, @Nullable String name, @NonNull T defaultValue) {
if (name == null) return defaultValue;
try {
return Enum.valueOf(clazz, name);
} catch (IllegalArgumentException e) {
return defaultValue;
}
}

private void loadSavedPreferences() {
if (mSharedPreferences.contains(PREF_KEY_MEDIA_URI))
mediaUri = Uri.parse(mSharedPreferences.getString(PREF_KEY_MEDIA_URI, null));
Expand Down Expand Up @@ -130,6 +149,9 @@ public void loadUserPreferences() {
languageAudio = mSharedPreferences.getString(PREF_KEY_LANGUAGE_AUDIO, languageAudio);
subtitleStyleEmbedded = mSharedPreferences.getBoolean(PREF_KEY_SUBTITLE_STYLE_EMBEDDED, subtitleStyleEmbedded);
subtitleStyleBold = mSharedPreferences.getBoolean(PREF_KEY_SUBTITLE_STYLE_BOLD, subtitleStyleBold);
subtitleVerticalPosition = mSharedPreferences.getInt(PREF_KEY_SUBTITLE_VERTICAL_POSITION, subtitleVerticalPosition);
subtitleSize = mSharedPreferences.getInt(PREF_KEY_SUBTITLE_SIZE, subtitleSize);
subtitleEdgeType = valueOfEnum(SubtitleEdgeType.class, mSharedPreferences.getString(PREF_KEY_SUBTITLE_EDGE_TYPE, null), subtitleEdgeType);
}

public void updateMedia(final Context context, final Uri uri, final String type) {
Expand Down Expand Up @@ -309,6 +331,41 @@ public void updateScope(final Uri uri) {
sharedPreferencesEditor.apply();
}

public void updateSubtitleVerticalPosition(final int subtitleVerticalPosition) {
this.subtitleVerticalPosition = subtitleVerticalPosition;
final SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit();
sharedPreferencesEditor.putInt(PREF_KEY_SUBTITLE_VERTICAL_POSITION, subtitleVerticalPosition);
sharedPreferencesEditor.apply();
}

public void updateSubtitleSize(final int subtitleSize) {
this.subtitleSize = subtitleSize;
final SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit();
sharedPreferencesEditor.putInt(PREF_KEY_SUBTITLE_SIZE, subtitleSize);
sharedPreferencesEditor.apply();
}

public void updateSubtitleEdgeType(final SubtitleEdgeType subtitleEdgeType) {
this.subtitleEdgeType = subtitleEdgeType;
final SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit();
sharedPreferencesEditor.putString(PREF_KEY_SUBTITLE_EDGE_TYPE, subtitleEdgeType.name());
sharedPreferencesEditor.apply();
}

public void updateSubtitleStyleBold(final boolean subtitleStyleBold) {
this.subtitleStyleBold = subtitleStyleBold;
final SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit();
sharedPreferencesEditor.putBoolean(PREF_KEY_SUBTITLE_STYLE_BOLD, subtitleStyleBold);
sharedPreferencesEditor.apply();
}

public void updateSubtitleStyleEmbedded(final boolean subtitleStyleEmbedded) {
this.subtitleStyleEmbedded = subtitleStyleEmbedded;
final SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit();
sharedPreferencesEditor.putBoolean(PREF_KEY_SUBTITLE_STYLE_EMBEDDED, subtitleStyleEmbedded);
sharedPreferencesEditor.apply();
}

public void setPersistent(boolean persistentMode) {
this.persistentMode = persistentMode;
}
Expand Down
33 changes: 32 additions & 1 deletion app/src/main/java/com/brouken/player/SubtitleUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
import android.view.accessibility.CaptioningManager;

import androidx.documentfile.provider.DocumentFile;
import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MimeTypes;
import androidx.media3.ui.CaptionStyleCompat;
import androidx.media3.ui.SubtitleView;

import com.brouken.player.osd.subtitle.SubtitleEdgeType;

import java.io.File;
import java.util.ArrayList;
Expand Down Expand Up @@ -282,7 +287,7 @@ public static MediaItem.SubtitleConfiguration buildSubtitle(Context context, Uri
return subtitleConfigurationBuilder.build();
}

public static float normalizeFontScale(float fontScale, boolean small) {
/*public static float normalizeFontScale(float fontScale, boolean small) {
// https://bbc.github.io/subtitle-guidelines/#Presentation-font-size
float newScale;
// ¯\_(ツ)_/¯
Expand All @@ -306,5 +311,31 @@ public static float normalizeFontScale(float fontScale, boolean small) {
newScale = (small ? 0.85f : 1.0f);
}
return newScale;
}*/

public static void updateFractionalTextSize(SubtitleView subtitleView, CaptioningManager captioningManager, Prefs prefs) {
float fontScale = captioningManager.getFontScale();
int subtitleSize = prefs.subtitleSize;
float fractionalTextSize = (SubtitleView.DEFAULT_TEXT_SIZE_FRACTION * fontScale) + (subtitleSize * 0.001f);
subtitleView.setFractionalTextSize(fractionalTextSize);
}

public static @CaptionStyleCompat.EdgeType int getSubtitleEdgeType(SubtitleEdgeType subtitleEdgeType, CaptioningManager.CaptionStyle captionStyle) {
switch (subtitleEdgeType) {
case Default:
return captionStyle.hasEdgeType() ? captionStyle.edgeType : CaptionStyleCompat.EDGE_TYPE_OUTLINE;
case None:
return CaptionStyleCompat.EDGE_TYPE_NONE;
case Outline:
return CaptionStyleCompat.EDGE_TYPE_OUTLINE;
case DropShadow:
return CaptionStyleCompat.EDGE_TYPE_DROP_SHADOW;
case Raised:
return CaptionStyleCompat.EDGE_TYPE_RAISED;
case Depressed:
return CaptionStyleCompat.EDGE_TYPE_DEPRESSED;
default:
throw new IllegalArgumentException("Unknown subtitleEdgeType: " + subtitleEdgeType);
}
}
}
Loading