From 36d42d5cb8811ad7d0a7e0b7199fe423c179f740 Mon Sep 17 00:00:00 2001 From: Andrey Pavlenko Date: Tue, 25 May 2021 02:33:52 +0300 Subject: [PATCH] Added web browser User-Agent settings. Fixes --- build.gradle | 4 +- depends/utils | 2 +- .../me/aap/fermata/ui/view/BodyLayout.java | 4 +- .../me/aap/fermata/ui/view/VideoView.java | 39 ++++---- .../engine/exoplayer/ExoPlayerEngine.java | 8 +- .../me/aap/fermata/engine/vlc/VlcEngine.java | 39 +------- .../aap/fermata/addon/web/FermataWebView.java | 98 +++++++++++++------ .../fermata/addon/web/WebBrowserAddon.java | 35 +++++++ .../web/src/main/res/values-ru/strings.xml | 1 + modules/web/src/main/res/values/strings.xml | 2 + 10 files changed, 140 insertions(+), 92 deletions(-) diff --git a/build.gradle b/build.gradle index 081773c4..ac191fad 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ ext { def abi = project.properties['ABI'] - VERSION_CODE = 90 - VERSION_NAME = "1.7.9" + VERSION_CODE = 91 + VERSION_NAME = "1.7.10" SDK_MIN_VERSION = 23 SDK_TARGET_VERSION = 30 SDK_COMPILE_VERSION = 30 diff --git a/depends/utils b/depends/utils index 5bf7944a..913f2f9f 160000 --- a/depends/utils +++ b/depends/utils @@ -1 +1 @@ -Subproject commit 5bf7944a4c47dfd0ec57ed2969faa89aff91866e +Subproject commit 913f2f9f3d55890766b83181d76e286a22f7b849 diff --git a/fermata/src/main/java/me/aap/fermata/ui/view/BodyLayout.java b/fermata/src/main/java/me/aap/fermata/ui/view/BodyLayout.java index f21874da..72412815 100644 --- a/fermata/src/main/java/me/aap/fermata/ui/view/BodyLayout.java +++ b/fermata/src/main/java/me/aap/fermata/ui/view/BodyLayout.java @@ -88,7 +88,7 @@ public void setMode(Mode mode) { getSplitHandle().setVisibility(GONE); getSwipeRefresh().setVisibility(GONE); lp.guidePercent = isPortrait() ? 1f : 0f; - vv.showVideo(); + vv.showVideo(true); getActivity().setVideoMode(true, vv); App.get().getHandler().post(vv::requestFocus); break; @@ -98,6 +98,7 @@ public void setMode(Mode mode) { getSplitHandle().setVisibility(VISIBLE); getSwipeRefresh().setVisibility(VISIBLE); lp.guidePercent = getActivity().getPrefs().getSplitPercent(getContext()); + vv.showVideo(true); getActivity().setVideoMode(false, vv); break; } @@ -196,6 +197,7 @@ public void onPlayableChanged(MediaLib.PlayableItem oldItem, MediaLib.PlayableIt setMode(BodyLayout.Mode.FRAME); } else { if (isFrameMode()) setMode(BodyLayout.Mode.VIDEO); + else getVideoView().showVideo(false); } } diff --git a/fermata/src/main/java/me/aap/fermata/ui/view/VideoView.java b/fermata/src/main/java/me/aap/fermata/ui/view/VideoView.java index d521b8c5..bc302eeb 100644 --- a/fermata/src/main/java/me/aap/fermata/ui/view/VideoView.java +++ b/fermata/src/main/java/me/aap/fermata/ui/view/VideoView.java @@ -72,6 +72,16 @@ protected void init(Context context) { getHolder().addCallback(VideoView.this); } }); + addView(new SurfaceView(getContext()) { + { + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT); + lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; + setLayoutParams(lp); + setZOrderMediaOverlay(true); + getHolder().setFormat(PixelFormat.TRANSLUCENT); + getHolder().addCallback(VideoView.this); + } + }); addTitle(context); setLayoutParams(new CircularRevealFrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); @@ -93,30 +103,15 @@ public SurfaceView getVideoSurface() { return (SurfaceView) getChildAt(0); } - public SurfaceView getSubtitleSurface(boolean create) { - if (getChildCount() < 3) { - if (!create) return null; - removeViewAt(1); - Context ctx = getContext(); - SurfaceView v = new SurfaceView(ctx); - FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT); - lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; - v.setLayoutParams(lp); - v.setZOrderMediaOverlay(true); - v.getHolder().setFormat(PixelFormat.TRANSLUCENT); - addView(v); - addTitle(ctx); - return v; - } - - return (SurfaceView) getChildAt(1); + public SurfaceView getSubtitleSurface() { + return (getChildCount() < 3) ? null : (SurfaceView) getChildAt(1); } public TextView getTitle() { return (TextView) getChildAt((getChildCount() < 3) ? 1 : 2); } - public void showVideo() { + public void showVideo(boolean hideTitle) { if (surfaceCreated) { MainActivityDelegate a = getActivity(); MediaSessionCallback cb = a.getMediaSessionCallback(); @@ -130,7 +125,7 @@ public void showVideo() { cb.addVideoView(this, a.isCarActivity() ? 0 : 1); TextView title = getTitle(); - title.setVisibility(GONE); + if (hideTitle) title.setVisibility(GONE); i.getMediaDescription().main().onSuccess(dsc -> { if (cb.getCurrentItem() != i) return; @@ -203,7 +198,7 @@ public void setSurfaceSize(MediaEngine eng) { surface.setLayoutParams(lp); } - if ((surface = getSubtitleSurface(false)) != null) { + if ((surface = getSubtitleSurface()) != null) { lp = surface.getLayoutParams(); if ((lp.width != width) || (lp.height != height)) { @@ -230,8 +225,10 @@ public void onLayoutChange(View v, int left, int top, int right, int bottom, int @Override public void surfaceCreated(@NonNull SurfaceHolder holder) { + if(!getVideoSurface().getHolder().getSurface().isValid()) return; + if(!getSubtitleSurface().getHolder().getSurface().isValid()) return; surfaceCreated = true; - showVideo(); + showVideo(true); } @Override diff --git a/modules/exoplayer/src/main/java/me/aap/fermata/engine/exoplayer/ExoPlayerEngine.java b/modules/exoplayer/src/main/java/me/aap/fermata/engine/exoplayer/ExoPlayerEngine.java index 479700d7..2923d73a 100644 --- a/modules/exoplayer/src/main/java/me/aap/fermata/engine/exoplayer/ExoPlayerEngine.java +++ b/modules/exoplayer/src/main/java/me/aap/fermata/engine/exoplayer/ExoPlayerEngine.java @@ -19,7 +19,7 @@ import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.util.Util; -import com.google.android.exoplayer2.video.VideoListener; +import com.google.android.exoplayer2.video.VideoSize; import me.aap.fermata.BuildConfig; import me.aap.fermata.media.engine.AudioEffects; @@ -35,7 +35,7 @@ /** * @author Andrey Pavlenko */ -public class ExoPlayerEngine implements MediaEngine, Player.EventListener, VideoListener { +public class ExoPlayerEngine implements MediaEngine, Player.Listener { private final Context ctx; private final Listener listener; private final SimpleExoPlayer player; @@ -190,8 +190,8 @@ public void onPlaybackStateChanged(int playbackState) { } @Override - public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { - listener.onVideoSizeChanged(this, width, height); + public void onVideoSizeChanged(VideoSize videoSize) { + listener.onVideoSizeChanged(this, videoSize.width, videoSize.height); } @Override diff --git a/modules/vlc/src/main/java/me/aap/fermata/engine/vlc/VlcEngine.java b/modules/vlc/src/main/java/me/aap/fermata/engine/vlc/VlcEngine.java index 15ce985f..62ec547c 100644 --- a/modules/vlc/src/main/java/me/aap/fermata/engine/vlc/VlcEngine.java +++ b/modules/vlc/src/main/java/me/aap/fermata/engine/vlc/VlcEngine.java @@ -4,7 +4,6 @@ import android.media.AudioManager; import android.net.Uri; import android.os.ParcelFileDescriptor; -import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.ViewGroup; @@ -54,7 +53,7 @@ /** * @author Andrey Pavlenko */ -public class VlcEngine implements MediaEngine, MediaPlayer.EventListener, SurfaceHolder.Callback, +public class VlcEngine implements MediaEngine, MediaPlayer.EventListener, IVLCVout.OnNewVideoLayoutListener { @SuppressWarnings({"FieldCanBeLocal", "unused"}) // Hold reference to prevent garbage collection private final VlcEngineProvider provider; @@ -102,7 +101,7 @@ public void prepare(PlayableItem source) { } else { media = new Media(vlc, uri); - if (scheme.startsWith("http")) { + if ((scheme != null) && scheme.startsWith("http")) { String agent = source.getUserAgent(); if (agent != null) media.addOption(":http-user-agent='" + agent + "'"); } @@ -224,17 +223,13 @@ public void setSpeed(float speed) { @Override public void setVideoView(VideoView view) { - if (this.videoView != null) { - this.videoView.getVideoSurface().getHolder().removeCallback(this); - } - this.videoView = view; IVLCVout out = player.getVLCVout(); out.detachViews(); if (view != null) { out.setVideoView(view.getVideoSurface()); - out.setSubtitlesView(view.getSubtitleSurface(true)); + out.setSubtitlesView(view.getSubtitleSurface()); out.attachViews(this); setSurfaceSize(view); } @@ -330,12 +325,7 @@ public void setSubtitleDelay(int milliseconds) { @Override public void close() { stop(); - - if (videoView != null) { - videoView.getVideoSurface().getHolder().removeCallback(this); - videoView = null; - } - + videoView = null; player.release(); if (effects != null) effects.release(); } @@ -355,16 +345,6 @@ public void onEvent(MediaPlayer.Event event) { } } - @Override - public void surfaceCreated(SurfaceHolder holder) { - } - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - if ((videoView == null) || !(source instanceof VideoSource)) return; - setSurfaceSize(videoView, (VideoSource) source); - } - @Override public void onNewVideoLayout(IVLCVout vlcVout, int width, int height, int visibleWidth, int visibleHeight, int sarNum, int sarDen) { @@ -517,7 +497,7 @@ private void setSurfaceLayout(VideoView view, int width, int height) { surface.setLayoutParams(lp); } - if ((surface = view.getSubtitleSurface(false)) != null) { + if ((surface = view.getSubtitleSurface()) != null) { lp = surface.getLayoutParams(); if ((lp.width != width) || (lp.height != height)) { @@ -528,15 +508,6 @@ private void setSurfaceLayout(VideoView view, int width, int height) { } } - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - if ((videoView != null) && (videoView.getVideoSurface().getHolder() == holder)) { - holder.removeCallback(this); - videoView = null; - player.getVLCVout().detachViews(); - } - } - private void startPlaying() { playing = true; diff --git a/modules/web/src/main/java/me/aap/fermata/addon/web/FermataWebView.java b/modules/web/src/main/java/me/aap/fermata/addon/web/FermataWebView.java index 97ad6025..fee7abc0 100644 --- a/modules/web/src/main/java/me/aap/fermata/addon/web/FermataWebView.java +++ b/modules/web/src/main/java/me/aap/fermata/addon/web/FermataWebView.java @@ -31,7 +31,10 @@ import me.aap.utils.ui.view.TextChangedListener; import me.aap.utils.ui.view.ToolBarView; +import static android.os.Build.VERSION; +import static android.os.Build.VERSION_CODES; import static androidx.webkit.WebViewFeature.FORCE_DARK; +import static java.util.Objects.requireNonNull; import static me.aap.fermata.addon.web.FermataJsInterface.JS_EDIT; import static me.aap.fermata.addon.web.FermataJsInterface.JS_EVENT; @@ -74,40 +77,49 @@ public void init(WebBrowserAddon addon, FermataWebClient webClient, FermataChrom s.setJavaScriptEnabled(true); s.setJavaScriptCanOpenWindowsAutomatically(true); - setDesktopMode(addon.isDesktopVersion(), false); - addon.getPreferenceStore().addBroadcastListener(this); addJavascriptInterface(createJsInterface(), FermataJsInterface.NAME); CookieManager.getInstance().setAcceptThirdPartyCookies(this, true); - if (WebViewFeature.isFeatureSupported(FORCE_DARK)) { - if (addon.isForceDark()) { - WebSettingsCompat.setForceDark(s, WebSettingsCompat.FORCE_DARK_ON); - } - } + addon.getPreferenceStore().addBroadcastListener(this); + setDesktopMode(addon, false); + setForceDark(addon, false); } @Override public void onPreferenceChanged(PreferenceStore store, List> prefs) { - WebBrowserAddon addon = getAddon(); - - if ((addon != null) && prefs.contains(addon.getDesktopVersionPref())) { - setDesktopMode(store.getBooleanPref(addon.getDesktopVersionPref()), true); + WebBrowserAddon a = getAddon(); + if (a == null) return; + + if (prefs.contains(a.getDesktopVersionPref())) { + setDesktopMode(a, true); + } else if (prefs.contains(a.getUserAgentPref())) { + UserAgent.ua = null; + setDesktopMode(a, true); + } else if (prefs.contains(a.getUserAgentDesktopPref())) { + UserAgent.uaDesktop = null; + setDesktopMode(a, true); + } else if (prefs.contains(a.getForceDarkPref())) { + setForceDark(addon, true); } } - private void setDesktopMode(boolean v, boolean reload) { + private void setDesktopMode(WebBrowserAddon a, boolean reload) { + if (getClass() != FermataWebView.class) return; + WebSettings s = getSettings(); + boolean v = a.getPreferenceStore().getBooleanPref(a.getDesktopVersionPref()); + String ua = v ? UserAgent.getUaDesktop(s, a) : UserAgent.getUa(s, a); + Log.d("Setting User-Agent to " + ua); + s.setUserAgentString(ua); s.setUseWideViewPort(v); + if (reload) reload(); + } - if (v) { - String ua = UserAgent.getPc(s); - Log.d("Changing UserAgent to " + ua); - s.setUserAgentString(ua); - } else { - s.setUserAgentString(null); + private void setForceDark(WebBrowserAddon a, boolean reload) { + if (WebViewFeature.isFeatureSupported(FORCE_DARK)) { + int v = a.isForceDark() ? WebSettingsCompat.FORCE_DARK_ON : WebSettingsCompat.FORCE_DARK_AUTO; + WebSettingsCompat.setForceDark(getSettings(), v); } - - if (reload) reload(); } protected FermataJsInterface createJsInterface() { @@ -290,30 +302,58 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { return super.onInterceptTouchEvent(ev); } - private static final class UserAgent { - private static String pc; + static final class UserAgent { + private static final Pattern pattern = Pattern.compile(".+ AppleWebKit/(\\S+) .+ Chrome/(\\S+) .+"); + static String ua; + static String uaDesktop; + + static String getUa(WebSettings s, WebBrowserAddon a) { + if (ua != null) return ua; + + String ua = s.getUserAgentString(); + Matcher m = pattern.matcher(ua); + + if (m.matches()) { + String av; + if (VERSION.SDK_INT >= VERSION_CODES.R) av = VERSION.RELEASE_OR_CODENAME; + else av = VERSION.RELEASE; + String wv = m.group(1); + String cv = m.group(2); + UserAgent.ua = a.getPreferenceStore().getStringPref(a.getUserAgentPref()).trim() + .replace("{ANDROID_VERSION}", av) + .replace("{WEBKIT_VERSION}", requireNonNull(wv)) + .replace("{CHROME_VERSION}", requireNonNull(cv)); + if (UserAgent.ua.isEmpty()) UserAgent.ua = ua; + } else { + Log.w("User-Agent does not match the pattern ", pattern, ": " + ua); + UserAgent.ua = ua; + } + + return UserAgent.ua; + } - static String getPc(WebSettings s) { - if (pc != null) return pc; + static String getUaDesktop(WebSettings s, WebBrowserAddon a) { + if (uaDesktop != null) return uaDesktop; String ua = s.getUserAgentString(); - Pattern pattern = Pattern.compile(".+ AppleWebKit/(\\S+) .+ Chrome/(\\S+) .+"); Matcher m = pattern.matcher(ua); if (m.matches()) { String wv = m.group(1); String cv = m.group(2); - pc = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/" + wv - + " (KHTML, like Gecko) Chrome/" + cv + " Safari/" + wv; + uaDesktop = a.getPreferenceStore().getStringPref(a.getUserAgentDesktopPref()) + .replace("{WEBKIT_VERSION}", requireNonNull(wv)) + .replace("{CHROME_VERSION}", requireNonNull(cv)); } else { + Log.w("User-Agent does not match the pattern ", pattern, ": " + ua); int i1 = ua.indexOf('(') + 1; int i2 = ua.indexOf(')', i1); - pc = ua.substring(0, i1) + "X11; Linux x86_64" + ua.substring(i2) + uaDesktop = ua.substring(0, i1) + "X11; Linux x86_64" + ua.substring(i2) .replace(" Mobile ", " ") .replaceFirst(" Version/\\d+\\.\\d+ ", " "); } - return pc; + return uaDesktop; } } } diff --git a/modules/web/src/main/java/me/aap/fermata/addon/web/WebBrowserAddon.java b/modules/web/src/main/java/me/aap/fermata/addon/web/WebBrowserAddon.java index 3e1a29e6..a4248b54 100644 --- a/modules/web/src/main/java/me/aap/fermata/addon/web/WebBrowserAddon.java +++ b/modules/web/src/main/java/me/aap/fermata/addon/web/WebBrowserAddon.java @@ -28,6 +28,14 @@ public class WebBrowserAddon implements FermataAddon { private static final Pref> LAST_URL = Pref.s("LAST_URL", "http://google.com"); private static final Pref FORCE_DARK = Pref.b("FORCE_DARK", false); + private static final Pref> USER_AGENT = Pref.s("USER_AGENT", + "Mozilla/5.0 (Linux; Android {ANDROID_VERSION}) " + + "AppleWebKit/{WEBKIT_VERSION} (KHTML, like Gecko) " + + "Chrome/{CHROME_VERSION} Mobile Safari/{WEBKIT_VERSION}"); + private static final Pref> USER_AGENT_DESKTOP = Pref.s("USER_AGENT_DESKTOP", + "Mozilla/5.0 (X11; Linux x86_64) " + + "AppleWebKit/{WEBKIT_VERSION} (KHTML, like Gecko) " + + "Chrome/{CHROME_VERSION} Safari/{WEBKIT_VERSION}"); private static final Pref DESKTOP_VERSION = Pref.b("DESKTOP_VERSION", false); private static final Pref> BOOKMARKS = Pref.sa("BOOKMARKS"); private final SharedPreferenceStore preferenceStore; @@ -55,6 +63,25 @@ public void contributeSettings(PreferenceStore store, PreferenceSet set, Changea o.title = R.string.force_dark; o.visibility = visibility; }); + + if (getClass() == WebBrowserAddon.class) { + set.addStringPref(o -> { + o.store = getPreferenceStore(); + o.pref = getUserAgentPref(); + o.title = R.string.user_agent; + o.stringHint = o.pref.getDefaultValue().get(); + o.visibility = visibility; + o.maxLines = 3; + }); + set.addStringPref(o -> { + o.store = getPreferenceStore(); + o.pref = getUserAgentDesktopPref(); + o.title = R.string.user_agent_desktop; + o.stringHint = o.pref.getDefaultValue().get(); + o.visibility = visibility; + o.maxLines = 3; + }); + } } public SharedPreferenceStore getPreferenceStore() { @@ -65,6 +92,14 @@ public Pref getForceDarkPref() { return FORCE_DARK; } + public Pref> getUserAgentPref() { + return USER_AGENT; + } + + public Pref> getUserAgentDesktopPref() { + return USER_AGENT_DESKTOP; + } + public boolean isForceDark() { return getPreferenceStore().getBooleanPref(getForceDarkPref()); } diff --git a/modules/web/src/main/res/values-ru/strings.xml b/modules/web/src/main/res/values-ru/strings.xml index 0bffcaac..1d889719 100644 --- a/modules/web/src/main/res/values-ru/strings.xml +++ b/modules/web/src/main/res/values-ru/strings.xml @@ -1,6 +1,7 @@ Форсировать темный стиль, если поддерживается + User-Agent - Версия для ПК Версия для ПК Полноэкранный режим Выйти из полноэкранного режима diff --git a/modules/web/src/main/res/values/strings.xml b/modules/web/src/main/res/values/strings.xml index 7138c6e5..fb53452a 100644 --- a/modules/web/src/main/res/values/strings.xml +++ b/modules/web/src/main/res/values/strings.xml @@ -1,6 +1,8 @@ Force dark mode, if supported + User-Agent + User-Agent - Desktop version Desktop version Full screen Exit full screen