-
Notifications
You must be signed in to change notification settings - Fork 893
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Android] youtube fullscreen in landscape and pip #23933
Conversation
browser/android/preferences/background_video_playback_tab_helper.cc
Outdated
Show resolved
Hide resolved
|
||
String pattern = | ||
"^(?:https?:)?(?:\\/\\/)?(?:youtu\\.be\\/|(?:www\\.|m\\.)?youtube\\.com\\/(?:watch|v|embed)(?:\\.php)?(?:\\?.*v=|\\/))([a-zA-Z0-9\\_-]{7,15})(?:[\\?&][a-zA-Z0-9\\_-]+=[a-zA-Z0-9\\_-]+)*(?:[&\\/\\#].*)?$"; | ||
Pattern compiledPattern = Pattern.compile(pattern); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Android Chromium has url/android/java/src/org/chromium/url/GURL.java
, I think we should use that instead of regexing. youtu.be
links are redirected to youtube.com
, that eTLD+1 is all we need to check regarding the domain. Please check this native implementation of YT video URL matching here https://github.com/brave/brave-core/pull/20730/files#diff-21b9f0db07f562d309edd861da6dea61508a287c552ac00f08bb70aa121c5b09R34
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thank you @stoletheminerals. I'll update it
android/java/org/chromium/chrome/browser/app/BraveActivity.java
Outdated
Show resolved
Hide resolved
32e7eb9
to
7c66332
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
++
} | ||
} | ||
|
||
private boolean isYTVideoUrl(GURL url) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tapanmodh can we place this function into some util class ? i think we are already using similar function at other places
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we are using this function in two places in BraveActivity
class. we can place into util class but it is not being used by any another class. I think we should move after it being used by another class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need some kind of test for this so would it be easier to unit test if we put it someplace else? Or actually maybe it's better to pass the url and isInPictureInPictureMode
to BackgroundVideoPlaybackTabHelper
and change it to maybeToggleFullscreen
so we can test it in a normal browser test and also encapsulate the logic for handling this in a single place.
interface Natives { | ||
void sendOrientationChangeEvent(WebContents webContents, boolean isFullScreen); | ||
|
||
boolean isPlayingMedia(WebContents webContents); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to expose this function ? can we check idf the media is being played before we inject the script ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we are not injecting the script in this case. we are checking only when user press the home button. we have to display PIP on portrait mode if video is playing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't FullscreenVideoPictureInPictureController
already handle this? Also isPictureInPictureAllowedForFullscreenVideo
in webcontents?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have to display PIP from portrait mode and in that case FullscreenVideoPictureInPictureController
is not handling this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@stoletheminerals do you have any concerns with changes ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
std::string script; | ||
if (is_full_screen) { | ||
script = | ||
"if(!document.fullscreenElement) {" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If YT updates their site and these classes/ids no longer match then Brave is going to look broken.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also please assign this to constexpr const char16_t
and the if/else will just decide which one to run
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use uR"js( ... )js"
for multiline scripts in general, but I think we need to source this script from a component to handle YT site changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually do we even need this script at all? Can't we just call Browser::EnterFullscreenModeForTab
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, can't use Browser
here for android. On desktop setting it to fullscreen isn't the same as changing the video to fullscreen so not sure if we can use native methods here or not, but we definitely can below to exit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like FullscreenManager
is the equivalent in java, but not sure if it has the desired behavior here or not
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FullscreenManager
does not have any function for desired behavior.
rfh->GetRemoteAssociatedInterfaces()->GetInterface(&script_injector_remote); | ||
return script_injector_remote; | ||
} | ||
void JNI_BackgroundVideoPlaybackTabHelper_SendOrientationChangeEvent( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this method name doesn't make sense to me, it's not sending an orientation change, it's toggling YT fullscreen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also why are we putting this inside background_video_playback_tab_helper.cc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are already doing background audio playback for youtube videos in this class. I'll change the class name.
"}"; | ||
} | ||
GetRemote(web_contents->GetPrimaryMainFrame()) | ||
->RequestAsyncExecuteScript( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the use of RequestAsyncExecuteScript
is not needed here because we're not executing anything that returns a result. web_contents()->GetPrimaryMainFrame()->ExecuteJavaScriptInIsolatedWorld
is fine here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
web_contents()->GetPrimaryMainFrame()->ExecuteJavaScriptInIsolatedWorld
gives Failed to execute 'requestFullscreen' on 'Element': API can only be initiated by a user gesture.
error. Can we execute script with user gesture in ExecuteJavaScriptInIsolatedWorld
?
" if (moviePlayer) {" | ||
" moviePlayer.click();" | ||
" }" | ||
" setTimeout(() => {" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why does this use setTimeout?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Youtube is not loading controllers initially for this usecase and because of that we are using setTimeout.
namespace chrome { | ||
namespace android { | ||
|
||
mojo::AssociatedRemote<script_injector::mojom::ScriptInjector> GetRemote( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
helper methods should go in anonymous namespaces
This needs tests. Please use a simple test page with a media element with a fullscreen button |
" }" | ||
"}"; | ||
} else { | ||
script = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WebContents::HasActiveEffectivelyFullscreenVideo
WebContents::ExitFullscreen
" document._addEventListener(a,b,c);" | ||
" }" | ||
" };" | ||
" if(a != 'visibilitychange') {" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this script even doing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is handling background audio playback if we put app in background while video is playing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see why you need to keep a reference to the original function in document._addEventListener
and it could potentially cause namespace collision problems. Also the timing of calling it in DidFinishNavigation
does not guarantee that it will happen before any visibility change so you could end up in a place where it gets permanently set to not visible. This needs to be injected in the renderer and should not keep the original in document._addEventListener
. You don't need to worry about calling it more than once if you inject it only at the right time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also there should be comments explaining what this is doing
const base::android::JavaParamRef<jobject>& jweb_contents) { | ||
content::WebContents* web_contents = | ||
content::WebContents::FromJavaWebContents(jweb_contents); | ||
content::MediaSessionImpl* media_session_impl = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you cannot access MediaSessionImpl
outside of content
. The only reason this compiles is because #include "content/browser/web_contents/web_contents_impl.h"
is already incorrectly included and should be changed to #include "content/public/browser/web_contents.h"
and check_includes = false
should be removed from the target
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the correct way to get the status of media playing is to implement WebContentsObserver::MediaStartedPlaying/WebContentsObserver::MediaStoppedPlaying` with a tab helper, but as mentioned in the comment above it doesn't seem like this method is even necessary
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
diff --git a/browser/android/preferences/BUILD.gn b/browser/android/preferences/BUILD.gn
index 17a3651be37..20369a29f0c 100644
--- a/browser/android/preferences/BUILD.gn
+++ b/browser/android/preferences/BUILD.gn
@@ -7,8 +7,6 @@ import("//brave/components/ai_chat/core/common/buildflags/buildflags.gn>
import("//build/config/android/rules.gni")
source_set("preferences") {
- # Remove when https://github.com/brave/brave-browser/issues/10657 is resolved
- check_includes = false
sources = [
"background_video_playback_tab_helper.cc",
"background_video_playback_tab_helper.h",
diff --git a/browser/android/preferences/background_video_playback_tab_helper.cc b/brow>
index fdbdcd95c11..e2a15155ab2 100644
--- a/browser/android/preferences/background_video_playback_tab_helper.cc
+++ b/browser/android/preferences/background_video_playback_tab_helper.cc
@@ -7,14 +7,10 @@
#include <string>
-#include "base/strings/utf_string_conversions.h"
#include "brave/browser/android/preferences/features.h"
#include "brave/components/brave_shields/content/browser/brave_shields_util.h"
-#include "brave/components/constants/pref_names.h"
-#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "components/prefs/pref_service.h"
-#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_handle.h"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have changed it to implement WebContentsObserver::MediaStartedPlaying/WebContentsObserver::MediaStoppedPlaying
7c66332
to
14a4d00
Compare
->RequestAsyncExecuteScript( | ||
ISOLATED_WORLD_ID_BRAVE_INTERNAL, script, | ||
blink::mojom::UserActivationOption::kActivate, | ||
blink::mojom::PromiseResultOption::kAwait, base::NullCallback()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reported by reviewdog 🐶
[semgrep] RequestAsyncExecuteScript usages should be vet by the security-team.
References:
- https://github.com/brave/brave-browser/wiki/Security-reviews (point 13)
Source: https://github.com/brave/security-action/blob/main/assets/semgrep_rules/client/brave-execute-script.yaml
Cc @thypon @diracdeltas @bridiver
} )js"; | ||
GetRemote(web_contents->GetPrimaryMainFrame()) | ||
->RequestAsyncExecuteScript( | ||
ISOLATED_WORLD_ID_BRAVE_INTERNAL, script, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reported by reviewdog 🐶
[semgrep] Security hotspot found (ISOLATED_WORLD
). A security-team member should analyze the code security for possible vulnerabilities.
Source: https://github.com/brave/security-action/blob/main/assets/semgrep_rules/client/brave-isolated-world.yaml
Cc @thypon @diracdeltas @bridiver
Removing from the |
Closing in favor of #26355 |
Resolves brave/brave-browser#37267
Resolves brave/brave-browser#32846(Closed in favor of brave/brave-browser#37267)Resolves brave/brave-browser#26670(Closed in favor of brave/brave-browser#37267)Submitter Checklist:
https://github.com/brave/reviews/issues/1607
QA/Yes
orQA/No
;release-notes/include
orrelease-notes/exclude
;OS/...
) to the associated issuenpm run test -- brave_browser_tests
,npm run test -- brave_unit_tests
wikinpm run presubmit
wiki,npm run gn_check
,npm run tslint
git rebase master
(if needed)Reviewer Checklist:
gn
After-merge Checklist:
changes has landed on
Test Plan:
Brave should launch the full screen youtube player when it detects a user has rotated their device.
Brave should launch the pip mode when youtube video is playing